/* ═══════════════════════════════════════════════════════════════════════════════════
   MICHELANGELO — OPERATOR PORTAL
   Implements docs/PORTAL-DESIGN.md. Read that document before changing anything here;
   every value below is decided there, with the reasoning.

   The one line: Da Vinci is a warm cream retail dashboard that glows. Michelangelo is a
   cold graphite instrument that reads out. Quieter, denser, squarer, and it never uses
   colour for decoration.

   The rules this sheet holds (§9 of the design doc — the full list is there):
     · One neutral luminance ramp + ONE accent + THREE signals. No other hue.
     · The accent marks what has been MEASURED or what is LIVE. It is never an
       affordance: not a button, not a heading, not a hover. (§8.2)
     · `--accent` (cyan) and `--sig-crit` (red) are never the same colour again.
     · Every colour is a token. No hex or rgba() outside :root.
     · No glass, no blur, no mesh, no glow, no hover lift, no entrance animation.
     · Radii are 0 / 2 / 3px. 999px survives on the switch knob and a status dot only.
     · One uppercase rule in the whole sheet. One tracking value above 0.02em.
     · tabular-nums is set on :root and never unset.
   ═══════════════════════════════════════════════════════════════════════════════════ */

/* Fonts — Geist + Geist Mono, SIL OFL 1.1, self-hosted variable woff2 (latin subset).
   52,528 B for the pair, 100–900 weights. Nothing here may point at a CDN. */
@font-face { font-family:'Geist';      src:url('/portal/fonts/geist-var.woff2') format('woff2');      font-weight:100 900; font-style:normal; font-display:swap; }
@font-face { font-family:'Geist Mono'; src:url('/portal/fonts/geist-mono-var.woff2') format('woff2'); font-weight:100 900; font-style:normal; font-display:swap; }

*, *::before, *::after { box-sizing:border-box; margin:0; padding:0; }

/* ═══ TOKENS ═══════════════════════════════════════════════════════════════════════
   DARK is the default and the identity; LIGHT is a first-class alternate. Every token
   is fully defined here in bare :root — no colour may have its only definition inside
   a media query or a [data-theme] block. Ratios are WCAG 2.x against the worst surface
   the token can legally sit on. */
:root {
  color-scheme:light;

  /* ground plane — four luminance steps, one hue */
  --ground:#F6F7F7;          /* page background, outside the panels */
  --panel:#FFFFFF;           /* cards, table body, active rail row      [brand value] */
  --panel-raised:#F0F2F2;    /* row hover, menus, drawer, popovers, toasts */
  --panel-sunken:#EBEEEE;    /* inputs, table header strip, the left rail */

  /* rules — a hairline separates, a fill layers, a shadow floats */
  --rule:#DFE3E4;            /* default hairline */
  --rule-strong:#C7CDCF;     /* section dividers, chart reference lines */
  --rule-control:#7E878A;    /* the boundary of a control — 3.31:1 on --panel-raised, the WORST
                                surface it sits on (menus, drawer, popovers, toasts). The previous
                                value quoted 3.20:1 against --panel and measured 2.94:1 on raised,
                                i.e. under the WCAG 1.4.11 minimum on every floating control. A
                                contrast note must quote the least friendly surface, not the kindest. */

  /* type */
  --text:#15181A;            /* primary                    [brand value]  15.97:1 */
  --text-2:#4C5558;          /* secondary, provisional figures            7.95:1 */
  --text-3:#5C666A;          /* labels, units, captions, empty states     4.77:1 */

  /* accent — the measurement mark. §8.2 lists the six places it may appear. */
  --accent:#0C7085;
  --accent-hi:#0A5F70;
  --accent-wash:rgba(12,112,133,0.06);   /* 6%, not 12%: at 12% muted text on a selected row falls to 4.06:1 */
  --on-accent:#FFFFFF;

  /* signals — spent only where a state must be affirmed. Fine is unmarked. */
  --sig-ok:#2A7049;
  --sig-warn:#8A5A00;
  --sig-crit:#A91E00;
  --sig-muted:#5C666A;
  --wash-ok:rgba(42,112,73,0.09);
  --wash-warn:rgba(138,90,0,0.10);
  --wash-crit:rgba(169,30,0,0.08);
  --wash-muted:rgba(92,102,106,0.09);

  /* neutral action fill — the primary button is NOT accent-coloured (§8.2) */
  --solid:#15181A;
  --on-solid:#FFFFFF;        /* 17.11:1 */

  /* floating layers */
  --scrim:rgba(21,24,26,0.32);
  --shadow-pop:0 8px 24px rgba(21,24,26,0.12);

  /* ── type scale — seven sizes, three weights, px not rem ── */
  --font-ui:'Geist', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;
  --font-mono:'Geist Mono', ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace;
  --fs-eyebrow:11px; --fs-xs:12px; --fs-sm:13px; --fs-md:15px; --fs-lg:18px; --fs-xl:26px; --fs-2xl:34px;

  /* ── spacing — 4px base, ten steps ── */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:20px;
  --s6:24px; --s7:32px; --s8:40px; --s9:48px; --s10:64px;

  /* ── radii ── */
  --r-0:0; --r-1:2px; --r-2:3px;

  /* ── shell metrics ── */
  --rail:220px; --strip:48px; --content-max:1360px; --pad-x:28px;

  /* ── motion — one duration; colour transitions only ── */
  --dur:90ms;
  --ease-drawer:cubic-bezier(0.2,0,0,1);
}

/* DARK — the graphite instrument. It was the default; the owner asked for the lighter view, so
   LIGHT is now the identity and dark is a DELIBERATE choice, not something an operating-system
   preference decides for you. That is why there is no prefers-color-scheme block any more: a
   person who set their laptop to dark last winter did not thereby choose this app's appearance,
   and the previous arrangement meant the app looked different to two people sitting side by side
   with no way to tell why. Redefinition only: no token is invented here. */
:root[data-theme="dark"] {
  color-scheme:dark;
  --ground:#0D1011; --panel:#15181A; --panel-raised:#1C2023; --panel-sunken:#090B0C;
  --rule:#2B3135; --rule-strong:#394145; --rule-control:#667276;
  --text:#F3F3E9; --text-2:#AEB6B8; --text-3:#828C90;
  --accent:#5CD8E6; --accent-hi:#8AE7F1; --accent-wash:rgba(92,216,230,0.06); --on-accent:#0D1011;
  --sig-ok:#6FBF8F; --sig-warn:#E3A155; --sig-crit:#FF6B57; --sig-muted:#828C90;
  --wash-ok:rgba(111,191,143,0.10); --wash-warn:rgba(227,161,85,0.12);
  --wash-crit:rgba(255,107,87,0.12); --wash-muted:rgba(130,140,144,0.10);
  --solid:#F3F3E9; --on-solid:#0D1011;
  --scrim:rgba(0,0,0,0.55); --shadow-pop:0 8px 24px rgba(0,0,0,0.45);
}

/* ═══ BASE ═════════════════════════════════════════════════════════════════════════ */
html { font-variant-numeric:tabular-nums; }   /* §6.4 — Geist's default figures are proportional; never unset this */
[hidden] { display:none !important; }         /* the `hidden` attribute must beat any display rule */
body {
  background:var(--ground); color:var(--text);
  font-family:var(--font-ui); font-size:var(--fs-sm); line-height:1.45;
  min-height:100vh; overflow-x:hidden; -webkit-font-smoothing:antialiased;
}
a { color:var(--accent); text-decoration:none; }        /* sanctioned accent use #6 — inline links in prose */
a:hover { text-decoration:underline; }
button, input, select, textarea { font:inherit; color:inherit; }

/* Focus ring — sanctioned accent use #2. Never remove an outline without a replacement. */
:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }

/* ── Motion foundation. Default amount of motion: none. Transitions are permitted on
   colour only; transform is permitted on the drawer, the switch knob and the
   indeterminate loading segment. Nothing animates in. ── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration:0.001ms !important; animation-iteration-count:1 !important; transition-duration:0.001ms !important; scroll-behavior:auto !important; }
}

/* ── THE ONE UPPERCASE STYLE (§6.7) — 11px mono eyebrow, the only rule in this sheet
   allowed text-transform or letter-spacing above 0.02em. If a label needs shouting to
   be found, the layout is wrong. ── */
.section-title, .kpi-label, .nav-label, .pf-menu-title, .pf-filters-label,
.settings-section-title, .drp-presets-title, .drp-day-label, .loading-status,
.topbar-app, .login-brand-sub {
  font-family:var(--font-mono); font-size:var(--fs-eyebrow); font-weight:400;
  letter-spacing:0.06em; text-transform:uppercase; color:var(--text-3); line-height:1.45;
}
/* Eyebrow-sized notes that are NOT shouted: captions, stamps, units, ids. */
.section-meta, .kpi-note, .last-sync, .pf-pager, .drp-note, .pf-vgrid th, .pf-state-card code {
  font-family:var(--font-mono); font-size:var(--fs-eyebrow); color:var(--text-3); line-height:1.45;
}

/* ═══ SHELL — rail (where am I) + strip (what am I looking at). Never mixed. ═══════ */
.pf-rail {
  position:fixed; top:0; left:0; bottom:0; width:var(--rail); z-index:60;
  display:flex; flex-direction:column;
  background:var(--panel-sunken); border-right:1px solid var(--rule);
}
.topbar-logo {
  display:flex; align-items:center; gap:6px; flex-shrink:0;
  height:var(--strip); padding:0 14px; border-bottom:1px solid var(--rule); text-decoration:none;
}
.topbar-logo:hover { text-decoration:none; }
.topbar-logo svg { height:14px; width:auto; display:block; }
.topbar-logo svg path { fill:var(--text); }
.pf-rail-nav { flex:1 1 auto; overflow-y:auto; padding:var(--s2) 0; }
/* the foot sits outside the scroller so the account menu is not clipped by it */
.pf-rail-foot { flex:0 0 auto; border-top:1px solid var(--rule); padding:var(--s1) 0; }

.pf-shell { margin-left:var(--rail); min-height:100vh; }

.pf-strip {
  position:sticky; top:0; z-index:50;
  display:flex; align-items:center; flex-wrap:wrap; gap:var(--s3);
  min-height:var(--strip); max-width:var(--content-max); margin:0 auto; padding:var(--s1) var(--pad-x);
  background:var(--ground); border-bottom:1px solid var(--rule);
}
.main { max-width:var(--content-max); margin:0 auto; padding:var(--s6) var(--pad-x) var(--s10); }
.tab-content { display:block; }

/* ═══ NAV — flat, every destination visible, no expand/collapse ═══════════════════ */
.nav-groups, .nav-sub { display:flex; flex-direction:column; }
.nav-sub:empty { display:none; }
.nav-group, .nav-sub .source-tab, .settings-link {
  display:block; width:100%; text-align:left; background:none; border:none; border-radius:0;
  height:30px; padding:0 12px 0 14px; font-size:var(--fs-sm); font-weight:400; color:var(--text-2);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:pointer;
  transition:color var(--dur) linear, background-color var(--dur) linear;
}
.nav-group:hover, .nav-sub .source-tab:hover, .settings-link:hover { background:var(--panel); color:var(--text); }
/* Active — sanctioned accent use #1. No indent shift, no icon, no transform. */
.nav-group.active, .nav-sub .source-tab.active {
  background:var(--panel); color:var(--text); font-weight:500; box-shadow:inset 2px 0 0 var(--accent);
}
/* A group is a heading, not a control: it does not route, so reaching a child is one click. */
.nav-label { display:flex; align-items:center; height:22px; padding:0 12px 0 14px; margin-top:var(--s4); }
.nav-sub .source-tab { color:var(--text-3); padding-left:26px; }
.settings-link { color:var(--text-3); }

/* ═══ STRIP CONTENTS ══════════════════════════════════════════════════════════════ */
.pf-page-head { display:flex; align-items:center; flex-wrap:wrap; gap:var(--s1) var(--s3); flex:1 1 auto; min-width:0; }
.pf-page-head h1 { font-size:var(--fs-lg); font-weight:500; color:var(--text); white-space:nowrap; }
.pf-page-head .section-meta { margin-left:var(--s3); white-space:nowrap; }
.pf-page-head .section-meta::before { content:'· '; color:var(--rule-strong); }
.pf-page-head .pf-filters { margin-left:auto; }
.topbar-right { display:flex; align-items:center; gap:var(--s2); flex:0 0 auto; }
.pf-filters { display:flex; align-items:center; gap:var(--s2); flex-wrap:wrap; }
.pf-filters-label { margin-right:var(--s1); }
.date-btn, .sync-btn, .settings-link, .last-sync, .nav-group, .nav-sub .source-tab { white-space:nowrap; }

/* date range — one segmented box, divided by hairlines. Not a capsule. */
.date-picker-wrap { position:relative; }
.date-range { display:inline-flex; border:1px solid var(--rule-control); border-radius:var(--r-2); overflow:hidden; }
.date-btn {
  height:28px; padding:0 10px; background:none; border:none; border-left:1px solid var(--rule);
  color:var(--text-2); font-size:var(--fs-xs); cursor:pointer;
  transition:color var(--dur) linear, background-color var(--dur) linear;
}
.date-btn:first-child { border-left:none; }
.date-btn:hover:not(:disabled):not([aria-disabled="true"]) { background:var(--panel-raised); color:var(--text); }
.date-btn.active { background:var(--solid); color:var(--on-solid); }
.date-btn:disabled, .date-btn[aria-disabled="true"] { color:var(--text-3); cursor:not-allowed; background:none; }

/* refresh — words, not rotation: .syncing sets disabled and the label reads "Refreshing…" */
.sync-btn {
  height:28px; padding:0 10px; background:none; border:1px solid var(--rule-control); border-radius:var(--r-2);
  color:var(--text-2); font-size:var(--fs-xs); cursor:pointer;
  transition:color var(--dur) linear, border-color var(--dur) linear;
}
.sync-btn:hover:not(:disabled) { color:var(--text); border-color:var(--text-3); }
.sync-btn:disabled { color:var(--text-3); cursor:default; }

/* ═══ MENUS (account) ═════════════════════════════════════════════════════════════ */
.pf-menu-wrap { position:relative; }
.pf-menu {
  display:none; position:absolute; top:calc(100% + 6px); right:0; min-width:240px; z-index:210;
  background:var(--panel-raised); border:1px solid var(--rule); border-radius:var(--r-2);
  box-shadow:var(--shadow-pop); padding:var(--s1) 0;
}
.pf-menu.open { display:block; }
/* the rail foot is at the bottom of the viewport, so its menu opens upward and outward */
.pf-account .pf-menu { top:auto; bottom:calc(100% + 6px); left:var(--s2); right:auto; }
.pf-menu-title { padding:var(--s2) var(--s3) var(--s1); }
.pf-menu-item {
  display:flex; align-items:center; justify-content:space-between; gap:var(--s3);
  width:100%; text-align:left; background:none; border:none; padding:6px var(--s3);
  font-size:var(--fs-sm); color:var(--text); cursor:pointer; text-decoration:none;
  transition:background-color var(--dur) linear;
}
.pf-menu-item > span:first-child { white-space:nowrap; }
.pf-menu-item:hover { background:var(--panel); text-decoration:none; }
.pf-menu-item[aria-disabled="true"] { color:var(--text-3); cursor:not-allowed; }
.pf-menu-item small { font-family:var(--font-mono); font-size:var(--fs-eyebrow); color:var(--text-3); }
.pf-menu-sep { border:none; border-top:1px solid var(--rule); margin:var(--s1) 0; }
.pf-menu-meta { padding:var(--s2) var(--s3); font-family:var(--font-mono); font-size:var(--fs-xs); color:var(--text-2); line-height:1.5; word-break:break-all; }
.pf-account .pf-owner { margin-left:var(--s1); }

/* ═══ SECTIONS + BANNERS ══════════════════════════════════════════════════════════ */
.section-header { display:flex; align-items:baseline; justify-content:space-between; gap:var(--s3); margin-bottom:var(--s4); }

/* A banner's container carries the wash and a 3px signal rule; its body copy stays --text.
   Tinted paragraphs are harder to read and the tint has already been spent. */
.pf-banner, .error-banner {
  padding:var(--s3) var(--s4); margin-bottom:var(--s6); border-radius:var(--r-0);
  border-left:3px solid var(--rule-strong); background:var(--wash-muted);
  font-size:var(--fs-sm); color:var(--text); line-height:1.5;
}
.pf-banner.ok { border-left-color:var(--sig-ok); background:var(--wash-ok); }
.pf-banner.warn { border-left-color:var(--sig-warn); background:var(--wash-warn); }
.pf-banner.critical, .error-banner { border-left-color:var(--sig-crit); background:var(--wash-crit); }

/* ═══ KPI TILES ═══════════════════════════════════════════════════════════════════ */
.kpi-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--s4); margin-bottom:var(--s7); }
/* flat card, no hover state at all — it is not interactive, and a lift implies it is */
.kpi-card { position:relative; background:var(--panel); border:1px solid var(--rule); border-radius:var(--r-2); padding:14px 16px; }
.kpi-label { margin-bottom:var(--s2); padding-right:var(--s8); }   /* clears the absolutely-positioned delta */
.kpi-value { font-size:var(--fs-xl); font-weight:500; line-height:1; letter-spacing:-0.01em; color:var(--text); }
.kpi-change { margin-top:var(--s2); font-family:var(--font-mono); font-size:var(--fs-xs); color:var(--text-3); }
.kpi-change.up { color:var(--sig-ok); }
.kpi-change.down { color:var(--sig-crit); }
.kpi-change.neutral { color:var(--text-3); }
/* the delta loses its pill: plain mono text, colour only */
.kpi-delta { position:absolute; top:14px; right:16px; font-family:var(--font-mono); font-size:var(--fs-xs); line-height:1; white-space:nowrap; color:var(--text-3); }
.kpi-delta.good { color:var(--sig-ok); }
.kpi-delta.bad { color:var(--sig-crit); }
.kpi-delta.flat { color:var(--text-3); }
.kpi-spark-wrap { margin-top:var(--s2); }
.kpi-spark { display:block; width:100%; height:28px; }
.kpi-spark path { fill:none; stroke:var(--accent); stroke-width:1.25; }   /* sanctioned accent use #4 — the data trace */
.kpi-spark .area { display:none; }        /* a translucent wedge is decoration; the line is the measurement */
.kpi-note { margin-top:var(--s1); }

/* ═══ CARDS ═══════════════════════════════════════════════════════════════════════ */
.two-col { display:grid; grid-template-columns:1fr 1fr; gap:var(--s4); margin-bottom:var(--s7); }
.three-col { display:grid; grid-template-columns:1fr 1fr 1fr; gap:var(--s4); margin-bottom:var(--s7); }
/* the border is the bezel: --panel on --ground is only a 1.15:1 step, so it is not optional */
.chart-card { position:relative; background:var(--panel); border:1px solid var(--rule); border-radius:var(--r-2); padding:var(--s4); overflow:visible; }
.chart-card h3 { font-size:var(--fs-md); font-weight:500; color:var(--text); margin-bottom:var(--s4); }
.chart-wrap { position:relative; height:160px; }

/* metric rows inside a card */
.metric-row { display:flex; align-items:center; justify-content:space-between; gap:var(--s3); min-height:30px; padding:var(--s1) 0; border-bottom:1px solid var(--rule); }
.metric-row:last-child { border-bottom:none; }
.metric-label { font-size:var(--fs-sm); color:var(--text-2); }
.metric-val { font-family:var(--font-mono); font-size:var(--fs-sm); color:var(--text); text-align:right; }
/* home.js check lists / next steps (previously emitted with no CSS at all) */
.pf-checks, .pf-next-steps { margin-top:var(--s2); }
.pf-check-msg { font-size:var(--fs-xs); color:var(--text-2); text-align:left; max-width:60ch; }
.pf-warnings { margin-top:var(--s3); }
.pf-warnings > summary { font-size:var(--fs-xs); color:var(--text-3); cursor:pointer; }

/* ═══ TABLES — the table is the product ═══════════════════════════════════════════ */
.table-card { background:var(--panel); border:1px solid var(--rule); border-radius:var(--r-2); overflow:hidden; margin-bottom:var(--s7); }
.table-head { display:flex; align-items:center; justify-content:space-between; gap:var(--s3); flex-wrap:wrap; min-height:44px; padding:var(--s2) var(--s3); border-bottom:1px solid var(--rule); }
.table-head h3 { font-size:var(--fs-md); font-weight:500; color:var(--text); }
.table-scroll { overflow-x:auto; -webkit-overflow-scrolling:touch; }
table { width:100%; border-collapse:collapse; }
th {
  position:sticky; top:0; z-index:1;                 /* engages when the card itself is the scrollport */
  height:30px; padding:0 12px; text-align:left; white-space:nowrap;
  background:var(--panel-sunken); border-bottom:1px solid var(--rule-strong);
  font-size:var(--fs-xs); font-weight:500; color:var(--text-2);
}
td {
  height:34px; padding:0 12px; border-bottom:1px solid var(--rule);
  font-size:var(--fs-xs); color:var(--text-2);
  transition:background-color var(--dur) linear;
}
tr:last-child td { border-bottom:none; }
/* No zebra: the hairlines already delimit rows, and doing both halves the contrast of
   every other row. Hover is a fill and nothing else. */
tr:hover td { background:var(--panel-raised); }
/* Selection — sanctioned accent use #3. The cursor happening to be somewhere is not selection. */
tr.selected td { background:var(--accent-wash); }
tr.selected td:first-child { box-shadow:inset 2px 0 0 var(--accent); }
th.num, td.num { text-align:right; width:1%; white-space:nowrap; }
td.num { font-family:var(--font-mono); color:var(--text); }
td.td-main { font-family:var(--font-ui); font-weight:500; color:var(--text); }
th.sortable { cursor:pointer; user-select:none; transition:color var(--dur) linear; }
th.sortable:hover { color:var(--text); }
th.sortable.sorted { color:var(--text); font-weight:600; }
th.sortable[data-dir="asc"]::after  { content:' ▲'; font-size:var(--fs-eyebrow); color:var(--accent); }
th.sortable[data-dir="desc"]::after { content:' ▼'; font-size:var(--fs-eyebrow); color:var(--accent); }
td details > summary { cursor:pointer; color:var(--text-3); }
td details pre { font-family:var(--font-mono); font-size:var(--fs-eyebrow); white-space:pre-wrap; margin-top:var(--s1); color:var(--text-2); }
.empty { padding:var(--s9) var(--s4); text-align:center; font-size:var(--fs-sm); color:var(--text-3); }
.pf-pager { display:flex; align-items:center; justify-content:flex-end; gap:var(--s2); min-height:36px; padding:0 var(--s3); border-top:1px solid var(--rule); }

/* ═══ GRADE CHART (validate grid / heatmap) ═══════════════════════════════════════
   A grade rule is a table of increments read across: equal-width cells, figures on a
   shared column axis, row and column heads lighter than the cells. */
.pf-grid-wrap { overflow-x:auto; }
.pf-vgrid { width:auto; border-collapse:separate; border-spacing:2px; font-family:var(--font-mono); font-size:var(--fs-xs); }
.pf-vgrid th { position:static; height:auto; padding:2px 6px; text-align:right; background:none; border:none; font-weight:400; }
.pf-vgrid td { height:auto; padding:3px 6px; text-align:center; border:none; border-radius:var(--r-1); color:var(--text-2); }
.pf-vgrid tr:hover td { background:none; }
.pf-vgrid td.ok { background:var(--wash-ok); color:var(--sig-ok); }
/* an abstention is a state, not a warning: no fill, a dotted boundary */
.pf-vgrid td.abstain { background:none; outline:1px dotted var(--rule-control); outline-offset:-1px; color:var(--text-3); }
.pf-vgrid td.no_size { background:var(--wash-muted); color:var(--text-3); }
.pf-vgrid td.error { background:var(--wash-crit); color:var(--sig-crit); }
.pf-vgrid td.violation { outline:1px solid var(--sig-crit); outline-offset:-1px; }

/* contrast grid — the Styles page's own validator (it grades the widget's tokens) */
.pf-contrast { display:grid; grid-template-columns:repeat(auto-fill,minmax(200px,1fr)); gap:var(--s2); }
.pf-contrast .pair { display:flex; align-items:center; justify-content:space-between; gap:var(--s2); padding:var(--s2) var(--s3); border:1px solid var(--rule); border-radius:var(--r-2); font-family:var(--font-mono); font-size:var(--fs-xs); }
.pf-contrast .pair.pass { border-color:var(--sig-ok); }
.pf-contrast .pair.fail { border-color:var(--sig-crit); }

/* ═══ ATOMS — badges, tags, chips, hints ══════════════════════════════════════════
   Sentence case, no tracking, 2px radius. Colour never carries meaning alone: every
   signal colour arrives with a word. */
.badge { display:inline-block; padding:1px 5px; border-radius:var(--r-1); font-family:var(--font-mono); font-size:var(--fs-eyebrow); font-weight:500; line-height:1.5; white-space:nowrap; background:var(--wash-muted); color:var(--text-3); }
.badge-green { background:var(--wash-ok); color:var(--sig-ok); }
.badge-red { background:var(--wash-crit); color:var(--sig-crit); }
.badge-blue, .badge-grey { background:var(--wash-muted); color:var(--text-3); }
.badge-gold, .badge-amber { background:var(--wash-warn); color:var(--sig-warn); }
/* coverage / question-set states */
.pf-state-enabled, .pf-state-published { background:var(--wash-ok); color:var(--sig-ok); }
.pf-state-keyed_not_enabled, .pf-state-draft { background:var(--wash-warn); color:var(--sig-warn); }
.pf-state-gap { background:var(--wash-crit); color:var(--sig-crit); }
.pf-state-new_arrival { background:var(--wash-muted); color:var(--text-2); }   /* a new arrival is not an alert */
.pf-state-one_size, .pf-state-excluded, .pf-state-superseded { background:var(--wash-muted); color:var(--text-3); }

/* card-corner tag (.pf-tag; .crm-badge kept as an alias while pages still emit it) */
.pf-tag, .crm-badge {
  position:absolute; top:12px; right:12px; display:inline-block; padding:1px 5px;
  border:1px solid transparent; border-radius:var(--r-1);
  font-family:var(--font-mono); font-size:var(--fs-eyebrow); line-height:1.5; white-space:nowrap;
  background:var(--wash-muted); color:var(--text-3);
}
/* "live" = data that updates continuously — sanctioned accent use #5 */
.pf-tag.live, .crm-badge.live { color:var(--accent); background:var(--accent-wash); border-color:var(--accent); }
.pf-tag.cohort, .crm-badge.cohort { color:var(--text-3); background:var(--wash-muted); }
.pf-tag.amber, .crm-badge.amber { color:var(--sig-warn); background:var(--wash-warn); }

/* inline tags: returns window, owner. Same geometry, no absolute position. */
.pf-returns-badge, .pf-owner {
  display:inline-block; padding:1px 5px; border-radius:var(--r-1);
  font-family:var(--font-mono); font-size:var(--fs-eyebrow); line-height:1.5; white-space:nowrap;
}
.pf-returns-badge { background:var(--wash-warn); color:var(--sig-warn); }
.pf-owner { background:var(--wash-muted); color:var(--text-3); margin-left:var(--s1); }

/* chip. NOTE: .crm-chip is a live alias, not dead weight — portal/pages/config.js sets
   background and color INLINE on it to render the Styles gallery's colour swatches, so
   neither property may be !important here. */
.pf-chip, .crm-chip {
  display:inline-block; padding:1px 5px; border-radius:var(--r-1);
  font-family:var(--font-mono); font-size:var(--fs-eyebrow); line-height:1.5;
  background:var(--wash-muted); color:var(--text-2);
}

/* (i) hint — square, because nothing here is a pill */
.pf-hint, .crm-info {
  position:relative; display:inline-flex; align-items:center; justify-content:center;
  width:13px; height:13px; margin-left:var(--s1); vertical-align:middle;
  border:1px solid var(--rule-control); border-radius:var(--r-1);
  font-family:var(--font-mono); font-size:9px; font-style:normal; font-weight:400; line-height:1;
  color:var(--text-3); cursor:help; text-transform:none;
  transition:color var(--dur) linear, border-color var(--dur) linear;
}
.pf-hint:hover, .crm-info:hover { color:var(--text); border-color:var(--text-3); }
.pf-hint-bub, .crm-info-bub {
  display:none; position:absolute; left:-4px; bottom:calc(100% + 8px); width:240px; z-index:20;
  background:var(--panel-raised); border:1px solid var(--rule); border-radius:var(--r-2);
  box-shadow:var(--shadow-pop); padding:var(--s2) var(--s3);
  font-family:var(--font-ui); font-size:var(--fs-xs); font-weight:400; line-height:1.5;
  color:var(--text-2); letter-spacing:0; text-transform:none; white-space:normal;
}
.pf-hint:hover .pf-hint-bub, .crm-info:hover .crm-info-bub { display:block; }

/* ═══ THE FIVE STATES OF A NUMBER (§8.1) ══════════════════════════════════════════
   From the dimension callout: a value, its tolerance, its notes — annotation drawn
   lighter than the thing annotated. Measured carries no mark. Absent is an em dash,
   never 0. Any figure downstream of a value a human typed into Settings is .is-modelled. */
.is-modelled { border-bottom:1px dotted var(--rule-control); width:fit-content; }   /* the mark hugs the figure, not the cell */
.is-modelled::before { content:'≈'; color:var(--text-3); margin-right:0.15em; }
.is-open { color:var(--text-2); }                       /* period not closed — one notch dimmer */
.is-abstain { padding:0 3px; border:1px dotted var(--rule-control); font-family:var(--font-mono); color:var(--text-3); }

/* ═══ BUTTONS ═════════════════════════════════════════════════════════════════════ */
.btn-primary, .btn-secondary, .btn-danger {
  display:inline-flex; align-items:center; justify-content:center; gap:var(--s2);
  height:30px; padding:0 12px; border:1px solid transparent; border-radius:var(--r-2);
  font-family:var(--font-ui); font-size:var(--fs-sm); font-weight:500; line-height:1;
  white-space:nowrap; cursor:pointer; background:none;
  transition:color var(--dur) linear, background-color var(--dur) linear, border-color var(--dur) linear;
}
/* The primary button is a neutral high-contrast fill, NOT the accent. If the accent were
   the Save button it would stop meaning "measured" the first time anyone saw it. */
.btn-primary { background:var(--solid); color:var(--on-solid); }
.btn-primary:hover:not(:disabled) { background:var(--text-2); }
.btn-primary:disabled { opacity:0.5; cursor:default; }
.btn-secondary { border-color:var(--rule-control); color:var(--text-2); }
.btn-secondary:hover:not(:disabled) { border-color:var(--text-3); color:var(--text); }
.btn-secondary:disabled { opacity:0.45; cursor:not-allowed; }
.btn-danger { border-color:var(--sig-crit); color:var(--sig-crit); }
.btn-danger:hover:not(:disabled) { background:var(--wash-crit); }
.btn-danger:disabled { opacity:0.45; cursor:not-allowed; }
/* the destructive action is filled exactly once — at the moment of commitment */
.pf-modal-actions .btn-danger { background:var(--sig-crit); color:var(--ground); }
.pf-modal-actions .btn-danger:hover:not(:disabled) { background:var(--sig-crit); opacity:0.88; }

/* filter toggle — no longer a pill */
.pf-pill {
  height:24px; padding:0 8px; background:none; border:1px solid var(--rule-control); border-radius:var(--r-2);
  font-family:var(--font-mono); font-size:var(--fs-xs); color:var(--text-2); white-space:nowrap; cursor:pointer;
  transition:color var(--dur) linear, background-color var(--dur) linear, border-color var(--dur) linear;
}
.pf-pill:hover:not(:disabled) { color:var(--text); border-color:var(--text-3); }
.pf-pill.active { background:var(--solid); color:var(--on-solid); border-color:var(--solid); }
.pf-pill:disabled { opacity:0.45; cursor:not-allowed; }

/* switch — the knob is one of the two sanctioned 999px uses, and one of the two
   elements permitted to transform (it is an object that physically moves) */
.pf-switch { position:relative; width:30px; height:16px; border-radius:var(--r-1); background:var(--rule-control); border:none; cursor:pointer; vertical-align:middle; transition:background-color var(--dur) linear; }
.pf-switch::after { content:''; position:absolute; top:2px; left:2px; width:12px; height:12px; border-radius:999px; background:var(--ground); transition:transform 120ms linear; }
.pf-switch[aria-checked="true"] { background:var(--accent); }
.pf-switch[aria-checked="true"]::after { transform:translateX(14px); }
.pf-switch:disabled { opacity:0.45; cursor:not-allowed; }

/* ═══ FORMS ═══════════════════════════════════════════════════════════════════════ */
.settings-section-title { margin:0 0 var(--s4); padding-bottom:var(--s2); border-bottom:1px solid var(--rule); }
.settings-field { margin-bottom:var(--s4); }
.settings-field label { display:block; margin-bottom:var(--s1); font-size:var(--fs-xs); font-weight:500; color:var(--text-2); }
.settings-field input, .settings-field select, .settings-field textarea {
  width:100%; height:30px; padding:0 10px; background:var(--panel-sunken);
  border:1px solid var(--rule-control); border-radius:var(--r-2);
  font-family:var(--font-mono); font-size:var(--fs-sm); color:var(--text); outline:none;
  transition:border-color var(--dur) linear;
}
.settings-field textarea { height:auto; min-height:120px; padding:var(--s2) 10px; line-height:1.5; resize:vertical; }
.settings-field input:focus, .settings-field select:focus, .settings-field textarea:focus { border-color:var(--accent); }
.settings-field input::placeholder, .settings-field textarea::placeholder { color:var(--text-3); }
.settings-field .invalid { border-color:var(--sig-crit); }
.field-hint { display:block; margin-top:var(--s1); font-size:var(--fs-xs); color:var(--text-3); line-height:1.45; }
.field-error { margin-top:var(--s1); font-size:var(--fs-xs); color:var(--sig-crit); }
.settings-divider { border:none; border-top:1px solid var(--rule); margin:var(--s6) 0; }

/* ═══ DRAWER — one of the two elements permitted to transform ═════════════════════ */
.settings-backdrop { position:fixed; inset:0; background:var(--scrim); z-index:200; display:none; }
.settings-backdrop.open { display:block; }
.settings-drawer {
  position:fixed; top:0; right:0; bottom:0; width:520px; max-width:100vw; z-index:201;
  display:flex; flex-direction:column; background:var(--panel);
  border-left:1px solid var(--rule); border-radius:var(--r-0); box-shadow:var(--shadow-pop);
  transform:translateX(100%); transition:transform 180ms var(--ease-drawer);
}
.settings-drawer.open { transform:translateX(0); }
.settings-drawer-head { display:flex; align-items:center; justify-content:space-between; gap:var(--s3); padding:var(--s4) var(--s5); border-bottom:1px solid var(--rule); }
.settings-drawer-title { font-size:var(--fs-md); font-weight:500; color:var(--text); }
.settings-close { background:none; border:none; padding:2px var(--s2); font-size:var(--fs-md); line-height:1; color:var(--text-3); cursor:pointer; transition:color var(--dur) linear; }
.settings-close:hover { color:var(--text); }
.settings-drawer-body { flex:1; overflow-y:auto; padding:var(--s5); }
.settings-drawer-foot { display:flex; gap:var(--s2); padding:var(--s4) var(--s5); border-top:1px solid var(--rule); }
.settings-drawer-foot:empty { display:none; }
.settings-drawer-foot .btn-primary { flex:1; }

/* ═══ DATE PICKER ═════════════════════════════════════════════════════════════════ */
.date-picker-dropdown {
  display:none; position:absolute; top:calc(100% + 6px); right:0; z-index:200; flex-direction:row; overflow:hidden;
  background:var(--panel-raised); border:1px solid var(--rule); border-radius:var(--r-2); box-shadow:var(--shadow-pop);
}
.date-picker-dropdown.open { display:flex; }
.drp-presets { display:flex; flex-direction:column; width:148px; flex-shrink:0; padding:var(--s2) 0; background:var(--panel-sunken); border-right:1px solid var(--rule); }
.drp-presets-title { padding:var(--s1) var(--s3) var(--s2); border-bottom:1px solid var(--rule); margin-bottom:var(--s1); }
.drp-preset-btn { width:100%; text-align:left; height:28px; padding:0 var(--s3); background:none; border:none; font-size:var(--fs-sm); color:var(--text-2); white-space:nowrap; cursor:pointer; transition:color var(--dur) linear, background-color var(--dur) linear; }
.drp-preset-btn:hover:not(:disabled) { background:var(--panel-raised); color:var(--text); }
.drp-preset-btn.active { background:var(--solid); color:var(--on-solid); }
.drp-preset-btn:disabled { color:var(--text-3); cursor:not-allowed; background:none; }
.drp-cal-area { display:flex; flex-direction:column; gap:var(--s3); padding:var(--s4); }
.drp-months { display:flex; gap:var(--s6); }
.drp-month { width:210px; }
.drp-month-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--s2); }
.drp-month-title { flex:1; text-align:center; font-size:var(--fs-sm); font-weight:500; color:var(--text); }
.drp-nav-btn { background:none; border:none; padding:0 var(--s2); font-size:var(--fs-md); line-height:1; color:var(--text-3); cursor:pointer; transition:color var(--dur) linear; }
.drp-nav-btn:hover { color:var(--text); }
.drp-nav-btn[hidden] { visibility:hidden; display:inline-block !important; }
.drp-grid { display:grid; grid-template-columns:repeat(7,1fr); gap:1px; }
.drp-day-label { text-align:center; padding:var(--s1) 0; }
.drp-day { position:relative; width:26px; height:26px; margin:0 auto; display:flex; align-items:center; justify-content:center; border-radius:var(--r-1); font-family:var(--font-mono); font-size:var(--fs-xs); color:var(--text); cursor:pointer; user-select:none; transition:background-color var(--dur) linear, color var(--dur) linear; }
.drp-day:hover:not(.disabled):not(.range-start):not(.range-end) { background:var(--panel); }
.drp-day.other-month { color:var(--text-3); }
.drp-day.in-range, .drp-day.hover-range { background:var(--accent-wash); border-radius:var(--r-0); }
.drp-day.range-start, .drp-day.range-end { background:var(--accent); color:var(--on-accent); }
/* the "today" dot — the second and last sanctioned 999px use */
.drp-day.today::after { content:''; position:absolute; bottom:2px; left:50%; transform:translateX(-50%); width:3px; height:3px; border-radius:999px; background:var(--accent); }
.drp-day.disabled { color:var(--text-3); opacity:0.4; pointer-events:none; }
.drp-footer { display:flex; align-items:center; justify-content:space-between; gap:var(--s3); padding-top:var(--s2); border-top:1px solid var(--rule); font-family:var(--font-mono); font-size:var(--fs-xs); color:var(--text-2); }
.drp-footer-actions { display:flex; gap:var(--s2); }
.drp-month-select { display:flex; align-items:center; gap:var(--s2); font-family:var(--font-mono); font-size:var(--fs-xs); color:var(--text-2); }
.drp-month-select select { height:28px; padding:0 var(--s2); background:var(--panel-sunken); border:1px solid var(--rule-control); border-radius:var(--r-2); font-family:var(--font-mono); font-size:var(--fs-xs); color:var(--text); }
.drp-note { max-width:420px; line-height:1.45; }

/* The sandbox's standing explanations, folded away. A disclosure rather than a
   deletion: the text is still the record of what the frame can and cannot show,
   it just no longer stands between the operator and the preview. */
.pf-sandbox-about { margin-top:var(--s2); border-top:1px solid var(--rule); padding-top:var(--s2); }
.pf-sandbox-about > summary {
  font-family:var(--font-mono); font-size:var(--fs-eyebrow); letter-spacing:0.06em;
  text-transform:uppercase; color:var(--text-3); cursor:pointer; list-style:none;
}
.pf-sandbox-about > summary::-webkit-details-marker { display:none; }
.pf-sandbox-about > summary::before { content:'+ '; }
.pf-sandbox-about[open] > summary::before { content:'\2212 '; }
.pf-sandbox-about > summary:hover { color:var(--text-2); }
.pf-sandbox-about > .kpi-note { margin-top:var(--s2); }

/* ═══ TOASTS / MODAL / STATE CARDS ════════════════════════════════════════════════ */
.pf-toasts { position:fixed; right:var(--s5); bottom:var(--s5); z-index:400; display:flex; flex-direction:column; gap:var(--s2); max-width:min(420px, calc(100vw - 40px)); }
.pf-toast { background:var(--panel-raised); border:1px solid var(--rule); border-left:3px solid var(--rule-strong); border-radius:var(--r-2); box-shadow:var(--shadow-pop); padding:var(--s2) var(--s3); font-size:var(--fs-sm); color:var(--text); line-height:1.45; }
.pf-toast.ok { border-left-color:var(--sig-ok); }
.pf-toast.warn { border-left-color:var(--sig-warn); }
.pf-toast.critical, .pf-toast.error { border-left-color:var(--sig-crit); }

.pf-modal-backdrop { position:fixed; inset:0; z-index:300; display:flex; align-items:center; justify-content:center; padding:var(--s4); background:var(--scrim); }
.pf-modal { width:100%; max-width:420px; padding:var(--s6); background:var(--panel); border:1px solid var(--rule); border-radius:var(--r-2); box-shadow:var(--shadow-pop); }
.pf-modal p { font-size:var(--fs-sm); color:var(--text); line-height:1.55; margin-bottom:var(--s6); white-space:pre-line; }
.pf-modal-actions { display:flex; gap:var(--s2); justify-content:flex-end; }

.pf-state-card { max-width:520px; margin:var(--s7) auto; padding:var(--s7) var(--s6); background:var(--panel); border:1px solid var(--rule); border-radius:var(--r-2); text-align:center; }
.pf-state-card h2 { font-size:var(--fs-md); font-weight:500; color:var(--text); margin-bottom:var(--s2); }
.pf-state-card p { font-size:var(--fs-sm); color:var(--text-2); line-height:1.55; }
.pf-state-actions { display:flex; gap:var(--s2); justify-content:center; flex-wrap:wrap; margin-top:var(--s4); }

/* ═══ LOADING — the instrument does not display a value it has not measured, and that
   includes progress. An indeterminate segment at a constant rate; no percentage. ═══ */
.pf-loading { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--s3); padding:var(--s9) var(--s4); }
.loading-bar-wrap { position:relative; width:240px; max-width:100%; height:2px; background:var(--rule); overflow:hidden; }
.loading-bar { position:absolute; top:0; left:0; height:100%; width:33%; background:var(--accent); animation:pfScan 1.1s linear infinite; }
@keyframes pfScan { from { transform:translateX(-100%); } to { transform:translateX(300%); } }
@media (prefers-reduced-motion: reduce) { .loading-bar { animation:none; width:100%; transform:none; } }
.loading-status { text-align:center; }

/* ═══ SIGN-IN ═════════════════════════════════════════════════════════════════════ */
.pf-signin { position:fixed; inset:0; z-index:9999; display:flex; background:var(--ground); }
.login-split { position:absolute; inset:0; display:flex; }
.login-brand { flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--s4); padding:var(--s10); }
.login-brand-mark { width:180px; max-width:60%; }
.login-brand-mark path { fill:var(--text); }
.login-form-panel { width:420px; display:flex; flex-direction:column; justify-content:center; padding:var(--s10) var(--s8); background:var(--panel); border-left:1px solid var(--rule); }
.login-form-inner { width:100%; }
.login-title { font-size:var(--fs-lg); font-weight:500; color:var(--text); margin-bottom:var(--s2); }
.login-sub { font-size:var(--fs-sm); color:var(--text-2); line-height:1.55; margin-bottom:var(--s7); }
.login-reason { display:none; margin-bottom:var(--s4); padding:var(--s3) var(--s4); background:var(--wash-crit); border-left:3px solid var(--sig-crit); font-size:var(--fs-sm); color:var(--text); line-height:1.5; }
.login-reason.show { display:block; }
.login-google { display:flex; align-items:center; justify-content:center; gap:var(--s2); width:100%; height:36px; background:var(--solid); color:var(--on-solid); border:none; border-radius:var(--r-2); font-size:var(--fs-sm); font-weight:500; cursor:pointer; text-decoration:none; transition:background-color var(--dur) linear; }
.login-google:hover { background:var(--text-2); text-decoration:none; }
.login-google svg { width:16px; height:16px; flex-shrink:0; }
.login-foot { margin-top:var(--s8); font-family:var(--font-mono); font-size:var(--fs-eyebrow); color:var(--text-3); line-height:1.5; }

/* ═══ BREAKPOINTS — three, not five: 1240 / 900 / 640 ═════════════════════════════ */
@media (max-width:1239px) {
  .three-col { grid-template-columns:1fr 1fr; }
}
@media (max-width:899px) {
  /* the rail becomes a top bar; every destination stays visible, wrapped */
  .pf-rail { position:static; width:auto; flex-direction:row; flex-wrap:wrap; align-items:center; border-right:none; border-bottom:1px solid var(--rule); }
  .topbar-logo { border-bottom:none; }
  .pf-rail-nav { flex-basis:100%; order:3; overflow:visible; padding:0 var(--s2) var(--s2); }
  .pf-rail-foot { margin-left:auto; border-top:none; padding:0 var(--s2); }
  .pf-rail-foot .settings-link { width:auto; padding:0 var(--s2); }
  .pf-account .pf-menu { top:calc(100% + 6px); bottom:auto; left:auto; right:0; }
  .nav-groups, .nav-sub { flex-direction:row; flex-wrap:wrap; }
  .nav-group, .nav-sub .source-tab { width:auto; padding:0 10px; }
  .nav-label { height:30px; margin-top:0; padding:0 var(--s2) 0 0; }
  .pf-shell { margin-left:0; }
  .kpi-grid { grid-template-columns:repeat(2,1fr); }
  .two-col, .three-col { grid-template-columns:1fr; }
  .settings-drawer { width:100vw; }
}
@media (max-width:639px) {
  :root { --pad-x:16px; }
  .pf-strip { gap:var(--s2); padding:var(--s2) var(--pad-x); }
  .pf-page-head { flex-wrap:wrap; }
  .pf-page-head .pf-filters { margin-left:0; }
  .topbar-right { width:100%; justify-content:flex-end; flex-wrap:wrap; }
  .last-sync { display:none; }
  /* THE PRESET GROUP IS 404px WIDE AND THE VIEWPORT IS 375. It has overflow:hidden and the page
     has no horizontal scroll, so "Month to Date" rendered as "to Date" with its left half off
     screen and unclickable. Wrapping is right rather than scrolling: five presets over two rows
     is readable, and a horizontal scroller inside a vertical page is a thing people do not find. */
  .date-range { flex-wrap:wrap; overflow:visible; border-radius:var(--r-2); }
  .chart-wrap { height:140px; }
  .table-head { padding:var(--s2); }
  th, td { padding:0 var(--s2); }
  .date-picker-dropdown { position:fixed; top:auto; right:0; bottom:0; left:0; flex-direction:column; max-height:85vh; overflow-y:auto; border-radius:var(--r-0); }
  .drp-presets { width:100%; flex-direction:row; flex-wrap:wrap; gap:var(--s1); padding:var(--s2); border-right:none; border-bottom:1px solid var(--rule); }
  .drp-presets-title { display:none; }
  .drp-preset-btn { width:auto; padding:0 var(--s2); }
  .drp-months { flex-direction:column; gap:var(--s4); }
  .drp-month { width:100%; }
  .login-split { flex-direction:column; }
  .login-brand { flex:0 0 auto; padding:var(--s8) var(--s4) var(--s4); }
  .login-brand-mark { width:140px; }
  .login-form-panel { width:100%; flex:1 1 auto; padding:var(--s6) var(--s4); border-left:none; border-top:1px solid var(--rule); justify-content:flex-start; }
}
