/* Connections.

   The ground is paper, deliberately, because Market owns the powder blue wash and the calendar owns
   linen. The surface device is a ruled ledger with a fixed gutter down the right edge: no cards, no
   boxes, no brand logos. The composition anchor is one numeral top left with the whole list hanging
   under it, which is not what any other surface in this app does.

   The gutter is the point. Two marks per row, always in the same two places, so a person answers "what
   is broken" by running one eye down a column rather than by reading. Everything else on the page is
   sized to stay out of that column's way. */

.cx-root {
  background: var(--paper);
  min-height: 100%;
  overflow-y: auto;
}

.cx-wrap {
  max-width: 860px;
  margin: 0 auto;
  padding: 34px 28px 96px;
}

/* ---------- header ---------- */

.cx-head { margin-bottom: 30px; }

.cx-eyebrow {
  font-family: var(--f-ui);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 10px;
}

/* The one element that carries the page. The numeral is set far above everything else on purpose: a
   person should be able to answer "how many are alive" from across the room. */
.cx-title {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin: 0 0 12px;
  flex-wrap: wrap;
}

.cx-count {
  font-family: var(--f-display);
  font-weight: 800;
  font-size: clamp(54px, 9vw, 84px);
  line-height: .84;
  letter-spacing: -.04em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.cx-of {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: clamp(17px, 2.2vw, 22px);
  letter-spacing: -.01em;
  color: var(--ink-2);
}

.cx-lede {
  font-family: var(--f-ui);
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink-2);
  max-width: 62ch;
  margin: 0 0 18px;
}

.cx-actions { display: flex; gap: 10px; flex-wrap: wrap; }

/* ---------- the publisher switch, stated once, above the four networks ----------
   It sits on its own because it is not a per network fact: it gates all four at once, and the state
   route's `ready` flag folds it into every network, which would read as four broken networks when the
   truth is one switch that is off. */

.cx-switch {
  display: flex;
  align-items: flex-start;
  gap: 13px;
  padding: 15px 17px;
  margin: 0 0 30px;
  border: 1px solid var(--rule);
  border-left: 3px solid var(--muted);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  background: var(--linen);
}

.cx-switch.is-live {
  border-left-color: var(--good);
  background: var(--good-soft);
}

.cx-switch-glyph { width: 20px; height: 20px; flex: none; color: var(--muted); margin-top: 1px; }
.cx-switch.is-live .cx-switch-glyph { color: var(--good); }

.cx-switch-state {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 16px;
  color: var(--ink);
  margin: 0 0 3px;
}

.cx-switch-note {
  font-family: var(--f-ui);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-2);
  margin: 0;
  max-width: 58ch;
}

/* ---------- groups ---------- */

.cx-group { margin-bottom: 34px; }

.cx-group-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  padding-bottom: 9px;
  border-bottom: 2px solid var(--ink);
  margin-bottom: 2px;
}

.cx-group-head .cx-eyebrow { margin: 0; flex: none; }

.cx-heading {
  font-family: var(--f-display);
  font-weight: 800;
  font-size: 21px;
  letter-spacing: -.015em;
  color: var(--ink);
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
}

.cx-group-count {
  font-family: var(--f-ui);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
  flex: none;
  font-variant-numeric: tabular-nums;
}

/* ---------- rows ---------- */

.cx-list { list-style: none; margin: 0; padding: 0; }

.cx-row {
  display: flex;
  align-items: flex-start;
  gap: 24px;
  padding: 15px 0 16px;
  border-bottom: 1px solid var(--rule-2);
}

.cx-row:last-child { border-bottom: 0; }

.cx-row-body { flex: 1 1 auto; min-width: 0; }

.cx-name {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 16px;
  letter-spacing: -.008em;
  color: var(--ink);
  margin: 0 0 4px;
}

.cx-says {
  font-family: var(--f-ui);
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink-2);
  margin: 0;
  max-width: 56ch;
}

.cx-missing {
  font-family: var(--f-ui);
  font-size: 13px;
  line-height: 1.6;
  color: var(--bad);
  margin: 7px 0 0;
}

.cx-missing code {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 12px;
  background: var(--bad-soft);
  border-radius: var(--r-sm);
  padding: 1px 6px;
  margin-right: 4px;
  color: var(--bad);
  overflow-wrap: anywhere;
}

.cx-proof,
.cx-caveat {
  font-family: var(--f-ui);
  font-size: 13px;
  line-height: 1.55;
  color: var(--muted);
  margin: 6px 0 0;
  max-width: 56ch;
}

.cx-caveat { font-style: normal; color: var(--ink-2); }

/* ---------- the gutter, which is the whole design ---------- */

/* 176px split in two ellipsed WORKING to WORKI in every row. The label is the half of a mark that
   carries meaning: the glyph alone cannot say which of the two states it is reporting. So the gutter is
   sized to the longest label at its real size and the labels never clip. */
.cx-gutter {
  flex: none;
  width: 224px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  padding-top: 2px;
}

.cx-mark {
  display: flex;
  align-items: center;
  gap: 5px;
  font-family: var(--f-ui);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  padding: 4px 7px;
  border-radius: var(--r-sm);
  border: 1px solid var(--rule);
  color: var(--muted);
  background: transparent;
  white-space: nowrap;
  min-width: 0;
}

.cx-mark-glyph { width: 13px; height: 13px; flex: none; }
.cx-mark-label { overflow: visible; }

.cx-mark.is-on {
  color: var(--good);
  border-color: var(--good);
  background: var(--good-soft);
}

/* Not set up. Quiet, because it is a job on a list rather than something that broke. */
.cx-mark.is-off {
  color: var(--muted);
  border-color: var(--rule);
  background: transparent;
}

/* Set up and still not working. The one genuinely wrong state on the page, and the only red. */
.cx-mark.is-bad {
  color: var(--bad);
  border-color: var(--bad);
  background: var(--bad-soft);
}

/* Not a failure. Nothing in this app records an answer either way, and saying so is the honest mark. */
.cx-mark.is-unknown {
  color: var(--muted);
  border-style: dashed;
  background: transparent;
}

/* ---------- foot ---------- */

.cx-foot {
  font-family: var(--f-ui);
  font-size: 13px;
  line-height: 1.6;
  color: var(--muted);
  max-width: 62ch;
  margin: 30px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--rule-2);
}

.cx-fatal {
  font-family: var(--f-ui);
  font-size: 15px;
  line-height: 1.6;
  color: var(--bad);
  background: var(--bad-soft);
  border-left: 3px solid var(--bad);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  padding: 16px 18px;
  margin: 30px 0 0;
  max-width: 58ch;
}

/* ---------- loading ---------- */

.cx-row.is-skeleton {
  gap: 24px;
  pointer-events: none;
}

.cx-row.is-skeleton span {
  display: block;
  height: 15px;
  border-radius: var(--r-sm);
  background: var(--linen-2);
}

.cx-row.is-skeleton span:first-child { flex: 1 1 auto; }
.cx-row.is-skeleton span:last-child { flex: none; width: 224px; }

/* ---------- the rail door ---------- */

.rail-cx-btn { width: 100%; justify-content: flex-start; }

.rail-cx-count {
  margin-left: auto;
  font-family: var(--f-ui);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  flex: none;
}

.rail-cx-count.is-all { color: var(--good); }
.rail-cx-count.is-none { color: var(--bad); }

/* ---------- narrow ----------
   Below 720 the gutter stops being a column and becomes a row under the text, because a 176px gutter
   against a 200px body is two columns of nothing. The marks keep their order, so the scan still works,
   it just runs across instead of down. */

@media (max-width: 719.98px) {
  .cx-wrap { padding: 24px 18px 80px; }

  .cx-row {
    flex-direction: column;
    gap: 10px;
  }

  .cx-gutter {
    width: 100%;
    grid-template-columns: auto auto;
    justify-content: start;
  }

  .cx-row.is-skeleton span:last-child { width: 100%; }
}

/* wave 6, vibe
   The eyebrow steps onto the type ladder, the publisher switch lifts off the sheet, the working mark
   becomes a plate. Delete this block to revert. */
.cx-eyebrow { font-size: 10.5px; letter-spacing: .22em; }
.cx-switch { box-shadow: var(--shadow-card); }
.cx-mark.is-on { box-shadow: inset 0 1px 0 var(--band-hi); }

/* wave 7, the app tells time
   Every mark in the gutter holds the channel's orb from tui/orbs.js. The small claim orb sits beside SET UP
   and the medium orb beside WORKING, its rim lit only when a real read stored figures. While an orb is live
   (has-orb) the pill chrome moves from the mark onto its label, so the sphere stands on the paper and the
   label keeps its state colours beside it; the old glyph shows only when the orb could not draw (is-flat).
   The gutter widens by 16px so WORKING never clips beside a 56px orb, and the marks centre on one line.
   Delete this block to revert. */
.cx-gutter {
  width: 240px;
  grid-template-columns: auto auto;
  justify-content: end;
  column-gap: 12px;
  align-items: center;
}
.cx-row.is-skeleton span:last-child { width: 240px; }
.cx-mark.has-orb {
  padding: 0;
  border-color: transparent;
  background: transparent;
  box-shadow: none;
  gap: 7px;
}
.cx-mark.has-orb .tui-orb { order: -1; flex: none; }
.cx-mark.has-orb .cx-mark-glyph { display: none; }
.cx-mark.has-orb .cx-mark-label {
  padding: 4px 7px;
  border: 1px solid var(--rule);
  border-radius: var(--r-sm);
  background: transparent;
}
.cx-mark.has-orb.is-on .cx-mark-label {
  border-color: var(--good);
  background: var(--good-soft);
  box-shadow: inset 0 1px 0 var(--band-hi);
}
.cx-mark.has-orb.is-bad .cx-mark-label {
  border-color: var(--bad);
  background: var(--bad-soft);
}
.cx-mark.has-orb.is-unknown .cx-mark-label { border-style: dashed; }
.cx-mark.has-orb[data-orb="proof"] { min-height: 56px; }
/* The medium orb gets a ground: a soft accent disc under the dust, sized to the dot field and inside the rim
   ring, so the sphere reads on paper in the light theme and the lit rim reads as a ring around it. The
   gradient is measured against the closest side: the field's last dots sit at 70 percent of the half width
   and the ring at 82, so the disc ends under the field and short of the ring. (Look pass: measured against
   the farthest corner, as first written, the disc reached only 55 percent and left the outer third of the
   dust on bare paper.) */
.cx-mark.has-orb[data-orb="proof"] .tui-orb {
  border-radius: 50%;
  background: radial-gradient(circle closest-side at 50% 50%, var(--accent-soft) 0 70%, transparent 76%);
}
@media (max-width: 719.98px) {
  .cx-gutter { width: 100%; justify-content: start; }
  .cx-row.is-skeleton span:last-child { width: 100%; }
}
/* The small claim orb takes the same soft disc as the medium one, sized the same way, so at one pixel per
   point it reads as a small sphere on paper beside SET UP rather than as loose dust round a mark; without a
   ground the light theme lost the orb. */
.cx-mark.has-orb[data-orb="claim"] .tui-orb {
  border-radius: 50%;
  background: radial-gradient(circle closest-side at 50% 50%, var(--accent-soft) 0 70%, transparent 76%);
}
