/* The Signal Console's own surfaces.
 *
 * SCOPED, DELIBERATELY. Every selector here is either a `.cn-` class or is
 * nested under one. Nothing in this file can reach the storefront, the report,
 * the account pages or any shared component, which is the property that makes
 * it safe to load a second stylesheet at all. styles.css and signal.css are
 * untouched by this work.
 *
 * IT INVENTS NO SCALE. Every value below comes from the tokens dashboard.html
 * already declares: --t-* for type, --s-* for space, --r-* for radius,
 * --signal / --hairline / --ink / --muted / --up / --down for colour. The
 * design manifesto says this page is the reference implementation, so a
 * stylesheet standing beside it with its own sizes would be the migration
 * going backwards. Where a new token is defined it is derived from an existing
 * one and says so.
 *
 * The one thing this file adds to the vocabulary is STATE colour: a
 * connection that is live, expired or absent, and a measurement that is
 * stable, volatile or absent. Those are semantic and they are kept apart from
 * the accent, because purple already means "the customer" on every chart on
 * this page and must not start meaning "good".
 */

:root {
  /* Semantic state. Green and orange already exist as --up and --down; these
     name the third and fourth states those two do not cover. */
  --cn-flat: #8A87A8;          /* nothing to say, drawn from --muted */
  --cn-warn-bg: #FDF6EC;
  --cn-warn-ink: #8A5B12;
  --cn-live-bg: #EAF6F0;
  --cn-live-ink: #1F6B4A;
  --cn-off-bg: #F4F3F8;
  --cn-off-ink: #6B6885;
  --cn-cell-0: #F6F5FA;        /* an empty matrix cell: present, unfilled */
}

/* ==========================================================================
   SECTIONS
   Only one is ever on screen. Hidden with [hidden] rather than a class, so a
   section that never gets wired is invisible by default rather than flashing.
   ========================================================================== */
.cn-section[hidden] { display: none !important; }
.cn-section { animation: cn-fade .18s ease-out; }
@keyframes cn-fade { from { opacity: .4; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .cn-section { animation: none; } }

.cn-head { margin: 0 0 var(--s-4); }
.cn-head h2 {
  font-size: var(--t-title); font-weight: var(--w-strong); color: var(--ink);
  margin: 0 0 var(--s-1); letter-spacing: -.01em;
}
.cn-head p { font-size: var(--t-body); color: var(--muted); margin: 0; max-width: 68ch; line-height: 1.55; }

/* ==========================================================================
   THE BUSINESS SWITCHER
   Lives in the app bar. A button that opens a list, not a native select: the
   rows carry two lines and two status dots, which a select cannot draw.
   ========================================================================== */
.cn-switch { position: relative; min-width: 0; }
.cn-switch-btn {
  display: flex; align-items: center; gap: var(--s-2);
  background: none; border: 0; padding: 4px 6px; margin-left: -6px;
  border-radius: var(--r-control); cursor: pointer; text-align: left;
  max-width: 100%; font-family: var(--dash-font);
}
.cn-switch-btn:hover { background: var(--paper-dim, #F4F3F9); }
.cn-switch-btn:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }
.cn-switch-name {
  display: block; font-size: var(--t-lead); font-weight: var(--w-strong); color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 46vw;
}
.cn-switch-dom {
  display: block; font-size: var(--t-meta); color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 46vw;
}
/* THE PAGE'S OWN CHEVRON, not a sixth one.
   This file first drew a small solid triangle glyph. The page had five
   different marks doing that single job and unified them behind --chev
   precisely so a new control could not add another; a stroked chevron carries
   far less ink than a solid triangle at the same width, which is why the two
   do not read as the same mark sitting next to each other. Same mask, same
   size token, same colour as every other control that opens something. */
.cn-switch-car {
  display: inline-block; font-size: 0; flex: none;
  width: var(--chev-size); height: var(--chev-size);
  color: var(--muted); background-color: currentColor;
  -webkit-mask: var(--chev) center / var(--chev-size) var(--chev-size) no-repeat;
  mask: var(--chev) center / var(--chev-size) var(--chev-size) no-repeat;
}
.cn-switch-btn:hover .cn-switch-car { color: var(--ink); }
@media (forced-colors: active) { .cn-switch-car { background-color: CanvasText; } }

.cn-menu {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 60;
  min-width: 320px; max-width: min(420px, 92vw); max-height: 70vh; overflow: auto;
  background: #fff; border: 1px solid var(--hairline); border-radius: var(--r-surface);
  /* The one shadow this file spends. The manifesto reserves elevation for the
     transient layer, and a menu that closes on the next click is exactly that. */
  box-shadow: 0 12px 32px rgba(24, 20, 60, .13);
  padding: var(--s-2);
}
.cn-menu[hidden] { display: none; }
.cn-menu-label {
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: .07em;
  color: var(--muted); font-weight: var(--w-medium); padding: var(--s-2) var(--s-3) var(--s-1);
}
.cn-menu-item {
  display: flex; align-items: flex-start; gap: var(--s-3); width: 100%;
  background: none; border: 0; text-align: left; cursor: pointer;
  padding: var(--s-2) var(--s-3); border-radius: var(--r-control);
  font-family: var(--dash-font); color: var(--ink); text-decoration: none;
}
.cn-menu-item:hover { background: var(--dash-bg); }
.cn-menu-item:focus-visible { outline: 2px solid var(--signal); outline-offset: -2px; }
.cn-menu-item.is-on { background: var(--signal-tint); }
.cn-menu-item .mi-body { min-width: 0; flex: 1; }
.cn-menu-item .mi-name {
  display: block; font-size: var(--t-body); font-weight: var(--w-medium);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cn-menu-item .mi-meta {
  display: block; font-size: var(--t-meta); color: var(--muted); margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cn-menu-item .mi-tick { flex: none; color: var(--signal); font-size: 12px; width: 12px; }
.cn-menu-sep { height: 1px; background: var(--hairline); margin: var(--s-2) var(--s-1); }

/* ==========================================================================
   STATUS PILLS
   Form as well as number: a reader scanning a list should see what needs
   attention without reading a single figure.
   ========================================================================== */
.cn-pill {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--t-micro); font-weight: var(--w-medium); letter-spacing: .05em;
  text-transform: uppercase; padding: 3px 7px; border-radius: var(--r-tag);
  white-space: nowrap; vertical-align: middle;
}
.cn-pill.live { background: var(--cn-live-bg); color: var(--cn-live-ink); }
.cn-pill.warn { background: var(--cn-warn-bg); color: var(--cn-warn-ink); }
.cn-pill.off  { background: var(--cn-off-bg);  color: var(--cn-off-ink); }
.cn-pill.acc  { background: var(--signal-tint); color: var(--signal); }
.cn-dot { width: 6px; height: 6px; border-radius: 50%; flex: none; }
.cn-dot.live { background: var(--up); }
.cn-dot.warn { background: var(--down); }
.cn-dot.off  { background: #C9C7D8; }

/* ==========================================================================
   ONBOARDING
   Three cards over the real console. The console behind is the same blurred
   stage the first-run panel uses, so what somebody is being taught about is
   visible while they are taught it.
   ========================================================================== */
.cn-ob-backdrop {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(28, 24, 58, .34);
  backdrop-filter: blur(2px);
  display: flex; align-items: center; justify-content: center; padding: var(--s-5);
}
.cn-ob-backdrop[hidden] { display: none; }
.cn-ob {
  background: #fff; border-radius: var(--r-surface); width: min(620px, 100%);
  max-height: 90vh; overflow: auto;
  box-shadow: 0 24px 64px rgba(24, 20, 60, .22);
  padding: var(--s-6);
}
.cn-ob-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--s-5); }
.cn-ob-steps { display: flex; gap: 6px; align-items: center; }
.cn-ob-step { width: 26px; height: 3px; border-radius: 2px; background: var(--hairline); }
.cn-ob-step.is-on { background: var(--signal); }
.cn-ob-skip {
  background: none; border: 0; cursor: pointer; font-family: var(--dash-font);
  font-size: var(--t-meta); color: var(--muted); padding: 4px 6px; border-radius: var(--r-control);
}
.cn-ob-skip:hover { color: var(--ink); }
.cn-ob-skip:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }
.cn-ob h2 {
  font-size: var(--t-title); font-weight: var(--w-strong); color: var(--ink);
  margin: 0 0 var(--s-3); letter-spacing: -.012em; line-height: 1.2;
}
.cn-ob p { font-size: var(--t-lead); line-height: 1.6; color: var(--muted); margin: 0 0 var(--s-5); max-width: 56ch; }
.cn-ob-art {
  background: var(--dash-bg); border: 1px solid var(--hairline); border-radius: var(--r-surface);
  padding: var(--s-5); margin-bottom: var(--s-5);
}
.cn-ob-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); }
.cn-ob-back {
  background: none; border: 0; font-family: var(--dash-font); font-size: var(--t-body);
  color: var(--muted); cursor: pointer; padding: 6px 8px; border-radius: var(--r-control);
}
.cn-ob-back:hover { color: var(--ink); }
.cn-ob-back:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }
.cn-ob-back[hidden] { visibility: hidden; display: block; }

/* ---------------------------------------------------------------------------
   THE CARDS' OWN MOTION.

   Every animation below is the thing being explained, performing itself. The
   design manifesto lists "decorative motion" under what this product must
   never become, and that rule is kept by making none of this decorative: the
   grid filling to eighteen of sixty-four IS the denominator argument, the
   chain drawing in order IS the data flow, and the bar moving from one in
   eight to six in eight IS the promise that you can tell whether it worked.

   All of it is skipped under prefers-reduced-motion, and the script paints the
   finished state instead, so nobody who asked for less is shown less.
   --------------------------------------------------------------------------- */
.cn-ob-eyebrow {
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: .09em;
  color: var(--signal); font-weight: var(--w-medium); margin-bottom: var(--s-2);
}
.cn-ob-hi {
  font-size: var(--t-body); color: var(--muted); margin: 0 0 var(--s-3);
  animation: cn-rise .5s cubic-bezier(.2,.7,.3,1) both;
}
.cn-ob-body { animation: cn-card-in .34s cubic-bezier(.2,.7,.3,1) both; }
.cn-ob-body.from-left { animation-name: cn-card-in-back; }
@keyframes cn-card-in { from { opacity: 0; transform: translateX(14px); } to { opacity: 1; transform: none; } }
@keyframes cn-card-in-back { from { opacity: 0; transform: translateX(-14px); } to { opacity: 1; transform: none; } }
@keyframes cn-rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* The step rail. A finished step stays filled, so progress reads as ground
   covered rather than as a dot that moved. */
.cn-ob-step { transition: background .3s ease, width .3s ease; }
.cn-ob-step.is-done { background: var(--signal); opacity: .45; }
.cn-ob-step.is-on { background: var(--signal); width: 34px; }

/* Card 1: sixty-four answers, eighteen of them yours. The empty cells are the
   point, so they are as visible as the filled ones. */
/* EIGHT BY EIGHT, not sixteen by four. Sixty-four cells in a strip reads as a
   bar; in a square it reads as a quantity, which is the only reason the grid
   is here. Measured by looking at both. */
.cn-grid-art {
  display: grid; grid-template-columns: repeat(8, 1fr); gap: 4px;
  margin-bottom: var(--s-4); max-width: 296px;
}
.cn-grid-art i {
  display: block; padding-top: 100%; border-radius: 2px; background: var(--cn-cell-0);
  opacity: 0; transform: scale(.72);
  transition: opacity .22s ease, transform .22s cubic-bezier(.2,1.5,.4,1), background .22s ease;
}
.cn-grid-art i.in { opacity: 1; transform: none; }
.cn-grid-art i.on { background: var(--signal); }
.cn-art-line { display: flex; align-items: baseline; gap: var(--s-2); flex-wrap: wrap; }
.cn-art-n {
  font-size: var(--t-display); font-weight: var(--w-strong); color: var(--ink);
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}
.cn-art-n b { font-weight: var(--w-strong); }
.cn-art-k { font-size: var(--t-meta); color: var(--muted); }

/* Card 2: the chain, arriving in the order the data moves. */
.cn-chain { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.cn-chain span {
  font-size: var(--t-meta); font-weight: var(--w-medium); color: var(--ink);
  background: #fff; border: 1px solid var(--hairline); border-radius: var(--r-control);
  padding: 7px 10px; white-space: nowrap;
  opacity: 0; transform: translateY(5px); transition: opacity .3s ease, transform .3s cubic-bezier(.2,.8,.3,1);
}
.cn-chain span.in { opacity: 1; transform: none; }
.cn-chain-link {
  display: block; height: 1px; width: 0; background: var(--hairline);
  transition: width .26s ease;
}
.cn-chain-link.in { width: 16px; }

/* Card 3: the move. One question, before and after. */
.cn-move { display: grid; gap: var(--s-2); }
.cn-move-q { font-size: var(--t-body); color: var(--ink); margin-bottom: var(--s-1); }
.cn-move-row { display: flex; align-items: center; gap: var(--s-3); }
.cn-move-k { font-size: var(--t-meta); color: var(--muted); width: 46px; flex: none; }
.cn-move-track { flex: 1; height: 8px; border-radius: var(--r-pill); background: var(--cn-cell-0); overflow: hidden; }
.cn-move-track i { display: block; height: 100%; border-radius: var(--r-pill); background: var(--signal); }
.cn-move-track i.grow { width: 12.5%; transition: width .9s cubic-bezier(.2,.8,.25,1); }
.cn-move-v {
  font-size: var(--t-body); font-weight: var(--w-strong); color: var(--ink);
  font-variant-numeric: tabular-nums; width: 44px; text-align: right; flex: none;
}

/* The primary action sits in the same place on every card. space-between plus
   a hidden placeholder was supposed to do that and did not on the first card,
   where there is no Back: the button landed on the left and moved right on
   card two, so the one control a reader is aiming for was the one thing that
   jumped. margin-left:auto does not care whether the placeholder is there. */
.cn-ob-next { transition: transform .12s ease; margin-left: auto; }
.cn-ob-next:active { transform: translateY(1px); }

@media (prefers-reduced-motion: reduce) {
  .cn-ob-body, .cn-ob-hi { animation: none; }
  .cn-grid-art i, .cn-chain span, .cn-chain-link, .cn-move-track i, .cn-ob-step, .cn-ob-next {
    transition: none;
  }
  .cn-grid-art i { opacity: 1; transform: none; }
  .cn-chain span { opacity: 1; transform: none; }
}

/* ==========================================================================
   SETUP CHECKLIST
   Collapses to one line when the required items are done, because a permanent
   checklist on a finished console is furniture nobody asked for.
   ========================================================================== */
.cn-setup {
  border: 1px solid var(--hairline); border-radius: var(--r-surface);
  background: #fff; padding: var(--s-4); margin-bottom: var(--s-4);
}
.cn-setup-h { display: flex; align-items: center; gap: var(--s-3); }
.cn-setup-h h3 {
  font-size: var(--t-lead); font-weight: var(--w-medium); color: var(--ink); margin: 0; flex: 1;
}
.cn-setup-toggle {
  background: none; border: 0; cursor: pointer; font-family: var(--dash-font);
  font-size: var(--t-meta); color: var(--signal); font-weight: var(--w-medium);
  padding: 4px 6px; border-radius: var(--r-control);
}
.cn-setup-toggle:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }
.cn-setup-list { list-style: none; margin: var(--s-3) 0 0; padding: 0; display: grid; gap: var(--s-2); }
.cn-setup-list li { display: flex; align-items: flex-start; gap: var(--s-3); font-size: var(--t-body); }
.cn-setup-mark { flex: none; width: 16px; text-align: center; font-size: 12px; line-height: 1.5; }
.cn-setup-mark.done { color: var(--up); }
.cn-setup-mark.todo { color: #C9C7D8; }
.cn-setup-txt { min-width: 0; }
.cn-setup-txt b { font-weight: var(--w-medium); color: var(--ink); }
.cn-setup-txt span { display: block; color: var(--muted); font-size: var(--t-meta); margin-top: 1px; }
.cn-setup-act {
  background: none; border: 0; padding: 0; margin-top: 2px; cursor: pointer;
  font-family: var(--dash-font); font-size: var(--t-meta); font-weight: var(--w-medium);
  color: var(--signal); text-decoration: none; display: inline-block;
}
.cn-setup-act:hover { text-decoration: underline; }

/* ==========================================================================
   THE HEADLINE MEASUREMENT
   The numerator, the denominator and the period, in that order and at that
   emphasis. The percentage is second because it is derived from the two
   figures above it, and a page that leads with the derived number teaches the
   reader to stop looking for the evidence.
   ========================================================================== */
.cn-exec {
  display: grid; grid-template-columns: minmax(280px, 1.15fr) minmax(240px, 1fr);
  gap: var(--s-5); align-items: start;
  border: 1px solid var(--hairline); border-radius: var(--r-surface);
  background: #fff; padding: var(--s-5); margin-bottom: var(--s-4);
}
@media (max-width: 780px) { .cn-exec { grid-template-columns: 1fr; gap: var(--s-4); } }
.cn-exec-label {
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: .07em;
  color: var(--muted); font-weight: var(--w-medium); margin-bottom: var(--s-3);
}
.cn-frac { display: flex; align-items: baseline; gap: var(--s-2); flex-wrap: wrap; }
.cn-frac-n {
  font-size: 34px; font-weight: var(--w-strong); color: var(--ink);
  font-variant-numeric: tabular-nums; letter-spacing: -.02em; line-height: 1.05;
}
.cn-frac-of { font-size: var(--t-lead); color: var(--muted); }
.cn-frac-say { font-size: var(--t-body); color: var(--muted); margin-top: var(--s-2); line-height: 1.5; }
.cn-rate-row { display: flex; align-items: baseline; gap: var(--s-3); margin-top: var(--s-3); flex-wrap: wrap; }
.cn-rate { font-size: var(--t-display); font-weight: var(--w-strong); color: var(--ink); font-variant-numeric: tabular-nums; }
.cn-delta { font-size: var(--t-body); font-weight: var(--w-medium); font-variant-numeric: tabular-nums; }
.cn-delta.up { color: var(--up); }
.cn-delta.down { color: var(--down); }
.cn-delta.flat { color: var(--cn-flat); }

/* Per-source chips. Every one carries its own fraction: a source with four
   answers and a source with forty look identical as percentages. */
.cn-chips { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-4); }
.cn-chip {
  border: 1px solid var(--hairline); border-radius: var(--r-control);
  padding: 7px 10px; background: #fff; min-width: 0;
}
.cn-chip b { display: block; font-size: var(--t-meta); font-weight: var(--w-medium); color: var(--ink); }
.cn-chip span { display: block; font-size: var(--t-meta); color: var(--muted); font-variant-numeric: tabular-nums; margin-top: 2px; }

/* Measurement health: what the metric is made of, stated so the rate above
   can be checked rather than believed. */
.cn-health { border-left: 1px solid var(--hairline); padding-left: var(--s-5); }
@media (max-width: 780px) { .cn-health { border-left: 0; padding-left: 0; border-top: 1px solid var(--hairline); padding-top: var(--s-4); } }
.cn-health dl { margin: 0; display: grid; grid-template-columns: 1fr auto; gap: var(--s-2) var(--s-3); }
.cn-health dt { font-size: var(--t-body); color: var(--muted); }
.cn-health dd {
  margin: 0; font-size: var(--t-body); font-weight: var(--w-medium); color: var(--ink);
  font-variant-numeric: tabular-nums; text-align: right;
}

/* ==========================================================================
   CARDS AND TABLES
   ========================================================================== */
.cn-card {
  border: 1px solid var(--hairline); border-radius: var(--r-surface);
  background: #fff; padding: var(--s-4); margin-bottom: var(--s-4);
}
.cn-card-h { display: flex; align-items: baseline; gap: var(--s-3); margin-bottom: var(--s-3); flex-wrap: wrap; }
.cn-card-h h3 { font-size: var(--t-lead); font-weight: var(--w-medium); color: var(--ink); margin: 0; flex: 1; }
.cn-card-h .meta { font-size: var(--t-meta); color: var(--muted); }
.cn-note { font-size: var(--t-meta); color: var(--muted); line-height: 1.6; margin: var(--s-3) 0 0; }

.cn-scroll { overflow-x: auto; }
.cn-tbl { border-collapse: collapse; width: 100%; font-size: var(--t-body); }
.cn-tbl th, .cn-tbl td { text-align: left; padding: var(--s-2) var(--s-3); border-bottom: 1px solid var(--hairline); vertical-align: top; }
.cn-tbl th {
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); font-weight: var(--w-medium); white-space: nowrap;
}
.cn-tbl tr:last-child td { border-bottom: 0; }
.cn-tbl td.num, .cn-tbl th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cn-tbl .q { min-width: 260px; max-width: 460px; }
.cn-you td { background: var(--signal-tint); }

/* THE SELECT COLUMN. Narrow, top-aligned with the name rather than centred in
   a two-line cell, and a real checkbox: a styled div would lose the keyboard,
   the screen reader and the indeterminate state, all three of which this
   header cell needs. */
.cn-tbl th.chk, .cn-tbl td.chk { width: 1%; padding-right: 0; white-space: nowrap; }
.cn-tbl td.chk input, .cn-tbl th.chk input {
  width: 15px; height: 15px; margin: 2px 0 0; accent-color: var(--signal); cursor: pointer;
}
.cn-tbl th.chk input { margin-top: 0; }

/* The bulk strip. Inside the card and above the table, so it reads as a state
   of this list rather than as a toolbar the page always had. It is `hidden`
   until something is ticked; see wireBulk for why it is absent and not
   disabled. */
.cn-bulk {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
  flex-wrap: wrap; padding: var(--s-2) var(--s-3);
  border-bottom: 1px solid var(--hairline); background: var(--signal-tint);
}
.cn-bulk-say { font-size: var(--t-meta); color: var(--ink); font-weight: var(--w-medium); }
.cn-bulk-do { display: flex; align-items: center; gap: var(--s-2); }
.cn-you .nm { font-weight: var(--w-strong); }

/* The matrix. A cell is a button because it opens the answers behind it, and
   it has to look pressable for that to be discoverable. */
.cn-cell {
  display: block; width: 100%; border: 0; border-radius: var(--r-tag); cursor: pointer;
  font-family: var(--dash-font); padding: 6px 8px; text-align: center;
  background: var(--cn-cell-0); color: var(--ink); line-height: 1.25;
}
.cn-cell:hover { outline: 1px solid var(--signal); }
.cn-cell:focus-visible { outline: 2px solid var(--signal); outline-offset: 1px; }
.cn-cell b { display: block; font-size: var(--t-body); font-weight: var(--w-strong); font-variant-numeric: tabular-nums; }
.cn-cell span { display: block; font-size: var(--t-micro); color: var(--muted); font-variant-numeric: tabular-nums; }
.cn-cell[data-empty="1"] { cursor: default; }
.cn-cell[data-empty="1"]:hover { outline: 0; }

/* Consistency bands. */
.cn-bands { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--s-3); }
.cn-band { border: 1px solid var(--hairline); border-radius: var(--r-surface); padding: var(--s-3) var(--s-4); }
.cn-band-h { display: flex; align-items: center; gap: var(--s-2); margin-bottom: var(--s-2); }
.cn-band-h b { font-size: var(--t-body); font-weight: var(--w-medium); color: var(--ink); }
.cn-band-n { font-size: var(--t-display); font-weight: var(--w-strong); color: var(--ink); font-variant-numeric: tabular-nums; line-height: 1.1; }
.cn-band ul { list-style: none; margin: var(--s-2) 0 0; padding: 0; display: grid; gap: 6px; }
.cn-band li { font-size: var(--t-meta); color: var(--muted); line-height: 1.45; }
.cn-band li b { color: var(--ink); font-variant-numeric: tabular-nums; }

/* Quadrants. */
.cn-quads { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--s-3); }
.cn-quad { border: 1px solid var(--hairline); border-radius: var(--r-surface); padding: var(--s-4); }
.cn-quad.priority { border-color: #E8CDA8; background: var(--cn-warn-bg); }
.cn-quad h4 { font-size: var(--t-body); font-weight: var(--w-medium); color: var(--ink); margin: 0 0 var(--s-1); }
.cn-quad .why { font-size: var(--t-meta); color: var(--muted); margin: 0 0 var(--s-3); line-height: 1.5; }
.cn-quad-n { font-size: var(--t-display); font-weight: var(--w-strong); font-variant-numeric: tabular-nums; color: var(--ink); }

/* Action cards: an action is only worth reading with the evidence beside it. */
.cn-action { border: 1px solid var(--hairline); border-radius: var(--r-surface); padding: var(--s-4); margin-bottom: var(--s-3); background: #fff; }
.cn-action-top { display: flex; align-items: baseline; gap: var(--s-3); margin-bottom: var(--s-2); }
.cn-action-rank {
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: .07em;
  color: var(--muted); font-weight: var(--w-medium); white-space: nowrap;
}
.cn-action h4 { font-size: var(--t-lead); font-weight: var(--w-medium); color: var(--ink); margin: 0; flex: 1; }
.cn-ev { list-style: none; margin: var(--s-2) 0 var(--s-3); padding: 0; display: grid; gap: 5px; }
.cn-ev li { font-size: var(--t-body); color: var(--muted); line-height: 1.55; }
.cn-ev li b { color: var(--ink); font-variant-numeric: tabular-nums; font-weight: var(--w-medium); }

/* ==========================================================================
   THE EVIDENCE DRAWER
   Raw answers, reachable from any number. It slides from the right on a wide
   screen and covers the page on a narrow one.
   ========================================================================== */
.cn-drawer-scrim { position: fixed; inset: 0; z-index: 190; background: rgba(28, 24, 58, .28); }
.cn-drawer-scrim[hidden] { display: none; }
.cn-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 191;
  width: min(680px, 100vw); background: #fff; display: flex; flex-direction: column;
  box-shadow: -14px 0 40px rgba(24, 20, 60, .16);
}
.cn-drawer[hidden] { display: none; }
.cn-drawer-h {
  padding: var(--s-4) var(--s-5); border-bottom: 1px solid var(--hairline);
  display: flex; align-items: flex-start; gap: var(--s-3);
}
.cn-drawer-h .t { flex: 1; min-width: 0; }
.cn-drawer-h h3 { font-size: var(--t-lead); font-weight: var(--w-medium); color: var(--ink); margin: 0 0 3px; line-height: 1.4; }
.cn-drawer-h .meta { font-size: var(--t-meta); color: var(--muted); font-variant-numeric: tabular-nums; }
.cn-drawer-x {
  flex: none; background: none; border: 0; cursor: pointer; font-size: 18px; line-height: 1;
  color: var(--muted); padding: 4px 8px; border-radius: var(--r-control);
}
.cn-drawer-x:hover { color: var(--ink); background: var(--dash-bg); }
.cn-drawer-x:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }
.cn-drawer-b { flex: 1; overflow: auto; padding: var(--s-4) var(--s-5) var(--s-6); }

.cn-run { border: 1px solid var(--hairline); border-radius: var(--r-surface); padding: var(--s-3) var(--s-4); margin-bottom: var(--s-3); }
.cn-run-h { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; margin-bottom: var(--s-2); }
.cn-run-n { font-size: var(--t-micro); text-transform: uppercase; letter-spacing: .06em; color: var(--muted); font-weight: var(--w-medium); }
.cn-answer {
  font-size: var(--t-body); line-height: 1.65; color: var(--ink); white-space: pre-wrap;
  margin: 0; max-height: 320px; overflow: auto;
}
.cn-answer.quiet { color: var(--muted); font-style: italic; }
.cn-run-foot { margin-top: var(--s-2); padding-top: var(--s-2); border-top: 1px solid var(--hairline); font-size: var(--t-meta); color: var(--muted); line-height: 1.55; }
.cn-run-foot b { color: var(--ink); font-weight: var(--w-medium); }
.cn-cites { display: grid; gap: 3px; margin-top: 4px; }
.cn-cites a { font-size: var(--t-meta); color: var(--signal); text-decoration: none; overflow-wrap: anywhere; }
.cn-cites a:hover { text-decoration: underline; }

/* ==========================================================================
   EMPTY, LOADING AND CONNECTION STATES
   Skeletons rather than spinners, so the layout does not jump when data lands.
   ========================================================================== */
.cn-empty {
  border: 1px dashed var(--hairline); border-radius: var(--r-surface);
  padding: var(--s-6) var(--s-5); text-align: center; background: var(--dash-bg);
}
.cn-empty h3 { font-size: var(--t-lead); font-weight: var(--w-medium); color: var(--ink); margin: 0 0 var(--s-2); }
.cn-empty p { font-size: var(--t-body); color: var(--muted); margin: 0 auto var(--s-4); max-width: 52ch; line-height: 1.6; }
.cn-empty p:last-child { margin-bottom: 0; }

.cn-skel { display: grid; gap: var(--s-2); }
.cn-skel i {
  display: block; height: 12px; border-radius: var(--r-tag);
  background: linear-gradient(90deg, #F2F1F7 25%, #E9E7F2 37%, #F2F1F7 63%);
  background-size: 400% 100%; animation: cn-shimmer 1.3s ease-in-out infinite;
}
.cn-skel i:nth-child(2) { width: 82%; }
.cn-skel i:nth-child(3) { width: 64%; }
@keyframes cn-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@media (prefers-reduced-motion: reduce) { .cn-skel i { animation: none; } }

/* ==========================================================================
   CONTROLS
   Built on the page's existing .dash-btn wherever one will do. These are the
   two shapes it does not have.
   ========================================================================== */
.cn-inline-btn {
  background: none; border: 0; padding: 0; cursor: pointer; font-family: var(--dash-font);
  font-size: var(--t-meta); font-weight: var(--w-medium); color: var(--signal); text-decoration: none;
}
.cn-inline-btn:hover { text-decoration: underline; }
.cn-inline-btn:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }
.cn-inline-btn[disabled] { color: var(--muted); cursor: default; text-decoration: none; }

.cn-field {
  font-family: var(--dash-font); font-size: var(--t-body); color: var(--ink);
  padding: var(--s-2) var(--s-3); border: 1px solid var(--hairline);
  border-radius: var(--r-control); background: #fff; min-width: 0;
}
.cn-field:focus { outline: none; border-color: var(--signal); box-shadow: 0 0 0 3px rgba(91, 79, 224, .16); }
.cn-row { display: flex; gap: var(--s-2); flex-wrap: wrap; align-items: center; }
.cn-row .grow { flex: 1; min-width: 200px; }

/* Suggestions. Draft and accepted must never look alike: the whole safety
   property of this feature is that a proposal is visibly not a measurement. */
.cn-sug { border: 1px solid var(--hairline); border-radius: var(--r-surface); padding: var(--s-3) var(--s-4); margin-bottom: var(--s-2); }
.cn-sug.is-accepted { border-color: #BFD8CB; background: var(--cn-live-bg); }
.cn-sug.is-dismissed { opacity: .55; }
.cn-sug-t { font-size: var(--t-body); color: var(--ink); line-height: 1.5; margin: 0 0 var(--s-2); }
.cn-sug-ev { font-size: var(--t-meta); color: var(--muted); line-height: 1.55; margin: 0 0 var(--s-2); }
.cn-sug-ev b { color: var(--ink); font-variant-numeric: tabular-nums; font-weight: var(--w-medium); }
.cn-sug-acts { display: flex; gap: var(--s-4); flex-wrap: wrap; align-items: center; }

/* ==========================================================================
   RAIL: the console's own sections, above the page links that already exist.
   ========================================================================== */
.cn-rail-label {
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: .07em;
  color: var(--muted); font-weight: var(--w-medium); padding: 0 0 var(--s-2) 12px;
}

/* ==========================================================================
   NARROW SCREENS
   The console keeps every action on a phone. Tables scroll inside their own
   container so the page body never does.
   ========================================================================== */
@media (max-width: 640px) {
  .cn-ob { padding: var(--s-5) var(--s-4); }
  .cn-ob h2 { font-size: 22px; }
  .cn-grid-art { max-width: none; }
  .cn-exec { padding: var(--s-4); }
  .cn-frac-n { font-size: 28px; }
  .cn-menu { min-width: 0; width: min(340px, 90vw); }
  /* The switcher has a full row of its own at this width (the shell's bar
     wraps), so the name may use it rather than being cut at 40% of a viewport
     it no longer shares. */
  .cn-switch-name, .cn-switch-dom { max-width: 78vw; }
  .cn-drawer { width: 100vw; }
}

/* RENAME, beside the name it renames. A text control rather than a button
   shape: the row is a link to a dashboard and a second solid button in the
   same cell would compete with it for the eye. */
.cn-rename {
  font: inherit; font-size: var(--t-meta); color: var(--muted);
  background: none; border: 0; padding: 0 2px; margin-left: 6px; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.cn-rename:hover { color: var(--signal); }
.cn-rename:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; border-radius: 2px; }
.cn-rename[disabled] { opacity: .5; cursor: default; text-decoration: none; }

/* The switcher row: a link and its rename, side by side, because a button may
   not live inside an anchor.

   THE RENAME IS ON EVERY ROW, ALWAYS. It used to be `opacity: 0` until the row
   was hovered, and that was wrong three ways. A touch screen has no hover, so
   on every phone and tablet the control was unreachable while still sitting in
   the tab order, invisible and clickable at once. A control nobody can see is
   a control nobody knows exists: the founder reported the menu as offering a
   rename "for one business", which was simply the row the pointer was resting
   on. And the table on the Businesses screen shows its rename unconditionally,
   so the same action appeared and disappeared depending on where it was met.

   The original worry was real and is answered differently: the menu is mostly
   used for CHOOSING, so the rename must not read as a second button competing
   with the row. It stays quiet by being muted and unadorned until the row is
   engaged, rather than by being absent. */
.cn-menu-row { display: flex; align-items: center; gap: 4px; }
.cn-menu-row > .cn-menu-item { flex: 1; min-width: 0; }
.cn-menu-row > .cn-rename { flex: none; margin-right: var(--s-2); text-decoration: none; }
/* The underline is the affordance, and it arrives when the row is engaged.
   Colour still changes only on the rename itself, so pointing at the row does
   not make the rename look like the thing you are about to press. */
.cn-menu-row:hover > .cn-rename,
.cn-menu-row:focus-within > .cn-rename { text-decoration: underline; }
.cn-remove {
  font: inherit; font-size: var(--t-meta); color: var(--muted);
  background: none; border: 0; padding: 0 2px; margin-left: 8px; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.cn-remove:hover { color: var(--down); }
.cn-remove:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; border-radius: 2px; }
.cn-remove[disabled] { opacity: .5; cursor: default; text-decoration: none; }

/* ==========================================================================
   THE QUESTION WORKSPACE
   Above the measured matrix, and deliberately a different shape from it. The
   matrix is a result and reads as a table. This is work in progress and reads
   as a list of things waiting for a decision.
   ========================================================================== */

/* Where you stand, in one line. Four facts, no chrome around them, because a
   status strip that looks like four cards competes with the cards below it. */
.cn-standing {
  display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-6);
  padding: var(--s-3) 0 var(--s-4); border-bottom: 1px solid var(--hairline);
  margin-bottom: var(--s-5);
}
.cn-standing div { display: flex; flex-direction: column; gap: 2px; }
.cn-standing dt {
  font-size: var(--t-micro); letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); font-weight: var(--w-medium); margin: 0;
}
.cn-standing dd { font-size: var(--t-lead); color: var(--ink); font-weight: var(--w-medium); margin: 0; }
.cn-standing dd small { font-size: var(--t-meta); color: var(--muted); font-weight: 400; }

/* THE THREE ROUTES. Equal width on purpose: none of them is the recommended
   one, they answer different questions, and a customer with no Search Console
   should not read their best option as the greyed-out one. */
.cn-routes { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-3); }
@media (max-width: 860px) { .cn-routes { grid-template-columns: 1fr; } }
.cn-route {
  border: 1px solid var(--hairline); border-radius: var(--r-surface);
  padding: var(--s-4); display: flex; flex-direction: column; gap: var(--s-2);
  background: #fff;
}
.cn-route h4 { font-size: var(--t-body); font-weight: var(--w-medium); color: var(--ink); margin: 0; }
.cn-route p { font-size: var(--t-meta); color: var(--muted); margin: 0; line-height: 1.55; }
/* The control sits at the bottom of every card whatever the copy above it
   runs to, so three cards of different lengths still line their buttons up. */
.cn-route .cn-route-do { margin-top: auto; padding-top: var(--s-2); }

.cn-paste {
  width: 100%; box-sizing: border-box; min-height: 128px; resize: vertical;
  font: inherit; font-size: var(--t-meta); line-height: 1.55; color: var(--ink);
  border: 1px solid var(--hairline); border-radius: var(--r-control);
  padding: var(--s-3); background: var(--dash-bg);
}
.cn-paste:focus-visible { outline: 2px solid var(--signal); outline-offset: 1px; }

/* The prompt we hand them, shown as the thing it is: text to be copied, not
   copy to be read. Monospace and a scroll box rather than a paragraph. */
.cn-prompt {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px; line-height: 1.6; white-space: pre-wrap; word-break: break-word;
  background: var(--dash-bg); border: 1px solid var(--hairline);
  border-radius: var(--r-control); padding: var(--s-3);
  max-height: 200px; overflow-y: auto; color: var(--ink); margin: 0;
}

/* A PROPOSAL. Not a card: a row with its evidence under it, because twenty of
   these must stay readable and twenty cards would not. */
.cn-prop { display: grid; gap: 6px; padding: var(--s-3) 0; border-top: 1px solid var(--hairline); }
.cn-prop:first-child { border-top: 0; }
.cn-prop-t { font-size: var(--t-body); color: var(--ink); line-height: 1.5; }
.cn-prop-ev { font-size: var(--t-meta); color: var(--muted); line-height: 1.5; }
.cn-prop-do { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }
.cn-prop.is-done { opacity: .55; }
.cn-prop-edit {
  width: 100%; box-sizing: border-box; font: inherit; font-size: var(--t-body);
  border: 1px solid var(--signal); border-radius: var(--r-control);
  padding: 8px var(--s-3); color: var(--ink); background: #fff;
}

/* Where a proposal came from, as a word rather than a colour, so the four
   sources stay distinguishable to a reader who cannot separate the hues. */
.cn-src {
  font-size: var(--t-micro); letter-spacing: .06em; text-transform: uppercase;
  font-weight: var(--w-medium); color: var(--muted);
  background: var(--dash-bg); border: 1px solid var(--hairline);
  border-radius: var(--r-tag); padding: 2px 7px; white-space: nowrap;
}
.cn-src.own { color: var(--signal); border-color: var(--signal-tint); background: var(--signal-tint); }

/* Counts on the filter row, so "12 waiting" is legible before anything is
   clicked and the customer knows the list is not everything they have. */
.cn-props-filter { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-bottom: var(--s-2); }
.cn-props-filter button {
  font: inherit; font-size: var(--t-meta); color: var(--muted); cursor: pointer;
  background: none; border: 1px solid var(--hairline); border-radius: var(--r-pill);
  padding: 3px 12px;
}
.cn-props-filter button.is-on { color: var(--ink); border-color: var(--signal); background: var(--signal-tint); }
.cn-props-filter button:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }

.cn-say { font-size: var(--t-meta); color: var(--muted); margin: var(--s-2) 0 0; min-height: 1.2em; }
.cn-say.bad { color: var(--down); }

/* THE CATEGORY BAND. Context for every question below it, so it sits above
   them and reads as one sentence rather than as a tile of statistics. Not a
   card: a card would make it look like a fourth thing to do, and it is not a
   thing to do, it is the weather. */
.cn-cat {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 10px;
  padding: var(--s-3) var(--s-4); margin-bottom: var(--s-4);
  border: 1px solid var(--hairline); border-radius: var(--r-surface);
  background: var(--dash-bg); font-size: var(--t-body); line-height: 1.55;
}
.cn-cat-say { color: var(--ink); }
.cn-cat-say b { font-weight: var(--w-medium); }
.cn-cat-why { flex-basis: 100%; font-size: var(--t-meta); color: var(--muted); margin: 0; }
/* The source line. Always present, always says it is an index, because the
   one claim this data cannot support is the one everybody wants to make. */
.cn-cat-src { flex-basis: 100%; font-size: var(--t-micro); color: var(--muted); font-family: var(--dash-font); margin: 2px 0 0; }
.cn-cat-do { margin-left: auto; display: flex; gap: var(--s-2); align-items: center; }
.cn-cat-topic {
  font: inherit; font-size: var(--t-meta); color: var(--ink); min-width: 180px;
  border: 1px solid var(--hairline); border-radius: var(--r-control);
  padding: 5px var(--s-3); background: #fff;
}
.cn-cat-topic:focus-visible { outline: 2px solid var(--signal); outline-offset: 1px; }
.cn-dir { font-weight: var(--w-medium); }
.cn-dir.rising { color: var(--up); }
.cn-dir.falling { color: var(--down); }
.cn-dir.steady, .cn-dir.unknown { color: var(--muted); }

/* =====================================================================
   THE POINTER: onboarding that is not a dialog.
   ---------------------------------------------------------------------
   Founder, 2026-09-06: there should be some form of onboarding, and it does
   not have to always be a pop-up. Maybe the first time. After they have seen
   those steps, in-platform animation to lead their eyes to click certain
   things, with text showing why they should click it.

   So the modal stays for the first visit and this is what comes after it.
   Three things make it a pointer rather than a second dialog:

   IT POINTS AT A REAL CONTROL. The halo is drawn over an element that is on
   the screen right now, and it moves with it. Nothing is dimmed and nothing is
   trapped; the page underneath stays fully usable, which is the whole
   difference between a hint and an interruption.

   IT SAYS WHY, NOT WHAT. A label that reads "Buyer Questions" beside a link
   that says Buyer Questions has told nobody anything. The reason is the
   content.

   IT IS EARNED BY STATE. Each hint is derived from the setup checklist the
   server already computes, so it only ever appears while the thing it points
   at is genuinely undone, and it leaves the moment it is done. A tour that
   runs on a schedule instead of on state is furniture.
   ===================================================================== */
/* AN OUTLINE, NOT AN ELEVATION. The halo marks a control in place; it does not
   float above the page, and console-views.test.js reserves box-shadow for the
   layers that genuinely do. So the ring is a pseudo-element that scales and
   fades, which is also the cheaper thing to animate. */
.cn-coach-halo {
  position: fixed; z-index: 60; pointer-events: none;
  border-radius: 10px; border: 2px solid var(--signal);
}
.cn-coach-halo:after {
  content: ""; position: absolute; inset: -4px;
  border-radius: 13px; border: 2px solid var(--signal); opacity: .45;
  animation: cnCoachPulse 2.4s cubic-bezier(.4, 0, .2, 1) infinite;
}
@keyframes cnCoachPulse {
  0%   { transform: scale(1); opacity: .45 }
  70%  { opacity: 0 }
  100% { transform: scale(1.16); opacity: 0 }
}
.cn-coach {
  position: fixed; z-index: 61; max-width: 300px;
  background: var(--ink); color: #fff; border-radius: var(--r-surface);
  padding: 12px 14px 11px; box-shadow: 0 12px 34px rgba(20, 18, 31, .28);
  font-size: var(--t-meta); line-height: 1.55;
  animation: cnCoachIn .28s cubic-bezier(.2, .7, .3, 1) both;
}
@keyframes cnCoachIn { from { opacity: 0; transform: translateX(-6px) } to { opacity: 1; transform: none } }
/* The nib, so the card reads as attached to the thing rather than floating
   near it. */
.cn-coach:after {
  content: ""; position: absolute; left: -5px; top: 18px;
  width: 10px; height: 10px; background: var(--ink); transform: rotate(45deg);
}
.cn-coach b { display: block; font-weight: var(--w-medium); margin-bottom: 4px; color: #fff; }
.cn-coach p { margin: 0; color: rgba(255, 255, 255, .82); }
.cn-coach-do { display: flex; gap: 10px; align-items: center; margin-top: 10px; }
.cn-coach-do button {
  font: inherit; font-size: var(--t-meta); cursor: pointer; border-radius: 7px;
  padding: 5px 11px; border: 0; background: var(--signal); color: #fff; font-weight: var(--w-medium);
}
.cn-coach-do .cn-coach-skip { background: none; color: rgba(255, 255, 255, .6); padding: 5px 2px; text-decoration: underline; }
@media (prefers-reduced-motion: reduce) {
  .cn-coach-halo { animation: none }
  .cn-coach-halo:after { animation: none; opacity: .3 }
  .cn-coach { animation: none }
}
/* Below the rail's own breakpoint the rail is a drawer, so a halo pinned to a
   link inside it would point at something nobody can see. */
@media (max-width: 900px) { .cn-coach-halo, .cn-coach { display: none } }
