/* ops-dashboard.css
   ORAVANA console, ONE visual grammar (see DESIGN-NOTES.md, Law 3).
   Consumes the canonical ORA token stack (tokens.base → tokens.teglo.light
   → tokens.ceremonial; vendored from ora-core DesignSystem, v1.0.1 palette
   lock). No raw values where a token scale exists: colours are --color-*,
   spacing is the 4px --space-* grid, radii are --radius-md/lg/pill, width
   is --container-max, motion is --duration-* on --ease-*. (Note: never
   write the sequence star-slash inside this comment — it closes it; that
   has shipped broken CSS twice before.) The only literal px left are
   sub-8px glyph optics (chip dot, glyph boxes, bar/pin sizes) below the
   spacing grid's granularity.

   TYPE — exactly THREE sizes (JOB 3, 2026-08-18): --type-display,
   --type-body, --type-meta, declared in css/console-shell.css as aliases
   of the locked scale. Every font-size in this file is one of the three.

   One card anatomy: eyebrow (meta) · value (display) · anchor (meta) for
   stat cards; status chip · claim · evidence · one action for check rows.
   Status is the semantic quartet --color-status-danger (act now) / -warn
   (watch) / -muted (unknown or intentionally quiet) / -ok (verified live,
   only when the fact is held). Numbers are tabular.

   Rebuilt 2026-08-18 (ORAVANA masonry redesign; see
   the 2026-08-18 console dispatch for the fold map and the
   deleted one-off styles). */

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--color-bg-base);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--type-body);
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
}

.ops-main { max-width: var(--container-max); margin: 0 auto; padding: var(--space-md) var(--space-lg) var(--space-2xl); }

/* text utilities — tone only, never a fourth size */
.t-2nd { color: var(--color-text-secondary); font-size: var(--type-meta); }
.t-num { font-variant-numeric: tabular-nums; text-align: right; }
.t-danger { color: var(--color-status-danger); }

/* ── status chips — the ONE vocabulary: LIVE · DOWN · STALE · EXPECTED ·
      the dash. Green only when the fact is held; grey is unknown/quiet,
      never health. ─────────────────────────────────────────────────────── */
.chip {
  display: inline-flex; align-items: center; gap: 6px; /* dot-to-word optics */ flex: none;
  font-size: var(--type-meta); font-weight: var(--fw-bold); letter-spacing: var(--ls-wide);
  text-transform: uppercase; padding: var(--space-3xs) var(--space-xs); border-radius: var(--radius-md);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.chip::before { content: ""; width: 7px; height: 7px; border-radius: var(--radius-circle); background: currentColor; }
.chip--live     { color: var(--color-status-ok);     background: var(--ok-bg); }
.chip--down     { color: var(--color-status-danger); background: var(--danger-bg); }
.chip--stale    { color: var(--color-status-warn);   background: var(--warn-bg); }
.chip--expected { color: var(--color-text-secondary); background: var(--color-bg-glass); }
.chip--noprobe  { color: var(--color-text-secondary); background: var(--color-bg-glass); }
/* IDLE joins the not-an-alarm group rather than the warn ramp: the check is late but
   its declared traffic witness proved nothing was attempted, so nothing was lost. It
   is deliberately given the SAME muted treatment as EXPECTED and not a colour of its
   own -- per the rule this sheet's dot removal was argued from, the word carries the
   identity and colour never carries it alone. EXPECTED is a human declaring the
   silence; IDLE is the platform measuring it; the chips read differently because they
   say different words. */
.chip--idle     { color: var(--color-text-secondary); background: var(--color-bg-glass); }
.chip--noprobe::before, .chip--expected::before, .chip--idle::before { background: var(--color-status-muted); }

/* ── notification pill — what the RAIL did, beside what the CHECK found. Two different
      facts, so two different shapes: the chip is a status, this is an action taken.
      It must never compete with the chip, hence no border and a lighter weight. */
.npill {
  display: inline-block; font-size: var(--type-meta); font-weight: var(--fw-bold);
  letter-spacing: var(--ls-wide); padding: 1px var(--space-2xs); border-radius: var(--radius-pill);
  white-space: nowrap; cursor: help;
}
.npill--mail   { color: var(--color-status-warn);    background: var(--warn-bg); }
.npill--digest { color: var(--color-text-secondary); background: var(--color-bg-glass); }
.npill--quiet  { color: var(--color-text-secondary); background: transparent; }
.npill--test   { color: var(--color-text-tertiary);  background: var(--color-bg-glass); }
/* Test-traffic rows are dimmed, never hidden: they are on the board on purpose. */
.row--test > td { opacity: .62; }

/* ── the "of one kind" bulk control, inline with the hero actions. */
.bulk-type { display: inline-flex; align-items: center; gap: var(--space-2xs); flex-wrap: wrap; }
.bulk-type select {
  font: inherit; font-size: var(--type-meta); color: var(--color-text);
  background: var(--color-bg-surface); border: 1px solid var(--color-border-default);
  border-radius: var(--radius-md); padding: var(--space-3xs) var(--space-2xs); max-width: 22ch;
}

/* ── info glyph — explains the TERM next to it, never repeats the sentence. */
.i {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 15px; height: 15px; border-radius: var(--radius-circle); margin-left: var(--space-2xs);
  font-size: var(--type-meta); font-style: normal; font-weight: var(--fw-semibold); line-height: 1;
  color: var(--color-text-tertiary); border: 1px solid var(--color-border-default);
  cursor: help; user-select: none; vertical-align: 1px;
}
.i:hover { color: var(--color-text-secondary); border-color: var(--color-border-strong); }

/* ── Layer 1: hero — greeting, claim, one action row ────────────────────── */
.hero { padding: var(--space-lg) 0 var(--space-md); }
.hero--page { padding-bottom: var(--space-sm); }
.hero__hi { margin: 0 0 var(--space-3xs); font-size: var(--type-meta); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--color-text-tertiary); }
.hero__claim {
  font-family: var(--font-display); font-weight: var(--fw-regular);
  font-size: var(--type-display); letter-spacing: var(--ls-tight); line-height: var(--lh-tight);
  margin: 0 0 var(--space-2xs); max-width: 44ch;
}
.hero__claim b { font-weight: var(--fw-semibold); }
.hero__claim--bad b { color: var(--color-status-danger); }
.hero__note { margin: 0 0 var(--space-xs); font-size: var(--type-body); color: var(--color-text-secondary); max-width: 72ch; }
.hero__acts { display: flex; align-items: center; gap: var(--space-sm); margin-top: var(--space-2xs); }
.hero__alerts { font-size: var(--type-meta); color: var(--color-status-danger); font-weight: var(--fw-semibold); }

/* tile anatomy (metric rows + vertical altitude): number · label · anchor */
.tile {
  background: var(--color-bg-surface); border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-lg); padding: var(--space-sm) var(--space-md); box-shadow: var(--shadow-sm);
  display: flex; flex-direction: column; gap: var(--space-3xs); min-width: 0;
}
.tile__n { font-size: var(--type-display); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; letter-spacing: var(--ls-tight); line-height: var(--lh-tight); }
.tile__n small { font-size: var(--type-body); font-weight: var(--fw-regular); color: var(--color-text-secondary); }
.tile--bad .tile__n { color: var(--color-status-danger); }
.tile--ok .tile__n { color: var(--color-status-ok); }
.tile--na .tile__n { color: var(--color-text-secondary); }
.tile__l { font-size: var(--type-meta); text-transform: uppercase; letter-spacing: var(--ls-wide); color: var(--color-text-tertiary); }
.tile__anchor { font-size: var(--type-meta); color: var(--color-text-secondary); }
.tile__anchor a { color: var(--color-accent); text-decoration: none; }
.tile__anchor a:hover { text-decoration: underline; }
/* Part A's third leg — see .card__do for the anatomy this mirrors. */
.tile__do { font-size: var(--type-meta); color: var(--color-text-tertiary); }

/* hero tiles (vertical altitude keeps its four-up row) */
.hero__tiles {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-sm); margin: var(--space-sm) 0 var(--space-2xs);
}
@media (max-width: 900px) { .hero__tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* canonical-page metrics row — same tile anatomy, 4-up */
.metrics {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-sm); margin-bottom: var(--space-md);
  animation: rise var(--duration-slow) var(--ease-out) both;
}
@media (max-width: 900px) { .metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 460px) { .metrics { grid-template-columns: 1fr; } }

/* budget bar (anchor, not decoration) */
.bar { height: 4px; border-radius: var(--radius-pill); background: var(--color-bg-glass); margin-top: var(--space-2xs); overflow: hidden; }
.bar span { display: block; height: 100%; border-radius: var(--radius-pill); background: var(--color-accent); }
.bar--over span { background: var(--color-status-danger); }

/* ── sections: one heading grammar, phrased as the operator's question ──── */
.section { margin-top: var(--space-xl); }
.section__head { display: flex; align-items: baseline; gap: var(--space-sm); flex-wrap: wrap; margin-bottom: var(--space-xs); }
.section__head h2 {
  margin: 0; font-size: var(--type-meta); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--color-text-secondary);
}
.section__sum { font-size: var(--type-meta); color: var(--color-text-tertiary); }
.section__actions { margin-left: auto; display: flex; align-items: center; gap: var(--space-xs); flex-wrap: wrap; }

/* legend — the vocabulary, once, with meanings on hover */
.legend { display: flex; gap: 6px; /* chip-row optics */ flex-wrap: wrap; align-items: center; margin-left: auto; }
.legend .chip { cursor: help; }

/* ── rows — the check-card anatomy: chip · claim · evidence · one action ── */
.rows { display: flex; flex-direction: column; gap: var(--space-xs); }
.row {
  background: var(--color-bg-surface); border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
}
.row--down { border-left: 3px solid var(--color-status-danger); }
.row--stale { border-left: 3px solid var(--color-status-warn); }
.row > summary {
  display: flex; align-items: center; gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md); cursor: pointer; list-style: none; min-width: 0;
}
.row > summary::-webkit-details-marker { display: none; }
.row > summary::after {
  content: "▸"; color: var(--color-text-tertiary); font-size: var(--type-meta);
  transition: transform var(--duration-fast) var(--ease-out); flex: none;
}
.row[open] > summary::after { transform: rotate(90deg); }
.row__claim { font-weight: var(--fw-semibold); font-size: var(--type-body); white-space: nowrap; }
.row__evidence {
  font-size: var(--type-meta); color: var(--color-text-secondary); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1 1 auto;
}
.row__act { display: inline-flex; gap: 6px; /* button-pair optics */ flex: none; margin-left: auto; }
.row__detail {
  border-top: 1px solid var(--color-border-subtle);
  padding: var(--space-sm) var(--space-md); display: grid; gap: var(--space-xs); font-size: var(--type-body);
}
.row__detail dl { display: grid; grid-template-columns: auto 1fr; gap: var(--space-2xs) var(--space-sm); margin: 0; }
.row__detail dt { color: var(--color-text-tertiary); font-size: var(--type-meta); }
.row__detail dd { margin: 0; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.row__cause { color: var(--color-text); }
.row__cause span {
  display: block; font-size: var(--type-meta); font-weight: var(--fw-bold);
  letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--color-status-danger); margin-bottom: var(--space-3xs);
}

/* ── last contact vs last GOOD contact (2026-08-28) ──────────────────────────
   Two dates, adjacent, on purpose. They were one date for sixteen days and the
   one they were was the wrong one: a poller sending empty bodies every ten
   minutes read exactly like a poller that had stopped. When the two disagree
   the block turns red-edged and the verdict line says so in a sentence — it is
   NOT a new alert, the DOWN chip above it already fires. */
.row__contact {
  border: 1px solid var(--color-border-subtle); border-left: 3px solid var(--color-border);
  border-radius: var(--radius-md); padding: var(--space-sm) var(--space-md);
  display: grid; gap: var(--space-2xs); background: var(--color-bg-glass);
}
.row__contact.row__cause--bad { border-left-color: var(--color-status-danger); }
.row__contact dl.contact { display: grid; grid-template-columns: auto 1fr; gap: var(--space-3xs) var(--space-sm); margin: 0; }
.row__contact dl.contact dt {
  color: var(--color-text-tertiary); font-size: var(--type-meta);
  text-transform: uppercase; letter-spacing: var(--ls-wide);
}
.row__contact dl.contact dd { margin: 0; font-variant-numeric: tabular-nums; }
.row__contact dl.contact dd.t-bad { color: var(--color-status-danger); font-weight: var(--fw-semibold); }
.contact__verdict { margin: 0; color: var(--color-text); }
.contact__why { margin: 0; color: var(--color-text-secondary); font-size: var(--type-meta); }
.contact__why span {
  font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: var(--ls-wide);
  color: var(--color-status-danger); margin-right: var(--space-2xs);
}

/* One plain sentence naming who owns a fix this console cannot make. It sits
   where a dead Retry used to; it never offers to notify anyone. */
.row__handover {
  margin: 0; padding: var(--space-2xs) 0 0; color: var(--color-text);
  border-left: 3px solid var(--color-status-warn); padding-left: var(--space-sm);
}
.row__handover--todo { border-left-color: var(--color-text-tertiary); color: var(--color-text-secondary); font-size: var(--type-meta); }

.row--flat { display: flex; align-items: center; gap: var(--space-sm); padding: var(--space-sm) var(--space-md); }

/* ── system groups (collapsed by default — Law 1 layer 2) ───────────────── */
.group { border: 1px solid var(--color-border-subtle); border-radius: var(--radius-lg); background: var(--color-bg-surface); box-shadow: var(--shadow-sm); }
.group > summary {
  display: flex; align-items: center; gap: var(--space-sm); padding: var(--space-sm) var(--space-md);
  cursor: pointer; list-style: none; font-size: var(--type-body);
}
.group > summary::-webkit-details-marker { display: none; }
.group > summary::after { content: "▸"; color: var(--color-text-tertiary); font-size: var(--type-meta); transition: transform var(--duration-fast) var(--ease-out); }
.group[open] > summary::after { transform: rotate(90deg); }
.group__name { font-weight: var(--fw-semibold); }
.group__sum { color: var(--color-text-secondary); margin-left: auto; display: inline-flex; gap: 6px; /* chip-row optics */ align-items: center; font-size: var(--type-meta); }
.group__body { border-top: 1px solid var(--color-border-subtle); padding: var(--space-2xs) 0; }
.group__body .row { border: 0; border-radius: 0; box-shadow: none; }
.group__body .row + .row { border-top: 1px solid var(--color-border-subtle); }

/* blast-radius microcopy: what an action touches, stated BEFORE the click */
.blast { font-size: var(--type-meta); color: var(--color-text-tertiary); max-width: 46ch; margin: var(--space-2xs) 0 0; }

/* ══ MASONRY (Overview, JOB 2) — Pinterest column flow: varying heights,
      natural rhythm, no rigid grid. Cards stagger in on --i. ═════════════ */
.masonry { columns: 3; column-gap: var(--space-sm); }
@media (max-width: 1000px) { .masonry { columns: 2; } }
@media (max-width: 640px)  { .masonry { columns: 1; } }

.card {
  break-inside: avoid; -webkit-column-break-inside: avoid;
  background: var(--color-bg-surface); border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  padding: var(--space-md); margin: 0 0 var(--space-sm);
  display: flow-root; min-width: 0; position: relative;
  animation: rise var(--duration-slow) var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * 40ms);
  transition: box-shadow var(--duration-fast) var(--ease-out), transform var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out);
}
.card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); border-color: var(--color-border-default); }
@keyframes rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.card__eyebrow {
  margin: 0 0 var(--space-xs); font-size: var(--type-meta); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--color-text-tertiary);
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-xs);
}
.card__link { font-weight: var(--fw-medium); letter-spacing: var(--ls-normal); text-transform: none; color: var(--color-accent); text-decoration: none; font-size: var(--type-meta); }
.card__link:hover { text-decoration: underline; }
.card__cta { text-decoration: none; letter-spacing: var(--ls-normal); text-transform: none; }
.card__n {
  margin: 0 0 var(--space-2xs); font-family: var(--font-display);
  font-size: var(--type-display); font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums; letter-spacing: var(--ls-tight); line-height: var(--lh-tight);
}
.card__n small { font-size: var(--type-body); font-weight: var(--fw-regular); color: var(--color-text-secondary); }
.card__n--na { color: var(--color-text-secondary); }
.card__anchor { margin: var(--space-xs) 0 0; font-size: var(--type-meta); color: var(--color-text-secondary); }
.card__anchor a { color: var(--color-accent); text-decoration: none; }
.card__anchor a:hover { text-decoration: underline; }
/* Part A's third leg: what to DO about this number, or "nothing" stated
   plainly. Deliberately quieter than card__anchor (the comparison) so the
   hierarchy stays claim > comparison > instruction, but never omitted. */
.card__do { margin: var(--space-3xs) 0 0; font-size: var(--type-meta); color: var(--color-text-tertiary); }
.card--wide { /* masonry decides columns; wide cards simply carry more rows */ }

/* dark card — the live-calls pill (the one deliberate inversion) */
.card--dark {
  background: var(--color-text); border-color: var(--color-text); color: var(--color-text-inverse);
}
.card--dark .card__eyebrow, .card--dark .card__anchor, .card--dark .card__do { color: color-mix(in srgb, var(--color-text-inverse) 72%, transparent); }
.card--dark .card__n--na { color: color-mix(in srgb, var(--color-text-inverse) 72%, transparent); }
.live-pill { display: grid; grid-template-columns: auto 1fr; grid-template-rows: auto auto; column-gap: var(--space-sm); align-items: center; }
.live-pill__orb {
  grid-row: 1 / span 2; width: 34px; height: 34px; border-radius: var(--radius-circle);
  background: radial-gradient(circle at 34% 30%, var(--color-accent-bright), var(--color-accent));
  box-shadow: 0 0 0 5px var(--accent-glow);
}
.live-pill--on .live-pill__orb { animation: breathe 2.4s var(--ease-in-out) infinite; }
@keyframes breathe {
  0%, 100% { box-shadow: 0 0 0 4px var(--accent-glow); }
  50% { box-shadow: 0 0 0 9px var(--accent-glow); }
}
.live-pill__n { font-family: var(--font-display); font-size: var(--type-display); font-weight: var(--fw-semibold); letter-spacing: var(--ls-tight); line-height: var(--lh-tight); }
.live-pill__sub { font-size: var(--type-meta); color: color-mix(in srgb, var(--color-text-inverse) 72%, transparent); }
.live-pill__sub .i { border-color: color-mix(in srgb, var(--color-text-inverse) 35%, transparent); color: color-mix(in srgb, var(--color-text-inverse) 72%, transparent); }

/* ══ CHARTS (JOB 4) — one treatment: soft area, rounded cap, token accent ═ */
.spark { display: block; width: 100%; height: 56px; margin-top: var(--space-2xs); overflow: visible; }
.viz-card .spark { height: 96px; }
.spark__line {
  fill: none; stroke: var(--color-accent); stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 1; stroke-dashoffset: 1;
  animation: drawin var(--duration-slow) var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 40ms);
}
@keyframes drawin { to { stroke-dashoffset: 0; } }
.spark__area { opacity: 0; animation: fadein var(--duration-slow) var(--ease-out) forwards; animation-delay: calc(var(--i, 0) * 40ms + 150ms); }
@keyframes fadein { to { opacity: 1; } }
.spark__cap { fill: var(--color-accent); stroke: var(--color-bg-surface); stroke-width: 2; }
.card--dark .spark__cap { stroke: var(--color-text); }
.spark__dot { fill: var(--color-accent); stroke: var(--color-bg-surface); stroke-width: 2; opacity: 0; transition: opacity var(--duration-instant); }
.spark__pt:hover .spark__dot { opacity: 1; }

/* donut — one hue, opacity-stepped; identity lives in the swatched list */
.donut-wrap { position: relative; width: 156px; margin: 0 auto var(--space-sm); }
.donut { display: block; width: 100%; height: auto; }
.donut__track { fill: none; stroke: var(--color-bg-glass); }
.donut__seg { fill: none; stroke: var(--color-accent); stroke-linecap: butt; cursor: default; transition: opacity var(--duration-fast) var(--ease-out); }
.donut__seg.is-lit { opacity: 1 !important; filter: drop-shadow(0 0 4px var(--accent-glow)); }
.donut-center { position: absolute; inset: 0; display: grid; place-content: center; text-align: center; }
.donut-center__l { font-size: var(--type-meta); text-transform: uppercase; letter-spacing: var(--ls-wide); color: var(--color-text-tertiary); }
.donut-center__n { font-family: var(--font-display); font-size: var(--type-display); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; letter-spacing: var(--ls-tight); }

.cost-lines { display: flex; flex-direction: column; }
.cost-line {
  display: flex; align-items: baseline; gap: var(--space-xs);
  padding: var(--space-2xs) var(--space-2xs); border-radius: var(--radius-md);
  font-size: var(--type-body); cursor: default;
  transition: background var(--duration-fast) var(--ease-out);
}
.cost-line.is-lit, .cost-line:hover { background: var(--accent-bg); }
.cost-line__swatch { width: 10px; height: 10px; border-radius: 3px; /* swatch optics */ background: var(--color-accent); flex: none; align-self: center; }
.cost-line__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cost-line__val { margin-left: auto; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cost-line__val small { color: var(--color-text-tertiary); font-size: var(--type-meta); }

/* horizontal fact bars (pages' one-viz) — held counts only */
.hbar-rows { display: flex; flex-direction: column; gap: var(--space-xs); margin-top: var(--space-2xs); }
.hbar { display: grid; grid-template-columns: minmax(120px, 200px) 1fr auto; align-items: center; gap: var(--space-sm); font-size: var(--type-meta); }
.hbar__label { color: var(--color-text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hbar__track { display: flex; height: 8px; border-radius: var(--radius-pill); background: var(--color-bg-glass); overflow: hidden; min-width: 40px; }
.hbar__fill { height: 100%; background: var(--color-accent); border-radius: var(--radius-pill); transition: width var(--duration-slow) var(--ease-out); }
.hbar__fill--bad { background: var(--color-status-danger); }
.hbar__n { color: var(--color-text-secondary); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ── integration strip (the honest "system health") ─────────────────────── */
.integ-strip { display: flex; flex-direction: column; margin-top: var(--space-sm); }
.integ {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--space-3xs) var(--space-xs);
  padding: var(--space-2xs) var(--space-xs); border-radius: var(--radius-md);
  border: 1px solid transparent; font-size: var(--type-body);
}
.integ--bad { border-color: var(--danger-bg); background: color-mix(in srgb, var(--color-status-danger) 4%, transparent); margin: var(--space-3xs) 0; }
.integ__dot { width: 8px; height: 8px; border-radius: var(--radius-circle); }
.integ__dot--live { background: var(--color-status-ok); box-shadow: 0 0 0 3px var(--ok-bg); }
.integ__dot--down { background: var(--color-status-danger); box-shadow: 0 0 0 3px var(--danger-bg); }
.integ__dot--stale { background: var(--color-status-warn); box-shadow: 0 0 0 3px var(--warn-bg); }
.integ__dot--expected { background: var(--color-status-muted); }
.integ__name { font-weight: var(--fw-medium); min-width: 0; }
.integ__sum { font-size: var(--type-meta); color: var(--color-text-tertiary); white-space: nowrap; text-align: right; }
.integ__down { grid-column: 2 / -1; margin: 0; font-size: var(--type-meta); color: var(--color-text-secondary); display: flex; align-items: center; gap: var(--space-2xs) var(--space-xs); flex-wrap: wrap; }
.integ__down b { color: var(--color-text); }

/* ── recent activity rows ────────────────────────────────────────────────── */
.act-row { display: flex; align-items: baseline; gap: var(--space-xs); padding: var(--space-2xs) 0; font-size: var(--type-body); border-top: 1px solid var(--color-border-subtle); }
.act-row:first-of-type { border-top: 0; }
.act-row__dot { width: 7px; height: 7px; border-radius: var(--radius-circle); background: var(--color-status-muted); flex: none; align-self: center; }
.act-row__dot--danger { background: var(--color-status-danger); box-shadow: 0 0 0 3px var(--danger-bg); }
.act-row__dot--warn { background: var(--color-status-warn); box-shadow: 0 0 0 3px var(--warn-bg); }
.act-row__text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.act-row--quiet .act-row__text { color: var(--color-text-secondary); font-size: var(--type-meta); }
.act-row__when { margin-left: auto; font-size: var(--type-meta); color: var(--color-text-tertiary); white-space: nowrap; }

/* ── verticals mini rows (Overview) ─────────────────────────────────────── */
.vmini {
  display: flex; align-items: center; gap: var(--space-xs);
  padding: var(--space-xs) var(--space-2xs); border-radius: var(--radius-md);
  transition: background var(--duration-fast) var(--ease-out);
}
.vmini:hover { background: var(--color-bg-glass); }
.vmini__name { font-weight: var(--fw-semibold); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vmini__stat { margin-left: var(--space-xs); font-variant-numeric: tabular-nums; white-space: nowrap; }
.vmini__stat small { color: var(--color-text-tertiary); font-size: var(--type-meta); }
.vmini__stat:first-of-type { margin-left: auto; }
.vmini__go { color: var(--color-accent); text-decoration: none; flex: none; padding: 0 var(--space-2xs); transition: transform var(--duration-fast) var(--ease-out); }
.vmini:hover .vmini__go { transform: translateX(2px); }

/* ── canonical-page one-viz card ────────────────────────────────────────── */
.viz-card {
  background: var(--color-bg-surface); border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  padding: var(--space-md); margin-bottom: var(--space-md);
  animation: rise var(--duration-slow) var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * 40ms);
}

/* ── records table — wide content scrolls inside its wrap, never the page ─ */
.tbl-wrap {
  overflow-x: auto; background: var(--color-bg-surface);
  border: 1px solid var(--color-border-subtle); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
}
.tbl { width: 100%; border-collapse: collapse; font-size: var(--type-body); }
.tbl th {
  text-align: left; font-size: var(--type-meta); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--color-text-tertiary);
  padding: var(--space-sm) var(--space-md); border-bottom: 1px solid var(--color-border-subtle); white-space: nowrap;
}
.tbl td { padding: var(--space-sm) var(--space-md); border-bottom: 1px solid var(--color-border-subtle); vertical-align: top; font-variant-numeric: tabular-nums; }
.tbl tbody tr { transition: background var(--duration-fast) var(--ease-out); }
.tbl tbody tr:hover { background: var(--color-bg-glass); }
.tbl tbody tr:last-child td { border-bottom: 0; }
.tbl__act { text-align: right; white-space: nowrap; }
.tbl__act .ops-btn + .ops-btn { margin-left: var(--space-2xs); }
/* An archived vertical is present but not part of the live estate: recessive,
   never struck through or greyed to unreadable -- it is a real row with real
   history and it still has to be legible enough to restore. */
.tbl tbody tr.tbl__row--archived td { opacity: .68; }
.tbl tbody tr.tbl__row--archived:hover td { opacity: 1; }
.tbl__act .ops-btn { text-decoration: none; }
.tbl__id { display: inline-flex; align-items: center; gap: var(--space-xs); }

/* ── the spin-up modal (JOB 8): frames the brand-authoring flow ─────────── */
dialog.onboard {
  /* Sized for the conversational spin-up: the chat keeps 64px of air to
     every modal edge (addendum 2026-08-25), so the dialog itself grew. */
  width: min(1240px, calc(100vw - 48px));
  height: min(880px, calc(100vh - 48px));
  padding: 0; border: 1px solid var(--color-border-default); border-radius: var(--radius-lg);
  background: var(--color-bg-base); box-shadow: var(--shadow-md);
  display: none; flex-direction: column; overflow: hidden;
}
dialog.onboard[open] { display: flex; animation: modalin var(--duration-medium) var(--ease-out); }
dialog.onboard::backdrop { background: color-mix(in srgb, var(--color-text) 40%, transparent); backdrop-filter: blur(3px); }
@keyframes modalin { from { opacity: 0; transform: translateY(10px) scale(0.985); } to { opacity: 1; transform: none; } }
.onboard__bar {
  /* Centred title (the spin-up's name once the vertical is named), close
     glyph on the right; a gradient hairline instead of a hard border. */
  position: relative;
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-sm) var(--space-md);
  background: linear-gradient(180deg, var(--color-bg-surface), color-mix(in srgb, var(--color-bg-surface) 55%, transparent));
}
.onboard__bar::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--color-border-subtle) 18%, var(--color-border-subtle) 82%, transparent);
}
.onboard__title {
  font-weight: var(--type-subtitle2-fw, 600); font-size: var(--type-body);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 70%;
}
/* Defect 5: "Unnamed business" is a placeholder, and it reads like one --
   muted and unemphasised -- so the moment the vertical is named the header
   visibly becomes a name rather than swapping one label for another. */
.onboard__title--placeholder { color: var(--color-text-tertiary, var(--color-text-secondary)); font-weight: var(--fw-regular, 400); }
.onboard__bar .ops-btn { position: absolute; right: var(--space-md); flex: none; }
.onboard__frame { flex: 1; width: 100%; border: 0; background: var(--color-bg-base); }

/* The conversational spin-up host (js/spinup-chat.js). 64px of air between
   the chat UI and every modal edge is a stated requirement, not taste. */
.onboard__create { flex: 1; min-height: 0; display: flex; padding: 64px; }
@media (max-width: 860px) { .onboard__create { padding: var(--space-lg); } }
/* display:* on these containers must never defeat the hidden attribute
   (openBrandFrame hides the chat while the fine-tune frame is up). */
.onboard__create[hidden] { display: none; }
.su-chat [hidden] { display: none !important; }

/* ── the spin-up chat ────────────────────────────────────────────────────── */
.su-chat { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: var(--space-md); }
.su-chat__thread {
  flex: 1; min-height: 0; overflow-y: auto;
  display: flex; flex-direction: column; gap: var(--space-md);
  padding-right: var(--space-xs); scroll-behavior: smooth;
}
.su-turn { display: flex; flex-direction: column; max-width: 78%; }
.su-turn--ai { align-self: flex-start; }
.su-turn--op { align-self: flex-end; }
.su-turn--card { align-self: stretch; max-width: none; margin: var(--space-xs) 0; }
.su-turn__who {
  font-size: var(--type-meta); letter-spacing: .08em; text-transform: uppercase;
  color: var(--color-text-secondary); margin: 0 0 var(--space-2xs) var(--space-2xs);
}
.su-turn__bubble {
  font-size: var(--type-body); line-height: 1.55;
  animation: modalin var(--duration-medium) var(--ease-out);
}
/* DEFECT 5 (2026-08-26) · ASSISTANT PROSE IS PROSE.
   The 2026-08-25 pass removed the BORDER from the assistant bubble and left
   the surface fill, the shadow and the large radius behind it, which is the
   whole visual signature of a card, so every assistant sentence still read as
   a framed panel, one panel per sentence, stacked down the thread. Bubbles
   are not cards is a standing law, and a fill plus a shadow IS the frame. So
   the assistant side now carries no surface, no shadow and no radius at all:
   it is text on the thread, with the speaker label above it doing the work
   the frame was doing badly. The OPERATOR side keeps its tinted bubble —
   that is what makes the two sides legible as two sides, and it is a bubble
   rather than a panel: tinted, tight, no shadow, no border. */
.su-turn--ai .su-turn__bubble {
  background: none; border: 0; box-shadow: none; padding: 0;
  color: var(--color-text);
}
.su-turn--ai .su-turn__bubble > :first-child { margin-top: 0; }
.su-turn--ai .su-turn__bubble > :last-child { margin-bottom: 0; }
.su-turn--op .su-turn__bubble {
  padding: var(--space-sm) var(--space-md);
  border-radius: var(--radius-lg);
  border-top-right-radius: var(--radius-sm);
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--color-accent) 18%, var(--color-bg-surface)),
    color-mix(in srgb, var(--color-accent) 6%, var(--color-bg-surface)));
  border: 0; box-shadow: none;
}
/* Prose gets room to be prose: an assistant turn is allowed a wider measure
   than a bubble was, but still a readable one. */
.su-turn--ai { max-width: 62ch; }
.su-progress { display: flex; flex-direction: column; gap: var(--space-2xs); margin: 0 0 0 var(--space-md); }
.su-progress__line {
  font-size: var(--type-meta); color: var(--color-text-secondary);
  animation: modalin var(--duration-medium) var(--ease-out);
}
.su-progress__line::before { content: "· "; }
.su-progress__line[data-tone="ok"] { color: var(--color-status-ok, var(--color-accent)); }
.su-progress__line[data-tone="warn"] { color: var(--color-status-warn, var(--color-text-secondary)); }
.su-progress__line[data-tone="error"] { color: var(--color-status-danger, #b3261e); }
.su-progress__line[data-working="true"] { color: var(--color-text); }

/* Animated loading dots. Used wherever something is genuinely in flight — a
   build step, a lock, a Retry's token re-cut — and never as decoration on a
   step that has already finished: the dots are removed the moment the await
   settles, which is what makes them readable as "still going". */
.su-dots { display: inline-flex; gap: 3px; margin-left: 6px; vertical-align: baseline; }
.su-dots i {
  width: 4px; height: 4px; border-radius: 50%; background: currentColor;
  opacity: .3; animation: su-dot 1.1s ease-in-out infinite;
}
.su-dots i:nth-child(2) { animation-delay: .16s; }
.su-dots i:nth-child(3) { animation-delay: .32s; }
@keyframes su-dot { 0%, 70%, 100% { opacity: .28; transform: translateY(0); } 35% { opacity: 1; transform: translateY(-2px); } }
@media (prefers-reduced-motion: reduce) {
  .su-dots i { animation: none; opacity: .6; }
}
.su-error { color: var(--color-status-danger, #b3261e); font-size: var(--type-meta); margin: 0; }
.su-note { color: var(--color-text-secondary); font-size: var(--type-meta); margin: 0; }

.su-chat__chips { display: flex; flex-wrap: wrap; gap: var(--space-xs); justify-content: center; }
.su-chip {
  border: 0; color: var(--color-text); border-radius: var(--radius-md);
  background: linear-gradient(180deg, var(--color-bg-surface), color-mix(in srgb, var(--color-bg-surface) 72%, var(--color-bg-glass)));
  box-shadow: var(--shadow-sm);
  padding: var(--space-xs) var(--space-sm); font-size: var(--type-meta);
  cursor: pointer; text-align: left; max-width: 230px;
  transition: box-shadow var(--duration-fast) var(--ease-out), transform var(--duration-fast) var(--ease-out);
}
.su-chip:hover { box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-accent) 40%, transparent), var(--shadow-sm); transform: translateY(-1px); }

.su-chat__inputbar {
  display: flex; align-items: center; gap: var(--space-xs);
  border: 1px solid var(--color-border-default); border-radius: var(--radius-pill);
  background: var(--color-bg-surface); padding: var(--space-xs) var(--space-sm);
  box-shadow: var(--shadow-sm);
}
.su-chat__input { flex: 1; border: 0; outline: none; background: transparent; font: inherit; color: var(--color-text); padding: var(--space-xs); }
.su-chat__mic, .su-chat__send, .su-chat__attach, .su-chat__speaker {
  flex: none; display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 50%; border: 1px solid var(--color-border-subtle); cursor: pointer;
  background: transparent; color: var(--color-text-secondary);
}
.su-chat__send { background: var(--color-text); color: var(--color-bg-base); border-color: var(--color-text); font-weight: var(--fw-semibold); }
.su-chat__mic:disabled { cursor: not-allowed; opacity: .55; }
/* DEFECT 2 · voice output is a MODE the operator chooses, and the control
   shows which mode they are in. Off is the default and off is struck
   through, so "it is not going to talk at me" is readable at a glance
   rather than inferred from silence. */
.su-chat__speaker { position: relative; }
.su-chat__speaker[aria-pressed="true"] {
  color: var(--color-accent);
  border-color: color-mix(in srgb, var(--color-accent) 45%, transparent);
  background: color-mix(in srgb, var(--color-accent) 10%, transparent);
}
.su-chat__speaker[aria-pressed="false"] .su-chat__speaker-wave { opacity: .25; }
.su-chat__speaker[aria-pressed="false"] .su-chat__speaker-off {
  position: absolute; left: 7px; right: 7px; top: 50%; height: 1.5px;
  background: currentColor; transform: rotate(-38deg); border-radius: 1px; opacity: .8;
}

/* cards in the conversation (built on .ops-card) */
.su-card-head { display: flex; align-items: baseline; gap: var(--space-sm); }
.su-card-head h3 { margin: 0; font-size: var(--type-body); font-weight: var(--fw-semibold); }
.su-card-kicker { font-size: var(--type-meta); letter-spacing: .08em; text-transform: uppercase; color: var(--color-text-secondary); }

.su-recap__chips { display: flex; flex-wrap: wrap; gap: var(--space-xs); }
/* Interactive recap chips: hover invites, click edits IN PLACE (dropdown or
   inline input inside the chip). Gradient surfaces, no hard lines. */
.su-recap__chip {
  display: inline-flex; gap: 6px; align-items: baseline;
  border: 0; font: inherit; color: var(--color-text);
  background: linear-gradient(180deg, color-mix(in srgb, var(--color-bg-glass) 60%, var(--color-bg-surface)), var(--color-bg-glass));
  border-radius: var(--radius-pill); padding: var(--space-2xs) var(--space-sm); font-size: var(--type-meta);
  transition: box-shadow var(--duration-fast) var(--ease-out);
}
.su-recap__chip b { font-weight: var(--type-subtitle2-fw, 600); }
button.su-recap__chip--editable { cursor: pointer; }
button.su-recap__chip--editable:hover {
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-accent) 45%, transparent);
}
.su-recap__chip--editing {
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-accent) 60%, transparent);
}
.su-recap__chip-control {
  font: inherit; font-size: var(--type-meta); color: var(--color-text);
  border: 0; outline: none; background: transparent; max-width: 170px;
}
.su-recap__chip--inferred::after {
  content: "inferred"; font-size: var(--type-overline-size, 12px);
  letter-spacing: var(--ls-wide); color: var(--color-accent);
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--color-accent) 16%, transparent),
    color-mix(in srgb, var(--color-accent) 6%, transparent));
  border-radius: var(--radius-pill); padding: 0 7px; align-self: center;
}

.su-upload__zone {
  display: flex; align-items: center; justify-content: center; gap: var(--space-sm);
  border: 1.5px dashed var(--color-border-default); border-radius: var(--radius-lg);
  padding: var(--space-lg); color: var(--color-text-secondary); font-size: var(--type-meta);
}
.su-upload__zone[data-over="true"] { border-color: var(--color-accent); background: color-mix(in srgb, var(--color-accent) 8%, transparent); }
.su-upload__list { display: flex; flex-wrap: wrap; gap: var(--space-xs); margin-top: var(--space-sm); }
.su-upload__item { font-size: var(--type-meta); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-pill); padding: 3px 10px; }
.su-upload__item i { font-style: normal; color: var(--color-accent); }
.su-upload__item--bad { color: var(--color-status-danger, #b3261e); border-color: currentColor; }

/* Ta-daaaa: the preview card. The RENDER inside it is the tenant Home at
   reduced scale and owns its own block at the foot of this file (.bhp); what
   lives here is the card furniture around it — the applied-facts chips, the
   provenance line, the honesty note and the retry state.

   The .su-preview[data-su-branded] rules that used to sit here are DELETED,
   not disabled. They painted `background: var(--su-grad, var(--su-bg))` onto
   the preview from the reference's measured border-ring average, which on an
   accent-heavy reference is the accent — the mechanism that flooded an entire
   dashboard yellow (2026-08-27). Ground is now a role decided in
   js/brand-model.js and can never be handed a sampled chroma. */
.su-preview__prov { margin: var(--space-sm) 0 0; font-size: var(--type-meta); color: var(--color-text-secondary); }
.su-preview__prov b { color: var(--color-text); font-variant-numeric: tabular-nums; }
.su-preview__ruled { color: var(--color-text-tertiary, var(--color-text-secondary)); font-style: italic; }
.su-preview__honesty { margin: var(--space-xs) 0 0; }
/* Retry says it is working, and says what it landed on. The render itself
   stays fully legible while the token re-cut is in flight (the model on screen
   is local maths and already correct); only its crispness drops, so "busy"
   reads without hiding the thing being judged. */
.su-preview__retry-note { margin: var(--space-2xs) 0 0; }
.su-preview[data-su-busy="true"] .bhp__viewport {
  opacity: .72; transition: opacity var(--duration-fast) var(--ease-out);
}
/* An applied-facts chip carries its provenance. A value a RULE produced is
   marked, because that is exactly the case where a measurement did not
   survive and the operator is owed the difference. */
.su-recap__prov {
  font-style: normal; font-size: .85em; opacity: .68; margin-left: var(--space-2xs);
}
.su-recap__chip--ruled { border-style: dashed; }
.su-swatch {
  display: inline-block; width: .72em; height: .72em; border-radius: 3px;
  margin-right: .35em; vertical-align: -0.05em;
  border: 1px solid color-mix(in srgb, var(--color-text) 22%, transparent);
}
.su-door {
  font-family: var(--font-mono); font-size: var(--type-overline-size, 12px);
  background: var(--color-bg-glass); border-radius: var(--radius-sm); padding: 1px 6px;
}

/* ── the two provisioning steps on the finished card ─────────────────────
   A login and a phone number are the last two things a new vertical needed a
   human for, and both take one or two typed values. They get their OWN fields
   rather than the chat's input bar: the conversation is over by the time these
   are offered (state.step === 'done', and route() ignores everything after
   it), so a typed answer routed through the bar would go nowhere at all.

   The output area is deliberately generous with vertical space: it is where a
   generated password is shown ONCE, and a credential that wraps mid-string
   into the card's edge is a credential somebody copies wrong. */
.su-provision-form { display: flex; flex-direction: column; gap: var(--space-sm); margin-top: var(--space-sm); }
.su-provision-field { display: flex; flex-direction: column; gap: var(--space-3xs, 4px); }
.su-provision-field > span {
  font-size: var(--type-meta); color: var(--color-text-tertiary, var(--color-text-secondary));
  text-transform: uppercase; letter-spacing: .07em;
}
.su-provision-field > input {
  font: inherit; font-size: var(--type-body, 14px); color: var(--color-text);
  background: var(--color-bg-glass); border: 1px solid var(--color-border-default);
  border-radius: var(--radius-md); padding: 9px 11px;
}
.su-provision-field > input:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.su-provision-out { display: flex; flex-direction: column; gap: var(--space-2xs); }
.su-provision-out:empty { display: none; }
.su-provision-out .su-door { display: inline-block; margin-top: 2px; word-break: break-all; }

/* ── the number picker · the last step of the spin-up ──────────────────────
   The account's own numbers, offered rather than retyped. Each row is one
   radio and one number, big enough to read a phone number off at a glance,
   because the whole point of this list is that a digit is never retyped.
   The list scrolls at eight-ish rows rather than pushing the Attach button
   off the card: a submit an operator has to hunt for is how a picked number
   goes unattached. */
/* `display: flex` beats the `hidden` attribute, so the empty-list state has to
   say so explicitly or an empty bordered box sits above the honest sentence. */
.su-number-list[hidden] { display: none; }
.su-number-list {
  display: flex; flex-direction: column; gap: var(--space-3xs, 4px);
  max-height: 15rem; overflow-y: auto;
  border: 1px solid var(--color-border-default); border-radius: var(--radius-md);
  padding: var(--space-2xs, 6px);
}
.su-number-option {
  display: flex; align-items: center; gap: var(--space-2xs, 8px);
  padding: 7px 9px; border-radius: var(--radius-sm, 6px); cursor: pointer;
  font-size: var(--type-body, 14px); color: var(--color-text);
}
.su-number-option:hover { background: var(--color-bg-glass); }
.su-number-option:focus-within { box-shadow: var(--focus-ring); }
.su-number-option > input { accent-color: var(--color-accent, currentColor); margin: 0; }
.su-number-option b { font-variant-numeric: tabular-nums; letter-spacing: .01em; }
.su-number-name { color: var(--color-text-secondary); font-size: var(--type-meta); }

/* ── STEP 3 · what should it handle? ─────────────────────────────────────
   A form, not a wizard page: six groups the operator reads top to bottom and
   edits in place. Grouped by the operator's own question ("what it can do",
   "when you are open") rather than by the table each value lands in, because
   the table is our problem and the question is theirs. Every input is a plain
   text field on purpose: this step is read and corrected in a hurry, and a
   picker that needs learning costs more than it saves. */
.su-handle-form { display: flex; flex-direction: column; gap: var(--space-sm); }
.su-handle-group {
  border: 1px solid var(--color-border-subtle); border-radius: var(--radius-lg);
  padding: var(--space-xs, 10px) var(--space-sm, 14px) var(--space-sm, 14px);
  margin: 0; display: flex; flex-direction: column; gap: var(--space-2xs, 8px);
}
.su-handle-group > legend {
  padding: 0 var(--space-2xs, 6px); font-size: var(--type-meta);
  color: var(--color-text-secondary); letter-spacing: .02em; text-transform: uppercase;
}
.su-handle-field { display: flex; flex-direction: column; gap: 3px; }
.su-handle-field > span { font-size: var(--type-meta); color: var(--color-text-secondary); }
.su-handle-field > input {
  width: 100%; box-sizing: border-box; padding: 7px 9px;
  border: 1px solid var(--color-border-default); border-radius: var(--radius-sm, 6px);
  background: var(--color-bg-input, transparent); color: var(--color-text);
  font: inherit; font-size: var(--type-body, 14px);
}
.su-handle-field > input:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.su-handle-skill {
  display: flex; align-items: flex-start; gap: var(--space-2xs, 8px);
  padding: 6px 8px; border-radius: var(--radius-sm, 6px); cursor: pointer;
  font-size: var(--type-body, 14px); color: var(--color-text);
}
.su-handle-skill:hover { background: var(--color-bg-glass); }
.su-handle-skill:focus-within { box-shadow: var(--focus-ring); }
.su-handle-skill > input { accent-color: var(--color-accent, currentColor); margin: 3px 0 0; }
.su-handle-skill .su-note { display: block; }
/* Three fields per offer, side by side where there is room and stacked where
   there is not: the price is short and the line is long, so a fixed grid wastes
   the row on a phone. */
.su-handle-offer {
  display: grid; gap: var(--space-2xs, 8px);
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  padding-top: var(--space-2xs, 6px);
  border-top: 1px solid var(--color-border-subtle);
}
.su-handle-offer:first-of-type { border-top: 0; padding-top: 0; }

/* The staffed window's days. Seven ticks on one row where there is room, and a
   wrap where there is not: it is one answer to one question ("which days is
   somebody there"), so it reads as one control rather than seven fields. */
.su-handle-days { display: flex; flex-wrap: wrap; gap: var(--space-2xs, 8px); }
.su-handle-day {
  display: inline-flex; align-items: center; gap: 5px; cursor: pointer;
  padding: 5px 8px; border-radius: var(--radius-sm, 6px);
  border: 1px solid var(--color-border-subtle);
  font-size: var(--type-meta); color: var(--color-text);
}
.su-handle-day:hover { background: var(--color-bg-glass); }
.su-handle-day:focus-within { box-shadow: var(--focus-ring); }
.su-handle-day > input { accent-color: var(--color-accent, currentColor); margin: 0; }

/* ── the WEB DOOR step · the address, composed in front of the operator ──
   The host is fixed and printed as text; only the segment is a field, and the
   two sit on one line so what is being typed is visibly the last part of a URL
   rather than a name in a box. It wraps on a narrow screen instead of shrinking
   the field to nothing. */
.su-door-compose { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.su-door-compose > code { white-space: nowrap; }
.su-door-compose > input {
  flex: 1 1 140px; min-width: 120px; box-sizing: border-box; padding: 7px 9px;
  border: 1px solid var(--color-border-default); border-radius: var(--radius-sm, 6px);
  background: var(--color-bg-input, transparent); color: var(--color-text);
  font: inherit; font-size: var(--type-body, 14px);
}
.su-door-compose > input:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* ── the WIREFRAME step · pick an arrangement before any brand ───────────
   Greyscale ON PURPOSE. This card asks one question — how is Home laid out —
   and a coloured or logoed thumbnail here invites the operator to answer a
   different one. currentColor throughout so the frames inherit the muted ink
   and pick up the accent only on the selected tile. */
.su-wires { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: var(--space-sm); }
.su-wire {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-2xs);
  border: 1px solid var(--color-border-subtle); border-radius: var(--radius-lg);
  background: var(--color-bg-surface); padding: var(--space-sm);
  font: inherit; text-align: left; cursor: pointer; color: var(--color-text);
  transition: box-shadow var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out);
}
.su-wire:hover { border-color: color-mix(in srgb, var(--color-accent) 45%, transparent); }
.su-wire__frame {
  display: block; width: 100%; border-radius: var(--radius-md);
  background: var(--color-bg-glass); padding: var(--space-xs);
  color: var(--color-text-tertiary, var(--color-text-secondary));
}
.su-wire__svg { display: block; width: 100%; height: auto; }
.su-wire__label { font-size: var(--type-body); font-weight: var(--fw-semibold); }
.su-wire__blurb { font-size: var(--type-meta); color: var(--color-text-secondary); line-height: 1.4; }
.su-wire--on {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 1px var(--color-accent);
}
.su-wire--on .su-wire__frame { color: var(--color-accent); background: color-mix(in srgb, var(--color-accent) 10%, transparent); }
/* ── the SHAPE step · which business, and which modules (NOD-2) ─────────
   Built on the wireframe tiles above so the two structural questions read as
   one family; the frame carries a glyph instead of a wireframe because this
   card asks WHAT the business is, not what it looks like. Greyscale until
   selected, same as the wireframes — no brand decision is being made here. */
.su-shape__frame {
  display: flex; align-items: center; justify-content: center;
  min-height: 66px;
}
.su-shape__glyph { font-size: 26px; line-height: 1; }

.su-mods { margin-top: var(--space-md); }
.su-mods__note {
  margin: 0 0 var(--space-sm); font-size: var(--type-meta);
  color: var(--color-text-secondary); line-height: 1.45;
}
.su-mods__row { display: flex; flex-wrap: wrap; gap: var(--space-xs); }
/* A module chip is a toggle, and an untaken one must still look like a real
   offer rather than a disabled control — the operator is choosing, not being
   refused. Taken chips carry the accent; fixed ones carry no affordance at
   all, because the spine of a workspace is not a choice. */
.su-mod {
  display: inline-flex; align-items: center; gap: 7px;
  border: 1px solid var(--color-border-subtle); border-radius: var(--radius-pill);
  background: var(--color-bg-surface); color: var(--color-text-secondary);
  font: inherit; font-size: var(--type-meta); padding: var(--space-2xs) var(--space-sm);
  cursor: pointer;
  transition: border-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out),
              background var(--duration-fast) var(--ease-out);
}
.su-mod i { font-style: normal; opacity: .75; }
.su-mod:hover { border-color: color-mix(in srgb, var(--color-accent) 45%, transparent); color: var(--color-text); }
.su-mod--on {
  border-color: var(--color-accent); color: var(--color-text);
  background: color-mix(in srgb, var(--color-accent) 10%, transparent);
}
.su-mod--on i { opacity: 1; color: var(--color-accent); }
.su-mod--fixed { cursor: default; border-style: dashed; }
.su-mod--fixed:hover { border-color: var(--color-border-subtle); color: var(--color-text-secondary); }
.su-mod--fixed small {
  font-size: var(--type-overline-size, 12px); letter-spacing: var(--ls-wide);
  color: var(--color-text-tertiary, var(--color-text-secondary));
}

/* ── the INTEGRATIONS step · an acknowledgement, never a control ─────────
   Deliberately NOT toggles, switches or fields: nothing on this card
   provisions, connects or asks for a credential, and giving it controls would
   promise otherwise. Each row states the rail and what its absence means. */
.su-slots { display: grid; gap: var(--space-sm); }
.su-slot {
  border: 1px solid var(--color-border-subtle); border-left: 2px solid var(--color-border-default);
  border-radius: var(--radius-md); padding: var(--space-sm) var(--space-md);
  background: var(--color-bg-surface);
}
.su-slot__head { display: flex; align-items: baseline; gap: var(--space-sm); }
.su-slot__head b { font-size: var(--type-body); }
.su-slot__tag {
  font-size: var(--type-overline-size, 12px); letter-spacing: var(--ls-wide);
  text-transform: uppercase; color: var(--color-accent);
  background: color-mix(in srgb, var(--color-accent) 12%, transparent);
  border-radius: var(--radius-pill); padding: 0 7px;
}
.su-slot__tag--opt {
  color: var(--color-text-tertiary, var(--color-text-secondary));
  background: var(--color-bg-glass);
}
.su-slot__state { margin-top: var(--space-2xs); font-size: var(--type-meta); color: var(--color-text); }
.su-slot__body { margin-top: 2px; font-size: var(--type-meta); color: var(--color-text-secondary); line-height: 1.45; }

.su-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--space-sm) var(--space-md); margin-bottom: var(--space-md); }
.su-grid label { display: flex; flex-direction: column; gap: var(--space-2xs); font-size: var(--type-meta); color: var(--color-text-secondary); }
.su-grid label.su-check { flex-direction: row; align-items: center; gap: var(--space-xs); align-self: end; }
.su-grid input[type="text"], .su-grid input[type="number"], .su-grid select {
  padding: 6px 10px; border: 1px solid var(--color-border-default); border-radius: var(--radius-md);
  background: var(--color-bg-surface); color: var(--color-text); font: inherit; font-size: var(--type-body);
}
/* display:contents would defeat the UA's [hidden]{display:none}, so guard it */
.su-grid [data-su-neworg]:not([hidden]) { display: contents; }

/* ── skeleton first paint — shape, not numbers ──────────────────────────── */
.card--skeleton { border-color: transparent; box-shadow: none; background: var(--color-bg-surface); overflow: hidden; }
.card--skeleton::after, .skel {
  content: ""; display: block; border-radius: var(--radius-md);
  background: linear-gradient(100deg, var(--color-bg-glass) 40%, color-mix(in srgb, var(--color-text) 6%, transparent) 50%, var(--color-bg-glass) 60%);
  background-size: 200% 100%; animation: shimmer 1.4s linear infinite;
}
.card--skeleton::after { height: 100%; }
@keyframes shimmer { to { background-position: -200% 0; } }
.skel--line { height: 12px; margin-bottom: var(--space-sm); }
.skel--claim { height: 34px; max-width: 480px; }

/* ── map surface (residency) — the footer anchor. Restyle only (JOB 5):
      the one-marker-per-region model and numbered ties are untouched. ──── */
.map-breath { height: var(--space-3xl); }
.map-surface {
  --map-dot-land: color-mix(in srgb, var(--color-text) 45%, transparent);
  --map-dot-sea: color-mix(in srgb, var(--color-text) 7%, transparent);
  position: relative; border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-lg); background: var(--color-bg-surface);
  box-shadow: var(--shadow-sm); overflow: hidden;
  max-width: 980px; margin: 0 auto; /* footer anchor: centred, generous */
}
.map-surface__canvas { position: absolute; inset: 0; }
.map-surface__pins { position: absolute; inset: 0; }
.map-pin {
  position: absolute;
  transform: translate(calc(-50% + var(--dx, 0px)), calc(-50% + var(--dy, 0px)));
}
.map-pin__marker {
  display: grid; place-items: center;
  width: 18px; height: 18px; border-radius: var(--radius-circle);
  background: var(--color-accent); color: var(--color-text-inverse);
  font-size: var(--type-meta); font-weight: var(--fw-semibold); line-height: 1;
  font-variant-numeric: tabular-nums;
  box-shadow: 0 0 0 2px var(--color-bg-surface), 0 0 0 5px var(--accent-glow);
}
/* Opaque plate (85% translucency shipped illegible labels once). `top` is
   set by the measured placement pass in js/map-surface.js. */
.map-pin__label {
  position: absolute; left: 24px; /* clears the marker + its ring */ white-space: nowrap;
  font-size: var(--type-meta);
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border-default); border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  padding: var(--space-2xs) var(--space-xs); line-height: var(--lh-normal);
}
.map-pin__label b {
  display: flex; align-items: center; gap: var(--space-2xs);
  font-size: var(--type-body); color: var(--color-text); font-weight: var(--fw-semibold);
}
.map-pin__label i { font-style: normal; display: block; color: var(--color-text-secondary); }
.map-pin__label .map-pin__more { display: block; color: var(--color-text-tertiary); }
.map-pin__n {
  display: grid; place-items: center; flex: none;
  min-width: 15px; height: 15px; padding: 0 3px; border-radius: var(--radius-circle);
  background: var(--accent-glow); color: var(--color-accent);
  font-size: var(--type-meta); font-weight: var(--fw-semibold); line-height: 1;
  font-variant-numeric: tabular-nums;
}
.map-pin--flip .map-pin__label { left: auto; right: 24px; }

.map-facts { margin-top: var(--space-sm); max-width: 980px; margin-left: auto; margin-right: auto; }
.map-facts__n {
  display: grid; place-items: center; flex: none;
  min-width: 18px; height: 18px; padding: 0 3px; border-radius: var(--radius-circle);
  background: var(--accent-glow); color: var(--color-accent);
  font-size: var(--type-meta); font-weight: var(--fw-semibold); line-height: 1;
  font-variant-numeric: tabular-nums;
}
.map-facts__n--none { background: transparent; color: var(--color-text-tertiary); }

/* ── memory — Discovery's pattern at console altitude ───────────────────── */
.mem-cap { max-width: 82ch; }
.mem-wrap {
  display: grid; grid-template-columns: 170px minmax(0, 1.15fr) minmax(0, 1fr);
  gap: var(--space-md); align-items: start; margin-top: var(--space-xs);
}
.mem-rail { display: flex; flex-direction: column; gap: var(--space-3xs); }
.mem-rail__t {
  margin: var(--space-xs) 0 var(--space-3xs); font-size: var(--type-meta);
  text-transform: uppercase; letter-spacing: var(--ls-wide); color: var(--color-text-tertiary);
}
.mem-rail__t:first-child { margin-top: 0; }
.mem-filter {
  font: inherit; font-size: var(--type-body); text-align: left; cursor: pointer;
  padding: var(--space-2xs) var(--space-sm); border-radius: var(--radius-md);
  border: 1px solid transparent; background: transparent; color: var(--color-text-secondary);
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-xs);
  transition: background var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.mem-filter small { color: var(--color-text-tertiary); font-variant-numeric: tabular-nums; font-size: var(--type-meta); }
.mem-filter:hover { background: var(--color-bg-surface); color: var(--color-text); }
.mem-filter[aria-pressed="true"] {
  background: var(--color-bg-surface); border-color: var(--color-border-subtle);
  color: var(--color-text); box-shadow: var(--shadow-sm); font-weight: var(--fw-medium);
}
.mem-viz {
  background: var(--color-bg-surface); border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); padding: var(--space-sm);
}
.mem-canvas { display: block; width: 100%; height: auto; }
.mem-cluster__label { font-size: var(--type-meta); fill: var(--color-text-secondary); font-family: var(--font-body); }
.mem-bubble { stroke-width: 1.5; cursor: default; transition: fill-opacity var(--duration-fast) var(--ease-out); }
.mem-bubble--danger { fill: var(--color-status-danger); stroke: var(--color-status-danger); fill-opacity: .18; }
.mem-bubble--warn { fill: var(--color-status-warn); stroke: var(--color-status-warn); fill-opacity: .18; }
.mem-bubble--info { fill: var(--color-accent); stroke: var(--color-accent); fill-opacity: .14; }
.mem-bubble.is-lit { fill-opacity: .45; }
.mem-insights { display: flex; flex-direction: column; gap: var(--space-xs); min-width: 0; }
.mem-insight {
  background: var(--color-bg-surface); border: 1px solid var(--color-border-subtle);
  border-left-width: 3px; border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  padding: var(--space-xs) var(--space-sm);
  transition: background var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out);
}
.mem-insight--danger { border-left-color: var(--color-status-danger); }
.mem-insight--warn { border-left-color: var(--color-status-warn); }
.mem-insight--info { border-left-color: var(--color-accent); }
.mem-insight.is-lit { background: var(--color-bg-elevated); border-color: var(--color-border-strong); }
.mem-insight__sum { margin: 0; font-size: var(--type-body); }
.mem-insight__meta { margin: var(--space-3xs) 0 0; font-size: var(--type-meta); color: var(--color-text-tertiary); }
@media (max-width: 1000px) {
  .mem-wrap { grid-template-columns: 1fr; }
  .mem-rail { flex-direction: row; flex-wrap: wrap; align-items: baseline; }
  .mem-rail__t { margin: 0 var(--space-3xs) 0 0; }
}

/* ── cost cards (Usage & Costs page) — the house tile anatomy in a grid ─── */
.cost-cards {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: var(--space-sm);
}
.cost-cards .tile__anchor a { color: var(--color-accent); text-decoration: none; }
.cost-cards .tile__anchor a:hover { text-decoration: underline; }

/* ── audit ──────────────────────────────────────────────────────────────── */
.audit { margin-top: var(--space-xl); }
.audit summary { cursor: pointer; font-size: var(--type-body); color: var(--color-text-secondary); }
.audit__body { margin-top: var(--space-xs); font-size: var(--type-body); }
.audit__row { padding: var(--space-2xs) 0; border-top: 1px solid var(--color-border-subtle); font-variant-numeric: tabular-nums; }
.audit__row span { color: var(--color-text-tertiary); }

/* ── notes / errors / footer ────────────────────────────────────────────── */
.note { font-size: var(--type-body); color: var(--color-text-secondary); margin: var(--space-2xs) 0; }
.note--bad { color: var(--color-status-danger); }
.note--na { color: var(--color-text-tertiary); }
time { font-variant-numeric: tabular-nums; }

.ops-foot {
  max-width: var(--container-max); margin: 0 auto; padding: 0 var(--space-lg) var(--space-2xl);
  font-size: var(--type-meta); color: var(--color-text-tertiary); line-height: var(--lh-relaxed);
}

/* ── receipts (DESIGN-NOTES.md Law 8) ───────────────────────────────────────
   Every write's after-the-fact answer to "did it work": what happened, on
   which record, when, and whether it can be undone. A status region, not a
   dialog -- it never blocks the page, and it never auto-dismisses (a timer
   is not something a screen-reader user or someone who glanced away can
   rely on). Fixed bottom-left, stacking newest-on-top, capped at 4 by JS. */
#ops-receipts {
  position: fixed; left: var(--space-lg); bottom: var(--space-lg); z-index: 500;
  display: flex; flex-direction: column-reverse; gap: var(--space-xs);
  max-width: min(420px, calc(100vw - var(--space-lg) * 2));
  pointer-events: none;
}
.receipt {
  pointer-events: auto;
  display: flex; align-items: flex-start; gap: var(--space-sm);
  background: var(--color-bg-elevated); color: var(--color-text-primary);
  border: 1px solid var(--color-border-default); border-left-width: 3px;
  border-radius: var(--radius-lg); box-shadow: var(--shadow-overlay);
  padding: var(--space-sm) var(--space-md);
  animation: receipt-in var(--duration-slow) var(--ease-out) both;
}
.receipt--ok { border-left-color: var(--color-status-ok); }
.receipt--fail { border-left-color: var(--color-status-danger); }
.receipt--info { border-left-color: var(--color-status-warn); }
.receipt__icon {
  flex: none; width: 20px; height: 20px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--type-meta); font-weight: var(--fw-semibold); line-height: 1;
}
.receipt--ok .receipt__icon { color: var(--color-status-ok); background: color-mix(in srgb, var(--color-status-ok) 16%, transparent); }
.receipt--fail .receipt__icon { color: var(--color-status-danger); background: color-mix(in srgb, var(--color-status-danger) 16%, transparent); }
.receipt--info .receipt__icon { color: var(--color-status-warn); background: color-mix(in srgb, var(--color-status-warn) 16%, transparent); }
.receipt__body { flex: 1; min-width: 0; }
.receipt__what { margin: 0; font-size: var(--type-body); font-weight: var(--fw-semibold); }
.receipt__detail { margin: var(--space-3xs) 0 0; font-size: var(--type-meta); color: var(--color-text-secondary); }
.receipt__meta { margin: var(--space-3xs) 0 0; font-size: var(--type-meta); color: var(--color-text-tertiary); }
.receipt__close {
  flex: none; background: none; border: none; color: var(--color-text-tertiary);
  cursor: pointer; font-size: var(--type-body); line-height: 1; padding: var(--space-3xs);
  margin: -4px -4px 0 0; border-radius: var(--radius-sm);
}
.receipt__close:hover { color: var(--color-text-primary); background: var(--color-bg-glass); }
@keyframes receipt-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* focus visibility — keyboard operators get the token ring everywhere */
.card a:focus-visible, .shell__page:focus-visible, .cost-line:focus-visible,
.mem-filter:focus-visible, .vmini a:focus-visible, .tbl a:focus-visible,
.receipt__close:focus-visible {
  outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-md);
}

@media (prefers-reduced-motion: reduce) {
  .ops-btn, .row > summary::after, .group > summary::after,
  .card, .metrics, .viz-card { transition: none; animation: none; }
  .spark__line { stroke-dasharray: none; animation: none; }
  .spark__area { opacity: 1; animation: none; }
  .live-pill--on .live-pill__orb { animation: none; }
  .card--skeleton::after, .skel { animation: none; }
  .receipt { animation: none; }
}
@media (max-width: 460px) {
  #ops-receipts { left: var(--space-sm); right: var(--space-sm); bottom: var(--space-sm); max-width: none; }
}

/* narrow screens: evidence wraps under the claim instead of truncating */
@media (max-width: 720px) {
  .row > summary, .row--flat, .group > summary { flex-wrap: wrap; }
  .row__evidence { white-space: normal; flex-basis: 100%; order: 3; }
  .row__claim { white-space: normal; }
  .group__sum { margin-left: 0; flex-basis: 100%; }
  .hero__tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .integ-strip { grid-template-columns: 1fr; }
  .hbar { grid-template-columns: minmax(90px, 120px) 1fr auto; }
  .vmini { flex-wrap: wrap; }
  .vmini__stat:first-of-type { margin-left: 0; }
  /* A nowrap plate cannot fit beside a ~350px map without clipping itself or
     covering its neighbours. Keep the numbered markers; the numbered rows
     below carry every fact — same information, legibly. */
  .map-pin__label { display: none; }
  dialog.onboard { width: calc(100vw - var(--space-md)); height: calc(100vh - var(--space-md)); }
}
@media (max-width: 460px) {
  .hero__tiles { grid-template-columns: 1fr 1fr; gap: var(--space-xs); }
  .ops-main { padding: var(--space-md) var(--space-sm) var(--space-2xl); }
  .shell__bar { padding: var(--space-xs) var(--space-sm); }
  .shell__indicator { padding: 0 var(--space-sm) var(--space-xs); }
  .shell__pages { padding: 0 var(--space-sm); }
}

/* The Part C `data-su-branded` block that stood here is DELETED (2026-08-27).
   It themed a mini-dashboard mock from raw sampled colours: the page took the
   reference's measured ground straight, which is how a yellow-accent reference
   produced a yellow page. Its replacement is the .bhp block at the foot of
   this file, which paints only from --bm-* properties resolved by
   js/brand-model.js and gives the accent no background role at all. */
/* the applied-facts chips reuse the tenancy recap chip anatomy */
.su-preview .su-recap__chips { margin-bottom: var(--space-sm); }

/* ── THE RESOLUTION MATRIX (2026-08-27) ──────────────────────────────────────
   The reach chip and the "What the buttons do" page. ACKNOWLEDGE-ONLY renders
   in the danger colour deliberately: it is not a neutral fact that a control
   cannot fix what it is pointing at, and the operator asked for it in red. */
.reach {
  display: inline-block; font-size: var(--type-meta); font-weight: var(--fw-bold);
  letter-spacing: var(--ls-wide); padding: 1px var(--space-2xs);
  border-radius: var(--radius-pill); white-space: nowrap; cursor: help;
  margin-left: var(--space-2xs);
}
.reach--bad  { color: var(--color-status-danger); background: var(--danger-bg); }
.reach--warn { color: var(--color-status-warn);   background: var(--warn-bg); }
.reach--ok   { color: var(--color-status-ok);     background: var(--ok-bg); }
.reach--idle { color: var(--color-text-secondary); background: var(--color-bg-glass); }

.mx__h {
  margin: var(--space-lg) 0 var(--space-3xs);
  font-size: var(--type-meta); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-wide); text-transform: uppercase;
}
.mx__h.reach--bad  { color: var(--color-status-danger); background: none; }
.mx__h.reach--warn { color: var(--color-status-warn);   background: none; }
.mx__h.reach--ok   { color: var(--color-status-ok);     background: none; }
.mx__h.reach--idle { color: var(--color-text-secondary); background: none; }
/* Six prose columns do not fit a table that sizes itself to its content, and
   the two that matter most (what the button does, what a real fix needs) were
   the ones pushed off the edge. Fixed layout with declared widths keeps every
   column on screen; .tbl-wrap still scrolls on a narrow viewport. */
.mx .tbl { table-layout: fixed; }
.mx .tbl td { vertical-align: top; }
.mx .tbl th:nth-child(1), .mx .tbl td:nth-child(1) { width: 16%; }
.mx .tbl th:nth-child(2), .mx .tbl td:nth-child(2) { width: 13%; }
.mx .tbl th:nth-child(3), .mx .tbl td:nth-child(3) { width: 15%; }
.mx .tbl th:nth-child(4), .mx .tbl td:nth-child(4) { width: 19%; }
.mx .tbl th:nth-child(5), .mx .tbl td:nth-child(5) { width: 18%; }
.mx .tbl th:nth-child(6), .mx .tbl td:nth-child(6) { width: 19%; }
/* break-word, never `anywhere`: `anywhere` splits DigitalOcean into
   "DigitalO / cean" in a narrow column, which reads as a rendering fault. */
.mx .tbl td, .mx .tbl th { overflow-wrap: break-word; }
/* Table cells elsewhere in this console hold short facts, so .t-2nd is clipped
   to one nowrap line there. This page's cells ARE the prose -- what the button
   does, what a real fix needs -- and a sentence ending in an ellipsis is the
   opposite of what it is for. Wrap in full, headers included. */
.mx .tbl th { white-space: normal; }
.mx .tbl .t-2nd { display: block; white-space: normal; overflow: visible; text-overflow: clip; }
/* A row carrying open alerts is the one the operator is actually standing in
   front of; it gets the marker, not the whole table. */
.mx .row--live > td:first-child { border-left: 3px solid var(--color-status-warn); }

/* ── THE HOME SURFACE AT REDUCED SCALE (2026-08-27) ──────────────────────────
   js/brand-home-preview.js. This block is NOT console chrome and deliberately
   does not use the console's design tokens: it is the TENANT product's Home,
   laid out in the product's own 1280x800 design frame and then transform-
   scaled to whatever width the card gives it. Console tokens here would mean
   the preview shrinks differently from the thing it previews, which is exactly
   the mockup problem this replaced. Every colour is a --bm-* custom property
   written by resolveBrandModel(); nothing in this block picks a colour.

   THE ONE LAW OF THIS BLOCK: --bm-accent paints CTAs, the active nav item,
   key figures and the focus ring. It never appears as a background of .bhp,
   .bhp-main, .bhp-rail or .bhp-body. Grep it: the accent's only background
   uses are .bhp-cta, .bhp-nav__item--on (at 16% through --bm-accent-soft),
   .bhp-badge and .bhp-pill--on. */
.bhp { --bhp-scale: 1; container-type: inline-size; }
.bhp__viewport {
  width: 100%; overflow: hidden; border-radius: var(--radius-lg);
  border: 1px solid var(--color-border-subtle);
  box-shadow: 0 18px 40px rgba(20, 16, 44, .14);
}
.bhp__frame {
  transform-origin: top left;
  display: grid; grid-template-columns: 232px 1fr;
  background: var(--bm-page, #0f1015);
  color: var(--bm-ink, #f4f6fb);
  font-family: var(--su-body-font, "Inter", system-ui, sans-serif);
  -webkit-font-smoothing: antialiased;
}

/* rail */
.bhp-rail {
  display: flex; flex-direction: column; gap: 28px; padding: 24px 20px;
  background: var(--bm-surface, rgba(255,255,255,.04));
  border-right: 1px solid var(--bm-border, rgba(255,255,255,.14));
}
.bhp-logo { display: flex; align-items: center; min-height: 56px; padding: 8px 10px; border-radius: 10px; }
.bhp-logo[data-plate="none"], .bhp-logo[data-plate="bare"] { background: transparent; padding: 8px 0; }
.bhp-logo[data-plate="light"] { background: #ffffff; }
.bhp-logo[data-plate="dark"]  { background: #14151b; }
/* The mark keeps its own aspect ratio and its own colours. No object-fit
   cover, no width+height pair that can disagree, no filter, ever. */
.bhp-logo__img {
  display: block; width: auto; height: auto;
  max-width: 100%; max-height: 44px; object-fit: contain;
}
.bhp-logo__fallback {
  display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%;
  background: var(--bm-accent, #059669); color: var(--bm-accent-on, #fff);
  font-size: 18px; font-weight: 600;
}
.bhp-nav { display: flex; flex-direction: column; gap: 4px; }
.bhp-nav__item {
  font-size: 15px; line-height: 1; padding: 11px 12px; border-radius: 8px;
  color: var(--bm-ink-muted, #94a3b8);
}
.bhp-nav__item--on {
  background: var(--bm-accent-soft, rgba(5,150,105,.16));
  color: var(--bm-accent, #059669); font-weight: 600;
}
.bhp-rail__foot {
  margin-top: auto; font-size: 12px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--bm-ink-muted, #94a3b8);
}

/* main */
.bhp-main { display: flex; flex-direction: column; min-width: 0; }
.bhp-topbar {
  display: flex; align-items: flex-start; justify-content: space-between;
  padding: 24px 32px 20px; border-bottom: 1px solid var(--bm-border, rgba(255,255,255,.14));
}
.bhp-topbar__title {
  margin: 0; font-size: 26px; line-height: 1.1; font-weight: 600;
  font-family: var(--su-heading-font, "Inter", system-ui, sans-serif);
  color: var(--bm-ink, #f4f6fb);
}
.bhp-topbar__crumbs { margin: 6px 0 0; font-size: 14px; color: var(--bm-ink-muted, #94a3b8); }
.bhp-badge {
  font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  padding: 5px 11px; border-radius: 999px;
  background: var(--bm-accent, #059669); color: var(--bm-accent-on, #fff);
}
.bhp-body { display: flex; flex-direction: column; gap: 20px; padding: 24px 32px 32px; min-width: 0; flex: 1; }
/* The last block of a Home fills the frame, the way the product's own Home
   does. A preview that leaves a third of the page empty is a preview of a
   different page. */
.bhp-body > :last-child { flex: 1 1 auto; min-height: 0; }

/* hero */
.bhp-hero {
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  padding: 24px 28px; border-radius: 14px;
  background: var(--bm-surface, rgba(255,255,255,.04));
  border: 1px solid var(--bm-border, rgba(255,255,255,.14));
}
.bhp-hero__label { margin: 0; font-size: 13px; letter-spacing: .06em; text-transform: uppercase; color: var(--bm-ink-muted, #94a3b8); }
.bhp-hero__value {
  margin: 6px 0 0; font-size: 46px; line-height: 1; font-weight: 700;
  font-family: var(--su-heading-font, "Inter", system-ui, sans-serif);
  color: var(--bm-ink, #f4f6fb);
}
.bhp-hero__sub { margin: 8px 0 0; font-size: 14px; color: var(--bm-ink-muted, #94a3b8); }

/* the CTA. Accent fill, contrast-chosen label. There is no second source. */
.bhp-cta {
  border: 0; cursor: default; white-space: nowrap;
  padding: 13px 22px; border-radius: 10px; font-size: 15px; font-weight: 600;
  background: var(--bm-accent, #059669); color: var(--bm-accent-on, #ffffff);
  font-family: inherit;
}
.bhp-cta--sm { padding: 8px 14px; font-size: 13px; border-radius: 8px; }

/* tiles */
.bhp-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.bhp-strip { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.bhp-tile {
  display: flex; flex-direction: column; gap: 6px; padding: 18px 20px; border-radius: 12px;
  background: var(--bm-surface, rgba(255,255,255,.04));
  border: 1px solid var(--bm-border, rgba(255,255,255,.14));
}
.bhp-tile__label { font-size: 12px; letter-spacing: .06em; text-transform: uppercase; color: var(--bm-ink-muted, #94a3b8); }
.bhp-tile__value {
  font-size: 30px; line-height: 1.05; font-weight: 700;
  font-family: var(--su-heading-font, "Inter", system-ui, sans-serif);
  color: var(--bm-ink, #f4f6fb);
}
.bhp-tile__value.bhp-accent-ink { color: var(--bm-accent, #059669); }
.bhp-tile__delta { font-size: 13px; color: var(--bm-ink-muted, #94a3b8); }

/* panels + table */
.bhp-panel {
  padding: 20px 24px; border-radius: 14px; min-width: 0;
  background: var(--bm-surface, rgba(255,255,255,.04));
  border: 1px solid var(--bm-border, rgba(255,255,255,.14));
}
.bhp-panel--tall { flex: 1; }
.bhp-panel__head { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.bhp-panel__title {
  margin: 0 0 4px; font-size: 18px; font-weight: 600;
  font-family: var(--su-heading-font, "Inter", system-ui, sans-serif);
  color: var(--bm-ink, #f4f6fb);
}
.bhp-split { display: grid; grid-template-columns: 1.35fr 1fr; gap: 16px; align-items: stretch; }
.bhp-detail { display: flex; flex-direction: column; gap: 12px; align-items: flex-start; }
.bhp-detail__meta { margin: 0; font-size: 14px; color: var(--bm-ink-muted, #94a3b8); }
.bhp-detail .bhp-tile { width: 100%; }
.bhp-table { width: 100%; border-collapse: collapse; margin-top: 12px; font-size: 15px; }
.bhp-table th {
  text-align: left; font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--bm-ink-muted, #94a3b8); font-weight: 600; padding: 0 0 10px;
}
.bhp-table td { padding: 12px 0; border-top: 1px solid var(--bm-border, rgba(255,255,255,.14)); color: var(--bm-ink, #f4f6fb); }
.bhp-table .bhp-num { text-align: right; font-variant-numeric: tabular-nums; }
.bhp-pill {
  font-size: 12px; font-weight: 600; padding: 3px 10px; border-radius: 999px;
  color: var(--bm-ink-muted, #94a3b8);
  border: 1px solid var(--bm-border, rgba(255,255,255,.14));
}
.bhp-pill--on {
  background: var(--bm-accent-soft, rgba(5,150,105,.16));
  color: var(--bm-accent, #059669); border-color: transparent;
}
/* a derived chip is readable but not editable: no hover invitation, and the
   reason still reachable through its title */
.su-recap__chip--ro { cursor: help; }

/* ── the spin-up's CHECKLIST · E3 (2026-09-03) ──────────────────────────
   Every step named before any of them runs, a spinner on the one running,
   a tick on the ones done, and on a failed one the sentence that says what
   to do next. Same honesty law as the progress lines above it: "current" is
   set only while that step's work is genuinely in flight. Colours are the
   console's own status tokens; nothing new. */
.su-steps { list-style: none; margin: 0 0 0 var(--space-md); padding: 0; display: flex; flex-direction: column; gap: var(--space-2xs); }
.su-step { display: flex; align-items: flex-start; gap: var(--space-xs); font-size: var(--type-meta); color: var(--color-text-secondary); animation: modalin var(--duration-medium) var(--ease-out); }
.su-step__mark {
  flex: none; width: 14px; height: 14px; margin-top: 2px; border-radius: 50%;
  border: 1.5px solid var(--color-border-default); box-sizing: border-box;
  display: grid; place-items: center; font-size: 10px; line-height: 1;
}
.su-step__text { display: flex; flex-direction: column; gap: 1px; }
.su-step__note:empty, .su-step__next:empty { display: none; }
.su-step__note { color: var(--color-text-tertiary, var(--color-text-secondary)); }
.su-step[data-state="current"] { color: var(--color-text); }
.su-step[data-state="current"] .su-step__mark {
  border-color: color-mix(in srgb, var(--color-accent) 30%, transparent);
  border-top-color: var(--color-accent);
  animation: su-step-spin 900ms linear infinite;
}
.su-step[data-state="done"] { color: var(--color-status-ok, var(--color-accent)); }
.su-step[data-state="done"] .su-step__mark { border-color: currentColor; background: currentColor; color: var(--color-bg-base); }
.su-step[data-state="done"] .su-step__mark::before { content: "✓"; }
.su-step[data-state="skipped"] { color: var(--color-status-warn, var(--color-text-secondary)); }
.su-step[data-state="skipped"] .su-step__mark { border-style: dashed; border-color: currentColor; }
.su-step[data-state="failed"] { color: var(--color-status-danger, #b3261e); }
.su-step[data-state="failed"] .su-step__mark { border-color: currentColor; color: currentColor; }
.su-step[data-state="failed"] .su-step__mark::before { content: "!"; font-weight: var(--fw-semibold); }
.su-step[data-state="failed"] .su-step__note { color: inherit; }
.su-step__next { color: var(--color-text); }
@keyframes su-step-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .su-step[data-state="current"] .su-step__mark { animation: none; border-color: var(--color-accent); }
}

/* ── an uploaded artefact comes off again · E5 ───────────────────────────
   One control per chip, before "That's everything". */
.su-upload__item { display: inline-flex; align-items: center; gap: 6px; }
.su-upload__remove {
  border: 0; background: transparent; color: var(--color-text-secondary); cursor: pointer;
  font: inherit; font-size: 14px; line-height: 1; padding: 0 2px; border-radius: 50%;
}
.su-upload__remove:hover { color: var(--color-status-danger, #b3261e); }
.su-upload__remove:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* ── the INTEGRATIONS step is a CHOICE per rail · E4 ─────────────────────
   Two options on every row, neither disabled: use the platform's own for now
   (default, with the one line that says what that means) or connect your own
   in Settings. A card an operator cannot act on is a dead card. */
.su-slot__choices { display: grid; gap: var(--space-2xs); margin-top: var(--space-xs); grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.su-slot__choice {
  display: flex; flex-direction: column; gap: 2px; text-align: left; cursor: pointer;
  font: inherit; color: var(--color-text-secondary);
  border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md);
  background: var(--color-bg-surface); padding: var(--space-xs) var(--space-sm);
  transition: border-color var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out);
}
.su-slot__choice b { font-size: var(--type-meta); color: var(--color-text); }
.su-slot__choice span { font-size: var(--type-meta); line-height: 1.4; }
.su-slot__choice:hover { border-color: color-mix(in srgb, var(--color-accent) 45%, transparent); }
.su-slot__choice:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.su-slot__choice--on {
  border-color: var(--color-accent);
  background: color-mix(in srgb, var(--color-accent) 8%, transparent);
  box-shadow: 0 0 0 1px var(--color-accent);
}

/* ── BRAND STUDIO, mounted inside the thread · E7 ────────────────────────
   The same .ba-stage the Brand Studio page uses, hosted in one chat turn so
   its panels swap in place with their own choreography. The stage rests on
   the thread's ground, not on a second card. */
.su-turn--studio { display: flex; flex-direction: column; gap: var(--space-sm); }
.su-studio { width: 100%; }
.su-studio .ba-stage { min-height: 240px; }
.su-studio__skip { display: flex; justify-content: flex-end; }

/* ── the vertical page's VOICE editors · E9 (js/vertical-voice.js) ───────
   What the spin-up wrote, editable in place through the same writers, one
   field at a time, saved on blur, with the outcome said beside the field. */
.vx { display: flex; flex-direction: column; gap: var(--space-sm); }
.vx__group {
  border: 1px solid var(--color-border-subtle); border-radius: var(--radius-lg);
  background: var(--color-bg-surface); padding: var(--space-sm) var(--space-md);
  display: flex; flex-direction: column; gap: var(--space-2xs, 8px);
}
.vx__group > h3 { margin: 0; font-size: var(--type-meta); text-transform: uppercase; letter-spacing: .02em; color: var(--color-text-secondary); font-weight: var(--fw-semibold); }
.vx__row { display: grid; gap: var(--space-2xs, 8px); grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); align-items: end; }
.vx__field { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.vx__field > span { font-size: var(--type-meta); color: var(--color-text-secondary); }
.vx__field > input {
  width: 100%; box-sizing: border-box; padding: 7px 9px;
  border: 1px solid var(--color-border-default); border-radius: var(--radius-sm, 6px);
  background: var(--color-bg-input, transparent); color: var(--color-text);
  font: inherit; font-size: var(--type-body, 14px);
}
.vx__field > input:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.vx__field > input[readonly] { color: var(--color-text-secondary); }
.vx__days { display: flex; flex-wrap: wrap; gap: var(--space-2xs, 8px); }
.vx__status { font-size: var(--type-meta); color: var(--color-text-secondary); min-height: 1.2em; }
.vx__status[data-tone="ok"] { color: var(--color-status-ok, var(--color-accent)); }
.vx__status[data-tone="error"] { color: var(--color-status-danger, #b3261e); }
.vx__status[data-tone="busy"] { color: var(--color-text); }
.vx__status:empty { display: none; }
.vx__compose { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.vx__compose > code { white-space: nowrap; font-family: var(--font-mono); font-size: var(--type-overline-size, 12px); background: var(--color-bg-glass); border-radius: var(--radius-sm); padding: 1px 6px; }
.vx__compose > input { flex: 1 1 140px; min-width: 120px; box-sizing: border-box; padding: 7px 9px; border: 1px solid var(--color-border-default); border-radius: var(--radius-sm, 6px); background: var(--color-bg-input, transparent); color: var(--color-text); font: inherit; font-size: var(--type-body, 14px); }
.vx__compose > input:focus-visible { outline: none; box-shadow: var(--focus-ring); }
