/* Orchadstrate — product prototype.
   The same system as the marketing site: warm paper, near-black ink, oxblood
   accent, flat surfaces, hairline rules, no radius, no shadow. 'IBM Plex Sans' for text,
   Martian Mono for labels and numbers.

   This is a UI rather than a document, so the craft shifts: state is encoded in
   form as well as in words, the summary comes before the detail, and anything
   interactive looks interactive. The grey ramp is the contrast-solved one —
   every text colour clears AA on paper, panel and card. */

:root {
  color-scheme: light;
  --paper:  #f4f3f0;
  --panel:  #ece9e3;
  --card:   #fdfdfc;
  --ink:    #16181c;
  --ink-2:  #4a4e56;
  --muted:  #585c64;
  --faint:  #65686e;
  --rule:   #d6d4ce;
  --hair:   #e2e0da;
  --accent: #7f2b23;
  --good:   #2f6b46;

  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px;
  --s6: 32px; --s7: 48px; --s8: 64px;
  --ease: cubic-bezier(.2,.7,.2,1);
  --t-colour: 150ms; --t-move: 250ms; --t-enter: 400ms;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--paper); color: var(--ink);
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, -apple-system, sans-serif;
  font-size: 15px; line-height: 1.6; overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}
p { text-wrap: pretty; margin: 0; }
a { color: var(--accent); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The heading is focused on every screen change so a screen reader announces
   it. That is not a keyboard user asking for a ring. */
h1[tabindex]:focus, h1[tabindex]:focus-visible { outline: none; }
svg { display: block; }

.mono, .m {
  font-variant-numeric: tabular-nums; letter-spacing: 0;
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;
  font-size: 11.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--muted);
}
.num { font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-variant-numeric: tabular-nums; letter-spacing: -.03em; }

/* ---- demo notice: this is a simulation, and it never pretends otherwise ---- */
.demobar {
  background: var(--ink); color: var(--paper);
  padding: var(--s2) var(--s5); font-size: 12.5px;
  display: flex; gap: var(--s3); align-items: center; justify-content: center; text-align: center;
}
.demobar strong { font-weight: 700; }
.demobar span { color: #b9b6ae; }

/* ---- chrome ---- */
header.app {
  position: sticky; top: 0; z-index: 20; background: var(--paper);
  border-block-end: 1px solid var(--ink);
}
header.app .bar {
  max-width: 1180px; margin: 0 auto; padding: var(--s4) var(--s5);
  display: flex; align-items: center; justify-content: space-between; gap: var(--s5);
}
.brand { display: flex; align-items: center; gap: 10px; }
.brand .name { font-weight: 700; font-size: 17px; letter-spacing: -.02em; line-height: 1; }
.steps { display: flex; align-items: center; gap: var(--s3); }
.step { display: flex; align-items: center; gap: var(--s2); }
.step .dot { inline-size: 7px; block-size: 7px; background: var(--rule); flex: none; }
.step.done .dot { background: var(--muted); }
.step.now .dot { background: var(--accent); }
.step .lbl { font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--faint); }
.step.now .lbl { color: var(--ink); }
.step .sep { inline-size: 18px; block-size: 1px; background: var(--rule); }

main { max-width: 1180px; margin: 0 auto; padding: var(--s7) var(--s5) var(--s8); }
.narrow { max-width: 680px; }
h1 { font-size: clamp(26px, 3.4vw, 36px); font-weight: 700; letter-spacing: -.028em; line-height: 1.1; margin: var(--s3) 0 var(--s3); text-wrap: balance; }
h2 { font-size: 19px; font-weight: 700; letter-spacing: -.02em; margin: 0 0 var(--s3); }
.lead { font-size: 16.5px; color: var(--ink-2); max-width: 60ch; }

/* ---- controls ---- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  font-family: inherit; font-size: 15px; font-weight: 500; cursor: pointer;
  padding: 13px var(--s5); border: 1px solid var(--ink); background: var(--ink); color: var(--paper);
  transition: background-color var(--t-colour) var(--ease), color var(--t-colour) var(--ease);
  text-decoration: none;
}
.btn:hover { background: #000; }
.btn:active { transform: translateY(1px); }
.btn[disabled] { opacity: .38; cursor: not-allowed; }
.btn[disabled]:active { transform: none; }
.btn.ghost { background: transparent; color: var(--ink); border-color: var(--rule); }
.btn.ghost:hover { background: transparent; border-color: var(--ink); }
.btn.small { padding: 8px var(--s4); font-size: 13.5px; }
.actions { display: flex; gap: var(--s3); align-items: center; flex-wrap: wrap; margin-block-start: var(--s6); }
.actions .note { font-size: 13px; color: var(--faint); }

select, input[type=text] {
  font-family: inherit; font-size: 14px; color: var(--ink); background: var(--card);
  border: 1px solid var(--rule); padding: 7px 9px; border-radius: 0; block-size: 36px;
  transition: border-color var(--t-colour) var(--ease);
}
select:hover { border-color: var(--muted); }

/* ---- selectable rows ---- */
.pick { border-block: 1px solid var(--ink); margin-block-start: var(--s6); }
.pick label {
  display: grid; grid-template-columns: 22px 1fr auto; gap: var(--s4); align-items: center;
  padding: var(--s4) var(--s3); border-block-end: 1px solid var(--hair); cursor: pointer;
  transition: background-color var(--t-colour) var(--ease);
}
.pick label:last-child { border-block-end: 0; }
.pick label:hover { background: var(--card); }
.pick label:has(input:checked) { background: var(--card); }
/* A flat square that fills with ink — no rounded native control in this system. */
.pick input { position: absolute; opacity: 0; pointer-events: none; }
.box { inline-size: 17px; block-size: 17px; border: 1px solid var(--muted); position: relative; transition: background-color var(--t-colour) var(--ease), border-color var(--t-colour) var(--ease); }
.pick label:has(input:checked) .box { background: var(--ink); border-color: var(--ink); }
.box::after {
  content: ""; position: absolute; inset-inline-start: 4px; inset-block-start: 1px;
  inline-size: 6px; block-size: 11px; border: solid var(--paper); border-width: 0 2px 2px 0;
  transform: rotate(42deg) scale(0); transition: transform var(--t-colour) var(--ease);
}
.pick label:has(input:checked) .box::after { transform: rotate(42deg) scale(1); }
.pick input:focus-visible + .box { outline: 2px solid var(--accent); outline-offset: 2px; }
.pick .who { font-size: 15px; font-weight: 500; }
.pick .sub { font-size: 13px; color: var(--faint); margin-block-start: 2px; }
.pick .right { text-align: right; font-size: 14px; color: var(--ink-2); }

/* ---- tables ---- */
.tbl { inline-size: 100%; border-collapse: collapse; margin-block-start: var(--s5); }
.tbl th {
  text-align: left; font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px;
  letter-spacing: .09em; text-transform: uppercase; color: var(--muted); font-weight: 400;
  padding: 0 var(--s3) var(--s2) 0; border-block-end: 1px solid var(--ink); white-space: nowrap;
}
.tbl td { padding: var(--s3) var(--s3) var(--s3) 0; border-block-end: 1px solid var(--hair); vertical-align: middle; }
.tbl tr:last-child td { border-block-end: 1px solid var(--ink); }
.tbl .r { text-align: right; }
.tbl .cname { font-size: 14.5px; font-weight: 500; }
.tbl tbody tr { transition: background-color var(--t-colour) var(--ease); }
.tbl tbody tr:hover { background: var(--card); }

/* ---- name chips for bulk selection ---- */
.chips { display: flex; gap: var(--s2); align-items: center; flex-wrap: wrap; margin-block-start: var(--s5); }
.chip {
  font-family: inherit; font-size: 13px; cursor: pointer;
  border: 1px solid var(--rule); background: var(--card); color: var(--ink-2); padding: 6px 12px;
  transition: border-color var(--t-colour) var(--ease), color var(--t-colour) var(--ease);
}
.chip:hover { border-color: var(--ink); color: var(--ink); }

/* ---- summary tiles ---- */
.tiles { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); border: 1px solid var(--ink); margin-block-start: var(--s6); }
.tile { padding: var(--s5); border-inline-end: 1px solid var(--rule); background: var(--card); }
.tile:last-child { border-inline-end: 0; }
.tile .unit { font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--accent); }
.tile .big { font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: clamp(30px, 3.6vw, 44px); font-variant-numeric: tabular-nums; letter-spacing: -.04em; line-height: 1; margin-block: var(--s3) var(--s2); }
.tile p { font-size: 14px; color: var(--ink-2); }

/* ---- findings ---- */
.finding {
  border: 1px solid var(--rule); background: var(--card);
  padding: var(--s4) var(--s5); margin-block-start: var(--s4);
  display: grid; grid-template-columns: 1fr auto; gap: var(--s5); align-items: center;
}
.finding .m { color: var(--accent); margin-block-end: var(--s2); }
.finding .body { font-size: 14.5px; color: var(--ink-2); max-width: 78ch; }
.finding .body b { color: var(--ink); font-weight: 700; }
.finding .fbtns { display: flex; gap: var(--s2); flex: none; }
.finding.resolved { background: var(--panel); border-color: var(--hair); }
.finding.resolved .fbtns { display: none; }
.done-note { font-size: 13.5px; color: var(--good); font-weight: 500; white-space: nowrap; }

/* ---- panels ---- */
.panel { background: var(--panel); border: 1px solid var(--ink); padding: var(--s6); margin-block-start: var(--s7); }
.panel h2 { margin-block-end: var(--s2); }

/* ---- the watching state ---- */
.watch { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s8); align-items: center; }
.daybar { display: flex; gap: 3px; margin-block-start: var(--s5); }
.daybar i { flex: 1; block-size: 34px; background: var(--hair); display: block; }
.daybar i.on { background: var(--ink); }
.rows2 { border-block-start: 1px solid var(--ink); margin-block-start: var(--s5); }
.rows2 .r { padding-block: var(--s3); border-block-end: 1px solid var(--rule); }
.rows2 .r:last-child { border-block-end: 0; }
.rows2 .k { font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--accent); }
.rows2 .v { font-size: 14.5px; color: var(--ink-2); margin-block-start: 3px; }

/* ---- utilisation bar ---- */
.util { inline-size: 96px; block-size: 8px; background: var(--hair); position: relative; }
.util i { display: block; block-size: 100%; background: var(--ink); }
.util.over i { background: var(--accent); }

@media (prefers-reduced-motion: no-preference) {
  .screen { animation: enter var(--t-enter) var(--ease); }
}
@keyframes enter { from { opacity: 0; transform: translateY(8px); } }

@media (max-width: 900px) {
  .watch { grid-template-columns: 1fr; gap: var(--s6); }
  .tiles { grid-template-columns: 1fr; }
  .tile { border-inline-end: 0; border-block-end: 1px solid var(--rule); }
  .tile:last-child { border-block-end: 0; }
  .finding { grid-template-columns: 1fr; gap: var(--s3); }
  .steps .lbl { display: none; }
  .tblwrap { overflow-x: auto; }
}

/* ---- classes that replace what used to be inline style attributes ---------
   The site's Content-Security-Policy allows neither inline script nor inline
   style attributes, which is the right posture for something that will hold a
   customer's Google Ads authorisation. Values only known at render time are
   set through the CSSOM instead, which is not an inline style and is allowed. */
.brandlink { color: inherit; text-decoration: none; }
.gap-t { margin-block-start: var(--s8); }
.gap-s { margin-block-start: var(--s3); }
.sub { font-size: 15px; color: var(--ink-2); max-width: 62ch; }
.sub.wide { font-size: 15.5px; max-width: 64ch; }
.provenance { margin-block-start: var(--s8); font-size: 13px; color: var(--faint); max-width: 70ch; }
.chipslabel { margin-inline-end: var(--s1); }
.cbud { font-size: 12.5px; color: var(--faint); font-weight: 400; }
.utilcell { display: flex; align-items: center; gap: 10px; }
.num.sm { font-size: 13.5px; }
.pick .right .per { color: var(--faint); }
.util i { inline-size: 0; }

/* ---- the operational board -------------------------------------------------
   A screen that is scanned every morning, not read once. Summary before
   detail, state encoded in shape as well as in words, and the one number that
   matters — how a campaign is doing against ITS OWN day — given a whole column
   rather than a percentage buried in a row. */
.boardhead { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s5); flex-wrap: wrap; }
.boardhead h1 { margin-block-end: 0; }
.modebox { display: flex; align-items: center; gap: var(--s3); }
.mode {
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px; letter-spacing: .09em;
  text-transform: uppercase; padding: 5px var(--s3); border: 1px solid var(--muted); color: var(--muted);
}
.mode.on { border-color: var(--accent); color: var(--accent); }

/* The scrubber is the chart's x axis, not a control parked above the page: it
   is padded by the plot's own gutters (set in drawChart) so hour 0 sits under
   the 00:00 tick. And it is a playhead, not a ball — a round thumb on a
   timeline reads as a volume knob and is the wrong metaphor for a marker that
   has an exact position on an axis. */
.scrub { margin-block-start: 2px; }
.scrub input[type=range] {
  -webkit-appearance: none; appearance: none; inline-size: 100%; display: block;
  block-size: 20px; margin: 0; background: none; cursor: ew-resize;
}
.scrub input[type=range]::-webkit-slider-runnable-track { block-size: 2px; background: var(--edge); }
.scrub input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none; inline-size: 3px; block-size: 18px; border: 0;
  border-radius: 1px; background: var(--act); margin-block-start: -8px;
}
.scrub input[type=range]::-moz-range-track { block-size: 2px; background: var(--edge); }
.scrub input[type=range]::-moz-range-thumb {
  inline-size: 3px; block-size: 18px; border: 0; border-radius: 1px; background: var(--act);
}
.scrub input[type=range]:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent); }
.scrub input[type=range]:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent); }
.scrub input[type=range]:focus { outline: none; }
.scrubfoot { font-size: 12px; color: var(--faint); margin-block-start: 2px; max-inline-size: 62ch; }

.tiles.compact { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1100px) { .tiles.compact { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.tiles.compact .big { font-size: clamp(24px, 2.6vw, 32px); }
.tiles.compact .tile { padding: var(--s4) var(--s5); }

.tbl.board td { padding-block: 10px; }
/* A solid tint, not color-mix over transparent: the computed value has to be a
   colour a contrast check can actually read, and every foreground on this row
   still has to clear AA. Measured on #f8f2f0 — ink 16.04, faint 5.04,
   accent 8.34, warn 5.89. */
.tbl.board tr.hot { background: #f8f2f0; }
.num.sm.raised { color: var(--accent); font-weight: 500; }

/* Two readings on one track: the fill is where it has got to, the hairline is
   where its own curve says it should be by now. */
.pace { position: relative; inline-size: 130px; block-size: 10px; background: var(--hair); }
.pace .fill { display: block; block-size: 100%; inline-size: 0; background: var(--ink); }
.pace .fill.accent { background: var(--accent); }
.pace .fill.warn   { background: #b06a2c; }
.pace .fill.good   { background: var(--good); }
.pace .fill.muted  { background: var(--faint); }
.pace .mark { position: absolute; inset-block: -3px; inline-size: 1px; background: var(--ink); opacity: .55; }

.pill {
  display: inline-block; font-size: 12.5px; padding: 3px 9px; white-space: nowrap;
  border: 1px solid currentColor;
}
.pill.good { color: var(--good); }
.pill.accent { color: var(--accent); }
.pill.warn { color: #8a4f1d; }
.pill.muted { color: var(--faint); }

.switch {
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase;
  min-inline-size: 54px; padding: 5px 0; cursor: pointer;
  background: transparent; border: 1px solid var(--rule); color: var(--faint);
  transition: border-color var(--t-colour) var(--ease), color var(--t-colour) var(--ease), background-color var(--t-colour) var(--ease);
}
.switch.on { border-color: var(--ink); background: var(--ink); color: var(--paper); }

.boardgrid { display: grid; gap: var(--s7); margin-block-start: var(--s7); }
@media (min-width: 1000px) { .boardgrid { grid-template-columns: 1.15fr 1fr; gap: var(--s8); } }
.log { border-block-start: 1px solid var(--ink); margin-block-start: var(--s4); }
.log .entry { display: grid; grid-template-columns: 62px 1fr; gap: var(--s4); padding-block: var(--s3); border-block-end: 1px solid var(--hair); }
.log .entry:last-child { border-block-end: 0; }
.log .when { font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 12px; color: var(--accent); }
.log .what { font-size: 14.5px; font-weight: 500; }
.log .why { font-size: 13.5px; color: var(--ink-2); margin-block-start: 2px; }
.rows2 .hintline { display: block; font-size: 13px; color: var(--faint); margin-block-start: 4px; }

/* ---- dashboard surface -----------------------------------------------------
   The app is scanned and operated, not read, so it drops the editorial rhythm:
   smaller headings, tighter rows, panelled surfaces with real edges, and data
   given the room instead of the prose. */
.screen .boardhead h1 { font-size: clamp(22px, 2.4vw, 28px); letter-spacing: -.022em; }
.tbl.board td { padding-block: 8px; }
.tbl.board th { padding-block-end: 6px; }

".chart {
  border: 1px solid var(--rule); background: var(--card);
  padding: var(--s4) var(--s4) var(--s3); margin-block-start: var(--s5);
}
/* Inside a panel the chart is not its own card, and its padding would be a
   second inset — which silently scales every unit in the SVG, and with it the
   axis type. */
.pnl .chart { border: 0; background: none; padding: 0; margin-block-start: 0; }
.chart svg { inline-size: 100%; block-size: auto; }
#daychart { min-block-size: 1px; }   /* measured with the panel's own padding */
.chart .grid { stroke: var(--hair); stroke-width: 1; }
.chart .axis {
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 12px;
  fill: var(--faint); letter-spacing: -.02em;
}
.chart .expected { fill: none; stroke: #9a978f; stroke-width: 1.6; stroke-dasharray: 5 4; }
.chart .area { fill: var(--accent); opacity: .07; stroke: none; }
.chart .actual { fill: none; stroke: var(--accent); stroke-width: 2.2; stroke-linejoin: round; stroke-linecap: round; }
.chart .nowline { stroke: var(--ink); stroke-width: 1; opacity: .35; }
.chart .dot { fill: var(--accent); stroke: var(--card); stroke-width: 2; }
.chartkey { display: flex; gap: var(--s5); flex-wrap: wrap; margin-block-start: var(--s2); font-size: 12.5px; color: var(--ink-2); }
.chartkey span { display: flex; align-items: center; gap: 7px; }
.chartkey i { inline-size: 18px; block-size: 0; flex: none; }
.chartkey i.k-actual { border-top: 2.2px solid var(--accent); }
.chartkey i.k-expected { border-top: 2px dashed #9a978f; }

/* ---- findings --------------------------------------------------------------
   A report should say what is true of the account, not hand over the rows and
   let the reader work it out. The number leads, the sentence explains what it
   costs, and the campaigns behind it fold away rather than crowding it out. */
.findings { border-block-start: 1px solid var(--ink); margin-block-start: var(--s6); }
.found {
  display: grid; grid-template-columns: minmax(140px, 210px) 1fr; gap: var(--s6);
  padding-block: var(--s5); border-block-end: 1px solid var(--rule); align-items: start;
}
.found:last-child { border-block-end: 1px solid var(--ink); }
.foundnum {
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;
  font-size: clamp(26px, 3vw, 38px); letter-spacing: -.045em; line-height: 1;
  color: var(--accent); font-variant-numeric: tabular-nums;
}
.foundhead { font-size: 17px; font-weight: 700; letter-spacing: -.015em; line-height: 1.3; }
.foundbody { font-size: 15px; color: var(--ink-2); max-width: 68ch; margin-block-start: var(--s2); }

.which { margin-block-start: var(--s3); }
.which summary {
  list-style: none; cursor: pointer; display: inline-block;
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--muted);
  border-block-end: 1px solid var(--rule); padding-block-end: 2px;
  transition: color var(--t-colour) var(--ease), border-color var(--t-colour) var(--ease);
}
.which summary::-webkit-details-marker { display: none; }
.which summary:hover { color: var(--ink); border-block-end-color: var(--ink); }
.which[open] summary { color: var(--accent); border-block-end-color: var(--accent); }
.which ul { margin: var(--s3) 0 0; padding-inline-start: 0; list-style: none; }
.which li {
  font-size: 14px; color: var(--ink-2); padding-block: 5px;
  border-block-end: 1px solid var(--hair);
}
.which li:last-child { border-block-end: 0; }

.everything { margin-block-start: var(--s7); border-block: 1px solid var(--rule); }
.everything summary {
  list-style: none; cursor: pointer; padding-block: var(--s4);
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--muted);
}
.everything summary::-webkit-details-marker { display: none; }
.everything summary:hover { color: var(--ink); }
.everything[open] summary { color: var(--ink); border-block-end: 1px solid var(--hair); }
.everything .tblwrap { padding-block-end: var(--s5); }

@media (max-width: 760px) {
  .found { grid-template-columns: 1fr; gap: var(--s3); }
}

/* ═══ THE APP IS NOT THE WEBSITE ═════════════════════════════════════════════
   The site's design brief says: flat surfaces, no radius, no shadow, "this is
   the brand". That rule was written for a page that is read once. This is an
   instrument that gets opened every morning, and holding it to the same rule is
   what made it look like a document with numbers in it.

   So the two share a lineage — the same palette family, 'IBM Plex Sans' and a monospace
   for figures, the same restraint — and diverge where the job differs: panels
   that lift off a deeper ground, a console bar that says the thing is running,
   status carried in colour and a stripe rather than in a sentence, controls
   that look like controls.

   Semantic colour is separate from the accent and is never used for anything
   else. Every pill's text clears AA on its own tint, which the obvious choices
   for these hues do not: green 4.31, amber 3.20, rust 3.98 as first drawn.
   These are the darkened steps — 5.96, 5.18, 5.62. */
.app-shell {
  /* A data-oriented ground, not an editorial one. The marketing site's warm
     paper is right for a page you read once; behind a table of numbers it makes
     everything look like a brochure. This is a cool neutral so the only warm
     thing on screen is the one that means "look at this".

     Every step below clears AA on all three surfaces — the ground, white panels
     and the zebra row. The obvious mid-greys do not: #6b7280 measures 4.16 on
     the ground, which is why the muted step is darker than it looks like it
     needs to be. */
  --ground:  #eceef1;
  --surface: #ffffff;
  --row:     #f7f8fa;
  --edge:    #d8dce1;
  --hair2:   #e8ebee;
  --console: #14171a;
  --console-ink: #e8eaed;
  --console-dim: #949ba6;

  --ink:   #14171a;
  --ink-2: #3d434c;
  --muted: #5a6270;
  --faint: #626a76;

  /* Semantic, and used for nothing else. Warm only where it means attention. */
  --good: #1f6b45;  --good-bg: #e6f2ec;
  --warn: #b04a00;  --warn-bg: #fbeee2;
  --act:  #a8331c;  --act-bg:  #fbe9e4;
  --idle: #5a6270;  --idle-bg: #e9ebee;
  --accent: #a8331c;

  /* Crisp rather than soft. 8px reads as a SaaS card; 3px reads as a panel. */
  --r: 3px;
  background: var(--ground);

  /* The grey ramp was solved against the site's paper (#f4f3f0). This ground is
     darker, so the same greys measure lower on it — --faint landed at 4.47.
     Re-solved for the surfaces this shell actually uses: 4.96 on the ground,
     5.93 on a panel, 5.43 on the protecting-row tint. */
  --faint: #5f6166;
}

/* ---- console bar ---- */
.console {
  position: sticky; top: 0; z-index: 30;
  background: var(--console); color: var(--console-ink);
  display: flex; align-items: center; gap: var(--s4);
  padding: 10px var(--s5); flex-wrap: wrap;
}
.console .cbrand { font-weight: 700; letter-spacing: .01em; }
.console .clive {
  display: flex; align-items: center; gap: 7px;
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px; letter-spacing: .1em;
}
.livedot { inline-size: 8px; block-size: 8px; border-radius: 50%; background: #4bb37c; flex: none; }
@media (prefers-reduced-motion: no-preference) {
  .livedot { animation: pulse 2s infinite; }
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(75,179,124,.55); }
  70%  { box-shadow: 0 0 0 7px rgba(75,179,124,0); }
  100% { box-shadow: 0 0 0 0 rgba(75,179,124,0); }
}
.console .csteps {
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px;
  letter-spacing: .1em; color: var(--console-dim);
}
.console .csteps b { color: #d7b25a; font-weight: 400; }
.console .cclock {
  margin-inline-start: auto; font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;
  font-size: 11.5px; color: var(--console-dim); letter-spacing: .04em;
}

/* ---- panels ---- */
.pnl {
  background: var(--surface); border: 1px solid var(--edge); border-radius: var(--r);
  padding: var(--s4) var(--s5); margin-block-start: var(--s3);
}
.pnl > h3 {
  margin: 0 0 var(--s3); font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;
  font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--idle);
  font-weight: 400; display: flex; justify-content: space-between; gap: var(--s4); align-items: center;
}

/* ---- account bar ---- */
.acct { display: flex; align-items: flex-end; gap: var(--s4); padding-block: var(--s5) var(--s3); flex-wrap: wrap; }
.acct .aname { font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--idle); }
.acct .anow { font-size: 24px; font-weight: 700; letter-spacing: -.022em; line-height: 1.1; margin-block-start: 2px; }
.acct .abtns { margin-inline-start: auto; display: flex; gap: var(--s2); align-items: center; }

/* ---- KPI cards ---- */
.kpis { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: var(--s2); margin-block-end: var(--s3); }
.kpi { background: var(--surface); border: 1px solid var(--edge); border-radius: var(--r); padding: 10px var(--s3) 0; }
.kpi .kl {
  white-space: nowrap;
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--idle); display: flex; justify-content: space-between; gap: var(--s2);
}
.kpi .kv {
  font-size: 25px; font-weight: 600; font-variant-numeric: tabular-nums;
  letter-spacing: -.02em; line-height: 1.15; margin-block: 3px 1px;
}
.kpi .ks {
  font-size: 12px; color: var(--muted); line-height: 1.35;
  /* Two lines' worth, always. A one-line sub next to a two-line one used to
     change the row's height as the day moved. */
  min-block-size: 2.4em; padding-block-end: 8px;
}
.kpi.k-act .kv  { color: var(--act); }
.kpi.k-warn .kv { color: var(--warn); }
/* The rule is the box's baseline, so all four end on the same pixel whether or
   not there is a proportion to draw in it. */
.kpi .krule { block-size: 3px; background: var(--hair2); margin-inline: calc(var(--s3) * -1); }
.kpi .krule i { display: block; block-size: 100%; inline-size: 0; background: var(--ink-2); }
.kpi.k-act .krule i  { background: var(--act); }
.kpi.k-warn .krule i { background: var(--warn); }

/* ---- dense table ---- */
.grid { inline-size: 100%; border-collapse: collapse; font-size: 13px; }
.grid th {
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--idle); font-weight: 400;
  text-align: right; padding: var(--s2) var(--s2) var(--s3); border-block-end: 1px solid var(--edge); white-space: nowrap;
}
.grid th.l, .grid td.l { text-align: left; }
.grid td { padding: 9px var(--s2); border-block-end: 1px solid var(--hair2); font-variant-numeric: tabular-nums; text-align: right; }
.grid tbody tr:last-child td { border-block-end: 0; }
/* Status as a stripe, so a row's state is readable before any word is. */
.grid td:first-child { border-inline-start: 3px solid transparent; padding-inline-start: 10px; }
.grid tr.s-ok td:first-child     { border-inline-start-color: var(--good); }
.grid tr.s-under td:first-child  { border-inline-start-color: var(--warn); }
.grid tr.s-acting td:first-child { border-inline-start-color: var(--act); }
.grid tr.s-shared td:first-child, .grid tr.s-off td:first-child { border-inline-start-color: #c9c6bc; }
/* A solid tint, not color-mix over transparent: a contrast check has to be able
   to read the computed value. Measured — ink 15.56, idle 5.78, act 6.02. */
.grid tr.s-acting { background: #f8eee8; }
.grid .cn { font-weight: 500; }
.grid .cs { font-size: 11.5px; color: var(--idle); font-weight: 400; white-space: nowrap; }

.tag {
  display: inline-block; font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;
  font-size: 11.5px; letter-spacing: .03em; padding: 3px 9px; border-radius: 999px; white-space: nowrap;
}
.tag.ok { color: var(--good); background: var(--good-bg); }
.tag.under { color: var(--warn); background: var(--warn-bg); }
.tag.acting { color: var(--act); background: var(--act-bg); }
.tag.shared, .tag.off { color: var(--idle); background: var(--idle-bg); }

.pace2 { position: relative; inline-size: 92px; block-size: 8px; background: #eceae2; border-radius: 4px; display: inline-block; vertical-align: middle; }
.pace2 .f { position: absolute; inset-block: 0; inset-inline-start: 0; border-radius: 4px; inline-size: 0; }
.pace2 .f.ok { background: var(--good); } .pace2 .f.under { background: var(--warn); }
.pace2 .f.acting { background: var(--act); } .pace2 .f.shared, .pace2 .f.off { background: #c9c6bc; }
.pace2 .m { position: absolute; inset-block: -3px; inline-size: 1.5px; background: var(--ink); opacity: .6; }

/* A control that looks like a control. */
.sw {
  inline-size: 36px; block-size: 20px; border-radius: 10px; background: #c9c6bc;
  position: relative; cursor: pointer; border: 0; padding: 0; flex: none;
  transition: background-color var(--t-colour) var(--ease);
}
.sw::after {
  content: ""; position: absolute; inset-block-start: 2px; inset-inline-start: 2px;
  inline-size: 16px; block-size: 16px; border-radius: 50%; background: #fff;
  transition: transform var(--t-colour) var(--ease);
}
.sw[aria-pressed="true"] { background: var(--good); }
.sw[aria-pressed="true"]::after { transform: translateX(16px); }
.sw:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- feed ---- */
.feed2 .fr { display: grid; grid-template-columns: 54px 1fr; gap: var(--s3); padding-block: var(--s2); border-block-end: 1px solid var(--hair2); align-items: baseline; }
.feed2 .fr:last-child { border-block-end: 0; }
.feed2 .ft { font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 12px; color: var(--act); }
.feed2 .fm { font-size: 13px; color: var(--idle); }
.feed2 .fm b { color: var(--ink); font-weight: 500; }

/* ---- control rail ---- */
.rail { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: var(--s3); }
.ctl { border: 1px solid var(--edge); border-radius: 6px; padding: var(--s3) var(--s4); background: #fff; }
.ctl .ck { font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--idle); }
.ctl .cv { margin-block-start: 4px; font-size: 13.5px; display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }

.btn.app { border-radius: 6px; padding: 8px var(--s4); font-size: 13.5px; }
.tag.mode { border: 1px solid currentColor; background: transparent; padding: 5px 11px; }
.tag.mode.observing { color: var(--warn); }
.tag.mode.livemode { color: var(--act); }

@media (max-width: 860px) {
  .kpis { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .rail { grid-template-columns: 1fr; }
  .grid .hidesm { display: none; }
  .console .csteps { display: none; }
}

/* ---- at a glance -----------------------------------------------------------
   One line per finding: the number, then what it means. No reasoning, no
   controls, no table — this is the screen that hands the reader a headline and
   a way forward, not the account review. */
.glance { list-style: none; margin: var(--s6) 0 0; padding: 0; border-block-start: 1px solid var(--ink); }
.glance li {
  display: grid; grid-template-columns: minmax(120px, 190px) 1fr; gap: var(--s5);
  padding-block: var(--s4); border-block-end: 1px solid var(--rule); align-items: baseline;
}
.glance .gn {
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;
  font-size: clamp(19px, 2.1vw, 25px); letter-spacing: -.04em; color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.glance .gt { font-size: 16px; color: var(--ink-2); max-width: 56ch; }
@media (max-width: 700px) {
  .glance li { grid-template-columns: 1fr; gap: 4px; }
}

.unlocks { margin-block-start: var(--s6); }
.unlocks .r .k { color: var(--accent); }

/* ---- chart filter ---- */
.chips2 { display: flex; gap: 6px; flex-wrap: wrap; margin-block-end: var(--s3); }
.chip2 {
  font-family: inherit; font-size: 12.5px; cursor: pointer;
  padding: 5px 11px; border-radius: 999px;
  border: 1px solid var(--edge); background: var(--surface); color: var(--idle);
  transition: border-color var(--t-colour) var(--ease), color var(--t-colour) var(--ease), background-color var(--t-colour) var(--ease);
}
.chip2:hover { border-color: var(--ink); color: var(--ink); }
.chip2.on { background: var(--ink); border-color: var(--ink); color: #fff; }

/* ---- chart filter ---- */
.filterbar { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; margin-block-end: var(--s3); }
.filterbar label {
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px;
  letter-spacing: .09em; text-transform: uppercase; color: var(--idle);
}
.filterbar select {
  font-family: inherit; font-size: 13.5px; color: var(--ink); background: #fff;
  border: 1px solid var(--edge); border-radius: 6px; padding: 6px 9px; block-size: 34px;
  max-inline-size: 320px;
}
.filterhint { font-size: 12.5px; color: var(--faint); }
/* Picking a campaign from the table is the other way in, so a row has to look
   like something you can pick. */
.grid tbody tr[data-focus] { cursor: pointer; }
.grid tbody tr[data-focus]:hover { background: #f4f2ec; }
.grid tbody tr.picked { background: #eee9df; }
.grid tbody tr[data-focus]:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* ---- pools ---- */
.pools { margin-block-start: var(--s6); }
.pools .sub { margin-block: var(--s2) var(--s4); }
.poolrow { display: flex; gap: var(--s2); flex-wrap: wrap; align-items: center; }
.poolchip { display: inline-flex; align-items: center; border: 1px solid var(--edge); border-radius: 999px; background: var(--surface); overflow: hidden; }
.poolchip input {
  font-family: inherit; font-size: 13px; color: var(--ink); background: transparent;
  border: 0; padding: 6px 4px 6px 13px; inline-size: 13ch; block-size: auto;
}
.poolchip input:focus { outline: none; background: #fff; }
.poolchip button {
  font-family: inherit; font-size: 15px; line-height: 1; cursor: pointer;
  background: transparent; border: 0; color: var(--faint); padding: 6px 11px 7px 4px;
}
.poolchip button:hover { color: var(--accent); }
.poolchip:focus-within { border-color: var(--ink); }
/* A blocked decision is not a change; it should not read like one. */
.feed2 .fr.blocked .ft { color: var(--idle); }
.feed2 .fr.blocked .fm b:first-child { color: var(--idle); }

/* Editable budgets. Both numbers belong to the customer, so they look like
   fields rather than readings — but stay right-aligned and tabular so a column
   of them still reads as a column. */
.bud {
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 13px;
  font-variant-numeric: tabular-nums; text-align: right;
  inline-size: 9ch; padding: 4px 6px; border-radius: 4px;
  border: 1px solid transparent; background: transparent; color: var(--ink);
  transition: border-color var(--t-colour) var(--ease), background-color var(--t-colour) var(--ease);
}
.bud { border-block-end-color: var(--edge); border-radius: var(--r); }
.bud:hover { border-color: var(--edge); background: #fff; }
.bud:focus { border-color: var(--ink); background: #fff; outline: none; }
.bud.live { inline-size: 11ch; font-weight: 500; }
.bud::-webkit-outer-spin-button, .bud::-webkit-inner-spin-button { opacity: 0; }
.bud:hover::-webkit-inner-spin-button { opacity: 1; }

/* ═══ BOARD LAYOUT ═══════════════════════════════════════════════════════════
   The work leads. Previously a full screen showed a title, a slider, four
   summary tiles and a chart before a single campaign — the one thing the tool
   exists to tell you was entirely below the fold. Now the table is the page,
   the summary is one line of type rather than four boxes of chrome, and the
   chart and the change log sit under it where evidence belongs. */
.hdr {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--s5); flex-wrap: wrap; padding-block: var(--s5) var(--s4);
}
.hdr .aname {
  font-family: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif; font-size: 11.5px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--muted);
}
/* Four boxes again, but operational ones and half the height. The complaint
   was never that a summary is wrong — it is that the old four were reporting
   metrics wearing an operator's clothes, in cards tall enough to push the work
   off the screen. These four are the questions the morning actually asks:
   is anything wrong, how much has gone, is that the right amount by now, and
   where does the day end up. */
.hdr { padding-block: var(--s4) var(--s3); }
.hdr-r { display: flex; align-items: center; gap: var(--s2); }
@media (max-width: 760px) { .kpis { grid-template-columns: repeat(2, minmax(0,1fr)); } }

/* Every row carries its own curve — the argument the product makes, and the
   thing a generic admin table cannot show. */
.rowspark { inline-size: 108px; }
.rowspark svg { display: block; }
.rowspark path { stroke: var(--ink-2); stroke-width: 1.6; }
.rowspark line { stroke: #c3c8cf; }

.tblwrap { background: var(--surface); border: 1px solid var(--edge); border-radius: var(--r); }
.grid tbody tr.alt { background: var(--row); }
.grid tbody tr.crow:hover { background: #eef1f5; }
.grid tbody tr.s-acting { background: var(--act-bg); }
.grid tbody tr.picked { background: #dfe6ef; }
.grid th { background: var(--surface); }
.grid td:first-child { padding-inline-start: 12px; }
.grid th:first-child { padding-inline-start: 15px; }

/* The change log used to be one account-wide feed beside the chart, which made
   you read eight campaigns' entries to answer a question about one. It is now
   a drawer on the row it happened to, and the chart takes the width back. */
.chartpnl { margin-block-start: var(--s3); }

.disc {
  display: inline-flex; align-items: center; gap: 5px; margin-block-start: 3px;
  padding: 1px 6px 1px 3px; border: 1px solid var(--edge); border-radius: var(--r);
  background: var(--surface); color: var(--muted); cursor: pointer;
  font: inherit; font-size: 11.5px; line-height: 1.5;
}
.disc:hover { color: var(--ink); border-color: var(--muted); }
.disc .car { inline-size: 8px; block-size: 8px; fill: none; stroke: currentColor; stroke-width: 1.4; transition: transform .12s ease; }
@media (prefers-reduced-motion: reduce) { .disc .car { transition: none; } }
.disc[aria-expanded="true"] { color: var(--ink); border-color: var(--muted); }
.disc[aria-expanded="true"] .car { transform: rotate(90deg); }

.grid tr.opened td { border-block-end-color: transparent; }
.grid tr.drawer td { padding: 0 var(--s3) 0 12px; text-align: left; border-block-end: 1px solid var(--hair2); }
.dlog { padding: 2px 0 10px; max-block-size: 220px; overflow-y: auto; }
/* Prose, so it gets a measure. Left to itself it ran the full width of a
   ten-column table and read as a spreadsheet cell. */
.de .dm { max-inline-size: 78ch; }
.de {
  display: grid; grid-template-columns: 52px 1fr; gap: var(--s3);
  padding-block: 3px; font-size: 12.5px; color: var(--muted); align-items: baseline;
}
.de .dt { font-size: 11.5px; color: var(--act); }
.de .dm b { color: var(--ink); font-weight: 500; }
.de.blocked .dt { color: var(--faint); }
.de.more { color: var(--faint); font-size: 11.5px; padding-block-start: 6px; }

/* Settings are configuration, not operation. They were taking a full panel on
   the screen somebody opens to see what happened this hour. */
.settings { margin-block-start: var(--s3); border: 1px solid var(--edge); border-radius: var(--r); background: var(--surface); }
/* It read as a heading, so nobody clicked it. A chevron that turns, a hint at
   what is inside, and a hover state make it obviously a thing that opens. */
.settings summary {
  list-style: none; cursor: pointer; padding: 11px var(--s4);
  display: flex; align-items: center; gap: var(--s3); color: var(--ink-2);
}
.settings summary::-webkit-details-marker { display: none; }
.settings summary .car {
  inline-size: 9px; block-size: 9px; flex: none; fill: none;
  stroke: currentColor; stroke-width: 1.5; transition: transform .12s ease;
}
@media (prefers-reduced-motion: reduce) { .settings summary .car { transition: none; } }
.settings[open] summary .car { transform: rotate(90deg); }
.settings summary .sname { font-size: 13px; font-weight: 500; }
.settings summary .shint { font-size: 12px; color: var(--faint); }
@media (max-width: 640px) { .settings summary .shint { display: none; } }
.settings summary:hover { background: var(--row); color: var(--ink); }
.settings summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.settings[open] summary { border-block-end: 1px solid var(--hair2); }
.settings .rail { padding: var(--s4); }

.chart { background: none; border: 0; padding: 0; }
.chart .grid { stroke: var(--hair2); }
.chart .actual { stroke: var(--ink); }
.chart .area { fill: var(--ink); opacity: .05; }
.chart .dot { fill: var(--ink); stroke: var(--surface); }
.chart .nowline { stroke: var(--act); opacity: .6; }
.chart .expected { stroke: #9aa2ad; }
.chartkey i.k-actual { border-top-color: var(--ink); }

/* One line per campaign. Wrapping the name doubled every row's height for no
   information — the full string is a hover away. */
.grid .cn {
  max-inline-size: 28ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  flex: 0 1 auto; min-inline-size: 0;
}
.grid td { padding-block: 7px; }
.grid .bud { padding-block: 3px; }

/* The mock's banner belonged to the warm palette it sat above. */
.app-shell .demobar { background: #2a2f36; }
.app-shell .demobar strong { color: #e6b8a6; }
.app-shell .demobar span { color: #b9c0c9; }


/* ---- filtering the list -------------------------------------------------
   Eight rows fit on a screen; fifty do not, and an account with fifty is
   ordinary. Search by name and filter by state, in the table's own header so
   it is obvious what it governs — and there is only one filter on the screen
   now, because the chart follows it. */
.tfilter {
  display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
  padding: 9px var(--s3) 9px 15px; border-block-end: 1px solid var(--edge);
}
.tscroll { overflow-x: auto; }
.qbox {
  font: inherit; font-size: 13px; flex: 1 1 11rem; inline-size: auto;
  min-inline-size: 0; max-inline-size: 15rem;
  padding: 5px 9px; border: 1px solid var(--edge); border-radius: var(--r);
  background: var(--surface); color: var(--ink);
}
.qbox:focus { border-color: var(--ink); outline: none; }
.qbox::placeholder { color: var(--faint); }
.tfilter select {
  font: inherit; font-size: 13px; padding: 5px 9px; min-inline-size: 0; max-inline-size: 100%;
  border: 1px solid var(--edge); border-radius: var(--r); background: var(--surface); color: var(--ink);
}
.tcount { margin-inline-start: auto; font-size: 12px; color: var(--faint); font-variant-numeric: tabular-nums; }
.grid td.empty { padding: var(--s5) 15px; color: var(--muted); }

/* ---- two drawers, one row ------------------------------------------------ */
/* On the name's own line. Stacked underneath they turned a 42px row into an
   88px one, which is the whole density complaint paid straight back out. */
.cnrow { display: flex; align-items: center; gap: 8px; min-inline-size: 0; }
.discs { display: flex; align-items: center; gap: 4px; flex: none; }
.disc.ico { padding: 3px; }
.disc.ico svg { inline-size: 14px; block-size: 14px; fill: none; stroke: currentColor; stroke-width: 1.2; stroke-linecap: round; }
.disc.ico circle { fill: var(--surface); }
.disc.ico[aria-expanded="true"] { background: var(--ink); border-color: var(--ink); color: var(--surface); }
.disc.ico[aria-expanded="true"] circle { fill: var(--ink); }

/* ---- per-campaign settings ---------------------------------------------- */
.cset { padding: var(--s3) 0 var(--s4); display: grid; gap: 2px; max-inline-size: 96ch; }
.csr {
  display: grid; grid-template-columns: 15rem 13rem 1fr; gap: var(--s3);
  align-items: center; padding-block: 5px;
}
@media (max-width: 900px) { .csr { grid-template-columns: 1fr; gap: 3px; } }
.csk { font-size: 13px; font-weight: 500; color: var(--ink); }
.csc select {
  font: inherit; font-size: 13px; inline-size: 100%; padding: 4px 8px;
  border: 1px solid var(--edge); border-radius: var(--r); background: var(--surface); color: var(--ink);
}
.csw { font-size: 12px; color: var(--faint); }
.csnote { font-size: 12.5px; color: var(--muted); max-inline-size: 78ch; padding-block: var(--s3); }

/* ---- a definition where the word is -------------------------------------- */
.tip { border-block-end: 1px dotted var(--edge); cursor: help; }
.tip:hover, .tip:focus-visible { border-block-end-color: var(--muted); }
.kpi .tip { border-block-end-color: var(--muted); }
.tip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tip::after {
  content: attr(data-tip); position: absolute; z-index: 30;
  inset-block-start: calc(100% + 7px); inset-inline-start: 0;
  inline-size: max-content; max-inline-size: 30ch;
  padding: 7px 9px; border-radius: var(--r);
  background: var(--console); color: var(--console-ink);
  font-size: 12px; font-weight: 400; line-height: 1.4; letter-spacing: 0;
  text-transform: none; text-align: left; white-space: normal;
  display: none;
}
.tip { position: relative; }
.tip:hover::after, .tip:focus-visible::after { display: block; }
/* Near the right edge the box would run off the panel. */
.grid th:nth-last-child(-n+3) .tip::after, .kpis > :last-child .tip::after {
  inset-inline-start: auto; inset-inline-end: 0;
}

/* ---- the scrubber reads as a scrubber ----------------------------------- */
.scrub { position: relative; padding-block-start: 22px; }
.scrubtip {
  position: absolute; inset-block-start: 0; transform: translateX(-50%);
  font-size: 11.5px; font-variant-numeric: tabular-nums; font-weight: 500;
  color: var(--surface); background: var(--act);
  padding: 1px 6px; border-radius: var(--r); pointer-events: none; white-space: nowrap;
}
/* A grip, not a ball: wide enough to look draggable, square enough to keep an
   exact position on the axis. */
.scrub input[type=range]::-webkit-slider-thumb {
  inline-size: 11px; block-size: 20px; border-radius: 2px; margin-block-start: -9px;
  background: var(--act) linear-gradient(90deg, transparent 3px, rgba(255,255,255,.6) 3px 4px,
    transparent 4px 7px, rgba(255,255,255,.6) 7px 8px, transparent 8px);
}
.scrub input[type=range]::-moz-range-thumb {
  inline-size: 11px; block-size: 20px; border-radius: 2px;
  background: var(--act) linear-gradient(90deg, transparent 3px, rgba(255,255,255,.6) 3px 4px,
    transparent 4px 7px, rgba(255,255,255,.6) 7px 8px, transparent 8px);
}
.scrubfoot b { color: var(--ink-2); font-weight: 500; }

/* ---- the guided overlay --------------------------------------------------
   The findings used to be their own page: a headline and three lines of prose
   read before the reader had seen a campaign. Standing on the row instead means
   the claim and its evidence are the same object. */
.tour { position: fixed; inset: 0; z-index: 60; }
/* One element makes the dim and the cut-out: the box is transparent and its
   shadow covers everything outside it. */
.tourhole {
  position: fixed; border-radius: var(--r); pointer-events: none;
  box-shadow: 0 0 0 9999px rgba(14, 17, 20, .58);
  outline: 2px solid var(--act); outline-offset: 0;
  transition: inset-block-start .18s ease, inset-inline-start .18s ease,
              inline-size .18s ease, block-size .18s ease;
}
.tourhole[hidden] { display: none; }
/* With no cut-out to draw, the dim has to come from somewhere. */
.tour:has(.tourhole[hidden])::before { content: ''; position: fixed; inset: 0; background: rgba(14, 17, 20, .58); }
@media (prefers-reduced-motion: reduce) { .tourhole { transition: none; } }

.tourbox {
  position: fixed; inline-size: min(30rem, calc(100vw - 24px));
  background: var(--surface); border: 1px solid var(--edge); border-radius: var(--r);
  padding: var(--s4); box-shadow: 0 14px 40px rgba(14, 17, 20, .3);
}
.tourbox.centred {
  inset-block-start: 50%; inset-inline-start: 50%;
  transform: translate(-50%, -50%);
}
.tourbox .tn {
  font-size: 11.5px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--faint); font-variant-numeric: tabular-nums;
}
.tourbox h2 { font-size: 18px; font-weight: 600; letter-spacing: -.015em; margin-block: 4px 6px; text-wrap: balance; }
.tourbox p { font-size: 13.5px; color: var(--ink-2); line-height: 1.5; }
.tacts { display: flex; align-items: center; gap: var(--s2); margin-block-start: var(--s4); flex-wrap: wrap; }
.tskip {
  font: inherit; font-size: 12.5px; color: var(--faint); background: none;
  border: 0; cursor: pointer; padding: 4px 2px; margin-inline-start: auto;
}
.tskip:hover { color: var(--ink); text-decoration: underline; }

/* ==========================================================================
   Density
   --------------------------------------------------------------------------
   A 15" laptop gives about 800px of viewport, and the board wanted 1251. The
   fix is not one big cut; it is the same cut everywhere, so nothing looks
   squeezed relative to anything else.

   Compact is the default, because this screen is opened to answer a question
   about eight campaigns at once and an operator who has to scroll to see the
   eighth is being asked to hold it in their head. Comfortable is one click
   away and remembered — density is a real setting, not a default somebody
   else picked. Reference: the compact/comfortable convention in data-table
   practice, where compact is 28–32px a row and comfortable is 48–52px.
   ========================================================================== */
.app-shell {
  --rowpad: 4px;      /* 32px rows with 13px type and a 22px sparkline */
  --sparkh: 22px;
  --panelpadv: 10px;
  --panelpadh: 14px;
  --gap: 8px;
}
.app-shell.roomy {
  --rowpad: 9px;
  --sparkh: 26px;
  --panelpadv: 16px;
  --panelpadh: 24px;
  --gap: 12px;
}

.app-shell main { padding-block: var(--gap) var(--s5); }

/* The account line, the mode and the actions on one row. */
.app-shell .hdr { padding-block: 0 var(--gap); align-items: center; }
.app-shell .hdr .aname { font-size: 11px; }

/* Four boxes, one line of content each. The label sits above; the value and
   what it is out of sit beside each other, because "$868 of $1,556" is one
   fact and was being read as two. */
.app-shell .kpis { gap: 6px; margin-block-end: var(--gap); }
.app-shell .kpi { padding: 6px 10px 0; }
.app-shell .kpi .kl { font-size: 10.5px; letter-spacing: .07em; }
.app-shell .kpi .kv { font-size: 19px; margin-block: 1px 0; }
.app-shell .kpi .kvrow { display: flex; align-items: baseline; gap: 7px; }
.app-shell .kpi .ks { font-size: 11.5px; min-block-size: 0; padding-block-end: 6px; }
.app-shell .kpi .krule { margin-inline: -10px; }

.app-shell .tfilter { padding: 6px var(--s2) 6px 12px; gap: 6px; }
.app-shell .qbox, .app-shell .tfilter select { padding: 3px 8px; font-size: 12.5px; }

.app-shell .grid th { padding: 5px var(--s2) 6px; font-size: 11px; }
.app-shell .grid td { padding-block: var(--rowpad); }
.app-shell .grid .bud { padding-block: 2px; }
.app-shell .rowspark svg { block-size: var(--sparkh); }
.app-shell .disc { padding-block: 0; line-height: 1.45; }
.app-shell .disc.ico { padding: 2px; }

.app-shell .pnl { padding: var(--panelpadv) var(--panelpadh); margin-block-start: var(--gap); }
.app-shell .pnl > h3 { margin-block-end: 6px; }
.app-shell .scrubfoot { font-size: 11.5px; margin-block-start: 0; }
.app-shell .chartkey { margin-block-start: 4px; }
.app-shell .settings { margin-block-start: var(--gap); }
.app-shell .settings summary { padding-block: 7px; }

/* Density and the performance columns sit with the other table controls,
   because that is what they change. */
.tdense { display: flex; gap: 0; margin-inline-start: auto; }
.tdense button {
  font: inherit; font-size: 11.5px; padding: 3px 9px; cursor: pointer;
  border: 1px solid var(--edge); background: var(--surface); color: var(--muted);
}
.tdense button:first-child { border-start-start-radius: var(--r); border-end-start-radius: var(--r); }
.tdense button:last-child { border-start-end-radius: var(--r); border-end-end-radius: var(--r); margin-inline-start: -1px; }
.tdense button[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: var(--surface); }
.tdense button:hover:not([aria-pressed="true"]) { color: var(--ink); }
.tcount { margin-inline-start: 0; }

/* The last 97px. Same proportional cut everywhere, so nothing reads as
   squeezed next to something that was not. */
.app-shell .demobar { padding-block: 4px; font-size: 11.5px; }
.app-shell .console { padding-block: 7px; }
.app-shell main { padding-block: 8px 12px; }
.app-shell .hdr { padding-block: 0 6px; }
.app-shell .tfilter { padding-block: 4px; }
.app-shell .grid td { padding-block: var(--rowpad); }
.app-shell .rowspark svg { block-size: var(--sparkh); }
.app-shell .cnrow { flex-wrap: nowrap; }
.app-shell .scrub { padding-block-start: 18px; }
.app-shell .scrub input[type=range] { block-size: 16px; }
.app-shell .scrub input[type=range]::-webkit-slider-thumb { block-size: 16px; margin-block-start: -7px; }
.app-shell .scrub input[type=range]::-moz-range-thumb { block-size: 16px; }
.app-shell .scrubtip { font-size: 11px; }

/* The legend and the caption are both one short line about the same figure, so
   they share one. The legend is moved under the scrubber by drawChart, which
   puts it immediately before the caption — this pairs them. */
.app-shell .chartkey { float: inline-start; margin-inline-end: var(--s4); margin-block-start: 2px; }
.app-shell .scrubfoot { margin-block-start: 2px; }
.app-shell .footrow {
  display: flex; align-items: baseline; gap: var(--s2) var(--s5);
  flex-wrap: wrap; margin-block-start: 3px;
}
.app-shell .chartkey { float: none; margin: 0; }
.app-shell .scrubfoot { max-inline-size: none; margin: 0; }
.app-shell .tfilter { padding-block: 3px; }
.app-shell .settings summary { padding-block: 5px; }
.tdense-one {
  font: inherit; font-size: 11.5px; padding: 3px 9px; cursor: pointer;
  border: 1px solid var(--edge); border-radius: var(--r);
  background: var(--surface); color: var(--muted);
}
.tdense-one[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: var(--surface); }
.tdense-one:hover:not([aria-pressed="true"]) { color: var(--ink); }
/* The findings are worth a colour when there are some. */
.btn.hasfound { border-color: var(--act); color: var(--act); }
.btn.hasfound:hover { background: var(--act-bg); }

/* ==========================================================================
   Numbers wear their own face
   --------------------------------------------------------------------------
   A column of figures and a column of campaign names in the same typeface read
   as one field of text. Plex Sans Condensed is the same voice a size narrower:
   obviously a different thing, obviously the same family, and narrower is what
   a column of money wants anyway.
   ========================================================================== */
.app-shell .num, .app-shell .kpi .kv, .app-shell .bud, .app-shell .de .dt,
.app-shell .tcount, .app-shell .scrubtip, .app-shell .tlticks,
.app-shell .grid td.num, .app-shell .chart .axis {
  font-family: 'IBM Plex Sans Condensed', 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}
.app-shell .kpi .kv { font-size: 21px; letter-spacing: -.01em; }
.app-shell .grid td.num, .app-shell .bud { font-size: 13.5px; }
/* A budget protection moved today is a fact about the number, so it belongs on
   the number rather than on a second line under it. */
.app-shell .bud.moved { color: var(--act); font-weight: 500; }

/* ==========================================================================
   The day as a timeline
   --------------------------------------------------------------------------
   The account-wide chart is gone. The product's whole claim is that campaigns
   do not behave alike, which makes the sum of them the least interesting line
   on the screen — and it was costing 215px to say so. What is left is the
   control that was attached to it, now labelled and ticked so it reads as a day
   rather than as a slider somebody forgot to explain.
   ========================================================================== */
.timeline {
  display: flex; align-items: center; gap: var(--s4);
  padding: 4px var(--s3) 2px 2px; margin-block-end: var(--gap);
}
.timeline .tlab {
  font-size: 11px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); white-space: nowrap; flex: none;
}
.timeline .scrub { flex: 1 1 auto; min-inline-size: 0; padding-block-start: 16px; }
.tlticks {
  display: flex; justify-content: space-between; font-size: 10.5px;
  color: var(--faint); margin-block-start: -2px;
}

/* ==========================================================================
   The drawer earns its space
   --------------------------------------------------------------------------
   The sparkline column was 108px of curve nobody could read, repeated down the
   page and — on an account whose campaigns share a profile — repeated
   identically. Opened on the row you asked about, the same information at a
   size you can read it is worth having.
   ========================================================================== */
.dpanes { display: grid; gap: var(--s4); padding-block: 4px 8px; }
@media (min-width: 980px) { .dpanes { grid-template-columns: minmax(320px, 1.05fr) 1fr; align-items: start; } }
.dchart { min-inline-size: 0; }
.dchart .chart { background: none; border: 0; padding: 0; }
.dchart .chartkey { font-size: 11px; margin-block-start: 2px; }
.dpanes .dlog { max-block-size: 160px; padding: 0; }

/* ---- the drawer's log stops at the recent few ---------------------------- */
.dmore {
  display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
  margin-block-start: 6px; font-size: 11.5px; color: var(--faint);
}
.dmore span { margin-inline-end: auto; }

/* ---- the report's log ---------------------------------------------------- */
.grid.log td { padding-block: 5px; }
.grid.log .cn { max-inline-size: 24ch; }
.grid.log .why { color: var(--muted); font-size: 12.5px; max-inline-size: 46ch; }
.grid.log tr.blockedrow .why, .grid.log tr.blockedrow td.num { color: var(--faint); }
.logmore { margin-block-start: var(--s2); font-size: 12px; }
.reportchart .sub { margin-block-start: var(--s2); max-inline-size: 72ch; }
.pnl > h3 .chip2 { text-transform: none; letter-spacing: 0; }

/* ==========================================================================
   Type scale, tied to density
   --------------------------------------------------------------------------
   15px body and 13.5px figures are a reading size, and this is not a page you
   read — it is a panel you scan for the one row that is wrong. Everything drops
   roughly a step and a half. Nothing goes under 10px, and the floor is only for
   uppercase letterspaced labels; anything that is a sentence or a number stays
   at 12 or above.

   Comfortable puts every one of these back, which is the point of having it:
   the previous scale was not wrong, it was one choice, and now it is a setting
   rather than a decision somebody else made.
   ========================================================================== */
.app-shell { font-size: 13px; }
.app-shell .grid .cn        { font-size: 12px; }
.app-shell .grid td.num,
.app-shell .bud             { font-size: 12.5px; }
.app-shell .grid th         { font-size: 10px; letter-spacing: .07em; }
.app-shell .grid .tag       { font-size: 10.5px; padding-block: 1px; }
.app-shell .grid .cs        { font-size: 10.5px; }
.app-shell .kpi .kl         { font-size: 10px; }
.app-shell .kpi .kv         { font-size: 17px; }
.app-shell .kpi .ks         { font-size: 11px; padding-block-end: 5px; }
.app-shell .hdr .aname      { font-size: 10px; }
.app-shell .qbox,
.app-shell .tfilter select  { font-size: 12px; }
.app-shell .tcount,
.app-shell .tdense button,
.app-shell .tdense-one      { font-size: 10.5px; }
.app-shell .timeline .tlab  { font-size: 10px; }
.app-shell .tlticks         { font-size: 10px; }
.app-shell .scrubtip        { font-size: 10.5px; }
.app-shell .disc            { font-size: 10.5px; }
.app-shell .settings summary .sname { font-size: 12px; }
.app-shell .settings summary .shint { font-size: 11px; }
.app-shell .de              { font-size: 11.5px; }
.app-shell .de .dt          { font-size: 10.5px; }
.app-shell .btn.app         { font-size: 12px; padding: 5px 11px; }
.app-shell .tag.mode        { font-size: 10.5px; }
.app-shell .csk             { font-size: 12px; }
.app-shell .csw             { font-size: 11px; }
.app-shell .csc select      { font-size: 12px; padding: 3px 7px; }
.app-shell .grid.log .why   { font-size: 11.5px; }
.app-shell .tip::after      { font-size: 11.5px; }
.app-shell .tourbox h2      { font-size: 16px; }
.app-shell .tourbox p       { font-size: 12.5px; }

/* And the space between it all, once the type is smaller. */
.app-shell .demobar { padding-block: 3px; font-size: 11px; }
.app-shell .console { padding-block: 5px; font-size: 11px; }
.app-shell main { padding-block: 6px 10px; }
.app-shell .hdr { padding-block: 0 5px; }
.app-shell .kpi { padding: 4px 9px 0; }
.app-shell .kpis { gap: 5px; }
.app-shell .grid td { padding-block: 3px; }
.app-shell .grid th { padding: 4px var(--s2) 5px; }
.app-shell .tfilter { padding-block: 3px; }
.app-shell .timeline { padding-block: 2px 0; }
.app-shell .timeline .scrub { padding-block-start: 15px; }
.app-shell .settings summary { padding-block: 4px; }

/* Onboarding is two screens that have to fit; the headline was set for a
   marketing page and carried over. */
.app-shell .screen.narrow h1 { font-size: clamp(19px, 1.9vw, 24px); }
.app-shell .lead { font-size: 13.5px; }

/* ---- Comfortable puts it all back --------------------------------------- */
.app-shell.roomy { font-size: 15px; }
.app-shell.roomy .grid .cn        { font-size: 13px; }
.app-shell.roomy .grid td.num,
.app-shell.roomy .bud             { font-size: 13.5px; }
.app-shell.roomy .grid th         { font-size: 11px; padding: 5px var(--s2) 6px; }
.app-shell.roomy .grid .tag       { font-size: 11.5px; padding-block: 2px; }
.app-shell.roomy .grid .cs        { font-size: 11.5px; }
.app-shell.roomy .kpi             { padding: 6px 10px 0; }
.app-shell.roomy .kpi .kl         { font-size: 10.5px; }
.app-shell.roomy .kpi .kv         { font-size: 21px; }
.app-shell.roomy .kpi .ks         { font-size: 11.5px; padding-block-end: 6px; }
.app-shell.roomy .hdr .aname      { font-size: 11px; }
.app-shell.roomy .qbox,
.app-shell.roomy .tfilter select  { font-size: 13px; }
.app-shell.roomy .tcount,
.app-shell.roomy .tdense button,
.app-shell.roomy .tdense-one      { font-size: 11.5px; }
.app-shell.roomy .timeline .tlab,
.app-shell.roomy .tlticks         { font-size: 11px; }
.app-shell.roomy .scrubtip        { font-size: 11px; }
.app-shell.roomy .disc            { font-size: 11.5px; }
.app-shell.roomy .settings summary .sname { font-size: 13px; }
.app-shell.roomy .settings summary .shint { font-size: 12px; }
.app-shell.roomy .de              { font-size: 12.5px; }
.app-shell.roomy .de .dt          { font-size: 11.5px; }
.app-shell.roomy .btn.app         { font-size: 13px; padding: 7px 14px; }
.app-shell.roomy .tag.mode        { font-size: 11.5px; }
.app-shell.roomy .csk             { font-size: 13px; }
.app-shell.roomy .csw             { font-size: 12px; }
.app-shell.roomy .csc select      { font-size: 13px; padding: 4px 8px; }
.app-shell.roomy .grid.log .why   { font-size: 12.5px; }
.app-shell.roomy .demobar { padding-block: 4px; font-size: 11.5px; }
.app-shell.roomy .console { padding-block: 7px; font-size: 12px; }
.app-shell.roomy .grid td { padding-block: var(--rowpad); }

/* 1180px was set for a page of prose. A table of eight columns on a 1560px
   window was leaving 190px of ground down each side and squeezing the one
   column that holds a sentence. */
.app-shell main { max-width: 1360px; }

/* A tooltip is a gloss, not a paragraph. It was 30ch of 11.5px prose in a box
   with 7px of padding, which is an essay hanging off a column heading — big
   enough to cover the rows it is explaining. */
.app-shell .tip::after {
  max-inline-size: 26ch; padding: 4px 7px; font-size: 11px; line-height: 1.35;
  inset-block-start: calc(100% + 5px);
}

/* ==========================================================================
   White ground
   --------------------------------------------------------------------------
   The cool paper was the right call while the app only ever wore our colours.
   It stops being right the moment a customer's own logo sits in the top left:
   their mark has to look like it belongs on the page, and a tinted ground
   fights every brand that is not ours. White is the one background that takes
   somebody else's colour without arguing with it.

   Separation moves from the ground to the edges, so the border is doing work it
   was not doing before and is a step stronger. Every ink token was solved
   against the old #eceef1 and every one of them gains contrast here: the worst
   case is now --faint at 4.65 on the status tints, against 4.5 required.
   ========================================================================== */
.app-shell {
  --ground:  #ffffff;
  --surface: #ffffff;
  --row:     #f6f7f9;
  --edge:    #dde1e6;
  --hair2:   #ebeef1;
  --idle-bg: #eef0f3;
}
/* Panels and page are the same colour now, so the control strip is what
   separates the table from the summary above it. */
.app-shell .tfilter { background: var(--row); border-block-end-color: var(--edge); }
.app-shell .grid thead th { background: var(--surface); border-block-end-width: 1px; border-block-end-color: var(--edge); }
.app-shell .settings summary { background: var(--row); }
.app-shell .settings summary:hover { background: #eef1f4; }
.app-shell .settings[open] summary { background: var(--row); }
/* On a white ground a white panel is its border, so the border has to hold. */
.app-shell .kpi, .app-shell .tblwrap, .app-shell .pnl, .app-shell .settings { border-color: var(--edge); }
.app-shell .grid tbody tr.crow:hover { background: #eef2f6; }

/* ==========================================================================
   A customer's own mark
   --------------------------------------------------------------------------
   On the top tier the product steps back: their mark, their account name, and
   Orchadstrate reduced to an attribution. An agency showing this board to its
   own client is the case it is for, which is also why it is the tier where
   sixty accounts sit.
   ========================================================================== */
.cbrand.branded { display: inline-flex; align-items: center; gap: 8px; text-decoration: none; }
.cbrand .mark {
  display: grid; place-items: center; inline-size: 20px; block-size: 20px;
  border-radius: 3px; background: var(--console-ink); color: var(--console);
  font-size: 10px; font-weight: 700; letter-spacing: .02em; flex: none;
}
.cbrand .bn { font-weight: 600; letter-spacing: -.01em; }
.cbrand .poweredby {
  font-size: 9.5px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--console-dim); font-weight: 400; padding-inline-start: 2px;
}
@media (max-width: 720px) { .cbrand .poweredby { display: none; } }
/* The report is the artefact that leaves the building, so it carries the mark
   too — it is the one an agency forwards to its client. */
.repbrand { display: flex; align-items: center; gap: 9px; margin-block-end: 6px; }
.repbrand .mark {
  display: grid; place-items: center; inline-size: 22px; block-size: 22px;
  border-radius: 3px; background: var(--ink); color: #fff;
  font-size: 10.5px; font-weight: 700; flex: none;
}
.repbrand .bn { font-size: 12.5px; font-weight: 600; }

/* ==========================================================================
   The greys, solved for AAA rather than AA
   --------------------------------------------------------------------------
   The sweep said zero failures and the sweep was answering the wrong question.
   AA is 4.5:1 and it is a floor for body text at a reading size; this is 10 and
   11px type, in grey, on a screen somebody has open all day. WCAG sets no
   minimum size, so small type passes the ratio check while still being hard to
   read — which is exactly what happened, because the type got smaller in the
   same pass that moved the ground to white.

   Every secondary grey is now at 7:1 or better on all six surfaces it can
   appear on — white, the zebra row, and the four status tints — which is AAA
   for normal text, and nothing grey is under 10.5px any more.
   ========================================================================== */
.app-shell {
  --muted: #3d4653;   /* 8.13:1 worst case, was #5a6270 at 5.23 */
  --faint: #454e5c;   /* 7.16:1 worst case, was #626a76 at 4.65 */
  --idle:  #454e5c;
  --console-dim: #a3aab5;  /* 7.69:1 on the console, was #949ba6 at 6.42 */
}
.app-shell .demobar span { color: #c3cad3; }

/* Nothing grey under 10.5px, and the secondary lines that carry actual
   information — what a number is out of, what a setting does — go back up to
   11.5, which is where they can be read without leaning in. */
.app-shell .grid th,
.app-shell .kpi .kl,
.app-shell .hdr .aname,
.app-shell .timeline .tlab,
.app-shell .tlticks       { font-size: 10.5px; }
.app-shell .cbrand .poweredby { font-size: 10px; }
.app-shell .kpi .ks,
.app-shell .csw,
.app-shell .settings summary .shint,
.app-shell .grid .cs,
.app-shell .tcount,
.app-shell .de .dt,
.app-shell .disc          { font-size: 11.5px; }
.app-shell .de            { font-size: 12px; }

/* The status labels are the one thing that cannot reach AAA: orange at 7:1 is
   brown, green is bottle green, and those colours are carrying meaning. They
   hold AA — 4.8 for the orange, 5.5 and 5.7 for the green and the rust — and
   get size instead, which is the other half of legibility and the half the
   ratio check never looks at. */
.app-shell .grid .tag { font-size: 11.5px; padding-block: 2px; }
.app-shell .cbrand .poweredby { font-size: 10.5px; }
