/* Self-hosted so the game needs no third-party request at boot — it runs in
   classrooms on unpredictable networks, and a blocked font host used to mean a
   flash of fallback type on a projector. Latin subsets, weight axis only:
   Archivo also ships a width axis and we deliberately do not load it (condensed
   type is the first thing to fail at the back of a room).

   Manrope has no italic cut at all, so <em> gets a synthetic oblique. That's
   fine for the handful of emphases in UI copy; don't lean on italics for
   anything load-bearing. */
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/archivo-latin-var.woff2") format("woff2");
}
@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("/fonts/manrope-latin-var.woff2") format("woff2");
}
@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/public-sans-latin-var.woff2") format("woff2");
}

/* Theme variables. Dark is the default; the other schemes override via
   [data-theme="…"] on <html>, cycled by the header button (app.js, SCHEMES).
   Four schemes: Ledger dark, Ledger light, Harbor (blue and white) and
   Sterling (silver with gold). Every scheme defines every token below, so a
   surface can never fall through to another scheme's value; `npm run
   contrast` checks each one.

   The palette is "Ledger" (docs/ui-overhaul-research.md): a leather-bound
   ledger book — cream paper, brass fixtures, fountain-pen ink. Chosen over a
   colder terminal look because the game is played in a classroom, often
   projected, and near-black surfaces wash out badly under room light.

   Every ink/accent/status colour clears WCAG AA (4.5:1) against the surface it
   sits on; every chart colour clears 3:1. Ratios are noted inline — if you
   change a value, recheck it.

   The chart series is the Okabe-Ito set, the most widely cited colourblind-safe
   categorical palette. It is deliberately independent of the surface palette:
   swap the ledger browns for something else and these should stay. */
:root {
  color-scheme: dark;
  --bg: #171310;
  --panel: #201a14;
  --panel-2: #2a2219;
  --line: #3d3226;
  --ink: #f0e6d6;        /* 13.94:1 on panel */
  --muted: #ab9c86;      /*  6.42:1 */
  --accent: #d69a4e;     /*  7.05:1  brass */
  --accent-ink: #1a1409; /*  7.48:1 on accent — text on brass-filled buttons */
  --good: #8fae5d;       /*  6.87:1  moss */
  --bad: #d46650;        /*  4.77:1  terracotta */
  --warn: #d9b23c;       /*  8.52:1  mustard */

  --header-grad-a: #241d16;
  --header-grad-b: #171310;
  --player-bg: #33291c;   /* ink 11.52:1 */
  --player-line: #4a3c28;
  --error-bg: #2e1a15;    /* ink 13.33:1 */
  --error-line: #5c3228;
  --hint-ink: #c4b49a;    /*  8.48:1 */
  --bar-from: #b8813f;    /*  5.13:1 */
  --rival-mark: #c0705a;  /*  4.68:1 */
  --captured-line: #4a6330;
  --badge-on-line: #4a6330;
  --badge-off-line: #6b5520;
  --overlay: rgba(12, 9, 6, 0.74);

  /* Chart series — Okabe-Ito, all >=3:1 on panel. */
  --viz-rev: #56b4e9;   /* sky blue       7.46:1 */
  --viz-cost: #d55e00;  /* vermillion     4.45:1 */
  --viz-unmet: #7d6f5a; /* neutral        3.52:1 */
  --viz-c1: #56b4e9;    /* sky blue       7.46:1 */
  --viz-c2: #e69f00;    /* orange         7.65:1 */
  --viz-c3: #009e73;    /* bluish green   5.03:1 */
  --viz-c4: #cc79a7;    /* reddish purple 5.63:1 */

  /* "Clean Room": precision over personality. Archivo carries the structure,
     Manrope reads long, Public Sans holds the figures — it was built for the US
     Web Design System's civic data tables and has real tabular numerals, which
     Archivo's own support for is undocumented. Hence three faces, not two. */
  --font-display: "Archivo", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-body: "Manrope", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-figures: "Public Sans", ui-sans-serif, system-ui, -apple-system, sans-serif;

  /* ---- Type scale ----------------------------------------------------------
     Six steps, one per genuine role. This replaced 21 ad-hoc sizes (including
     half-pixel nudges like 10.5 and 13.5) that produced six near-identical
     levels between 10px and 13px — nominally a hierarchy, but the eye read it
     as one blur.

     The floor is 12px on purpose. The game is played in classrooms and often
     projected, and the 9-11px tier was unreadable past the front row. Density
     comes from disciplined scales and hairline dividers, not smaller type. */
  --fs-xs: 12px;    /* labels, chart legends, badges, fine print */
  --fs-sm: 13px;    /* secondary body, notes, table cells */
  --fs-md: 15px;    /* body, chat prose */
  --fs-lg: 17px;    /* emphasised prose — narration, scene-setting beats */
  --fs-xl: 20px;    /* section headings, big stat values */
  --fs-2xl: 26px;   /* page title */

  /* ---- Spacing scale ---- (replaced 17 ad-hoc values) */
  --sp-0: 2px;   /* hairline gaps inside chips and badges */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;

  /* ---- Radius scale ---- (replaced 9 ad-hoc values) */
  --radius-1: 4px;     /* inputs, chips, small controls */
  --radius-2: 8px;     /* stat tiles, cards */
  --radius-3: 12px;    /* panels, modals, chat bubbles */
  --radius-round: 999px;

  /* ---- Motion ----------------------------------------------------------------
     Four durations and three curves, and nothing moves on any other value.
     The standard curve is the default: it reads as considered where linear
     reads as cheap. The overshoot is spent on exactly one thing, the commit
     button, because it is the one decisive action of a turn; everything else
     settles without bouncing. */
  --dur-1: 120ms;   /* hover, press */
  --dur-2: 220ms;   /* the default: state changes, chat lines arriving */
  --dur-3: 600ms;   /* number roll-ups, long enough to read as counting */
  --dur-4: 1000ms;  /* the delta pulse, a breath rather than a blink */
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
  --ease-overshoot: cubic-bezier(0.34, 1.56, 0.64, 1);
  /* The tint a tile pulses to when its number moves, and the tint it holds
     instead when the player has turned motion off. Mixed from the accent so
     the palette can change under it. */
  --pulse: color-mix(in srgb, var(--accent) 32%, transparent);
  --pulse-held: color-mix(in srgb, var(--accent) 16%, transparent);

  /* ---- The tabular face -----------------------------------------------------
   Numbers should read as measured, not narrated. The rule: if a number sits
   inside a sentence the arbiter wrote, it stays in the body face; if the number
   IS the element, it gets the tabular face.

   So this list is deliberately short — headline figures and table cells only.
   The chat column never appears here: fixed-width digits bleeding into prose
   read worse, not better. */
.stat .v:not(.stat-toggle),
.est .v,
.pl-big,
.pl-was,
.val-v,
.val-total .val-v,
.cap-rowline output,
.charts-table th,
.charts-table td,
.cost-row span:last-child,
.turn-cash {
  font-family: var(--font-figures);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

/* ---- Elevation -----------------------------------------------------------
     Depth used to be carried entirely by 1px borders, so every surface sat at
     the same height and nothing was foreground. On a dark ground a lighter
     surface reads as closer, which is what does the work here; the inset
     top-edge highlight is the catch-light that used to be a bevel. Keep it
     between .04 and .08 or it starts to look like a plastic button.

     Real shadows are reserved for things genuinely floating above the page
     (modals, tooltips) — they barely register against a near-black ground. */
  --elev-hi: rgba(255, 255, 255, 0.06);
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-2: 0 4px 12px rgba(0, 0, 0, 0.45);
  --shadow-3: 0 12px 32px rgba(0, 0, 0, 0.5);
}

:root[data-theme="light"] {
  color-scheme: light;
  --bg: #f7f0e3;         /* cream paper */
  --panel: #fffcf5;
  --panel-2: #f0e6d2;
  --line: #ded0b4;
  --ink: #2b2013;        /* 15.54:1 on panel */
  --muted: #786a55;      /*  5.13:1 */
  --accent: #9c5f26;     /*  5.03:1 */
  --accent-ink: #fffcf5; /*  5.03:1 on accent */
  --good: #5c7a3d;       /*  4.76:1 */
  --bad: #a8402c;        /*  5.97:1 */
  --warn: #8f6715;       /*  4.98:1 */

  --header-grad-a: #fffdf8;
  --header-grad-b: #f5ecdc;
  --player-bg: #f0e2c8;   /* ink 12.45:1 */
  --player-line: #dcc9a4;
  --error-bg: #f9e5df;    /* ink 13.12:1 */
  --error-line: #e0b5a8;
  --hint-ink: #5e523f;    /*  7.44:1 */
  --bar-from: #b57c34;    /*  3.48:1 */
  --rival-mark: #b5543a;  /*  4.77:1 */
  --captured-line: #a8bd8a;
  --badge-on-line: #a8bd8a;
  --badge-off-line: #d4c088;
  --overlay: rgba(43, 32, 19, 0.45);

  /* Okabe-Ito darkened for paper; hues preserved, all >=3:1 on panel. */
  --viz-rev: #0072b2;   /* blue           5.06:1 */
  --viz-cost: #b03a00;  /* vermillion     5.94:1 */
  --viz-unmet: #94876a; /* neutral        3.45:1 */
  --viz-c1: #0f7ea8;    /* sky blue       4.48:1 */
  --viz-c2: #b06e00;    /* orange         4.04:1 */
  --viz-c3: #007a5a;    /* bluish green   5.21:1 */
  --viz-c4: #a1447a;    /* reddish purple 5.66:1 */

  /* On paper, depth comes from a contact shadow rather than a catch-light. */
  --elev-hi: rgba(255, 255, 255, 0.7);
  --shadow-1: 0 1px 2px rgba(74, 58, 32, 0.09);
  --shadow-2: 0 4px 12px rgba(74, 58, 32, 0.10);
  --shadow-3: 0 12px 32px rgba(74, 58, 32, 0.14);
}

/* "Harbor": blue and white. White surfaces on a cool blue-grey ground, navy
   ink, a marine blue for the accent. The chart series is the same darkened
   Okabe-Ito as the light ledger, because data colours are independent of
   the chrome by design. */
:root[data-theme="harbor"] {
  color-scheme: light;
  --bg: #e9eff6;
  --panel: #ffffff;
  --panel-2: #eef3f9;
  --line: #c7d4e2;
  --ink: #14243a;        /* navy */
  --muted: #4d5f76;
  --accent: #1d5ca3;     /* marine blue */
  --accent-ink: #ffffff;
  --good: #2a7643;
  --bad: #b33e2c;
  --warn: #7f5d0c;

  --header-grad-a: #ffffff;
  --header-grad-b: #e4ecf5;
  --player-bg: #dae7f5;
  --player-line: #b7cde5;
  --error-bg: #fbe7e2;
  --error-line: #e4b7ad;
  --hint-ink: #3d4f68;
  --bar-from: #2f6fbf;
  --rival-mark: #b5543a;
  --captured-line: #9fc4a6;
  --badge-on-line: #9fc4a6;
  --badge-off-line: #d9c48a;
  --overlay: rgba(20, 36, 58, 0.45);

  --viz-rev: #0072b2;
  --viz-cost: #b03a00;
  --viz-unmet: #8e94a0;
  --viz-c1: #0f7ea8;
  --viz-c2: #b06e00;
  --viz-c3: #007a5a;
  --viz-c4: #a1447a;

  --elev-hi: rgba(255, 255, 255, 0.8);
  --shadow-1: 0 1px 2px rgba(20, 36, 58, 0.10);
  --shadow-2: 0 4px 12px rgba(20, 36, 58, 0.12);
  --shadow-3: 0 12px 32px rgba(20, 36, 58, 0.16);
}

/* "Sterling": silver and grey with gold. Graphite surfaces, silver-white
   ink, gold for the accent and the commit button. Dark, so it takes the
   dark ledger's chart series and its catch-light elevation. */
:root[data-theme="sterling"] {
  color-scheme: dark;
  --bg: #1a1c1f;
  --panel: #25282c;
  --panel-2: #30343a;
  --line: #474c54;
  --ink: #e9ebee;        /* silver-white */
  --muted: #a8aeb7;
  --accent: #d6b451;     /* gold */
  --accent-ink: #1c1600;
  --good: #8cc47f;
  --bad: #e37a66;
  --warn: #e6c65b;

  --header-grad-a: #2b2e33;
  --header-grad-b: #1a1c1f;
  --player-bg: #363a41;
  --player-line: #4c525b;
  --error-bg: #3a2825;
  --error-line: #6a3d36;
  --hint-ink: #c3c8cf;
  --bar-from: #b9963a;
  --rival-mark: #c8836f;
  --captured-line: #4e6b45;
  --badge-on-line: #4e6b45;
  --badge-off-line: #6e5d24;
  --overlay: rgba(10, 11, 13, 0.72);

  --viz-rev: #56b4e9;
  --viz-cost: #d55e00;
  --viz-unmet: #7f8590;
  --viz-c1: #56b4e9;
  --viz-c2: #e69f00;
  --viz-c3: #009e73;
  --viz-c4: #cc79a7;

  --elev-hi: rgba(255, 255, 255, 0.07);
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-2: 0 4px 12px rgba(0, 0, 0, 0.45);
  --shadow-3: 0 12px 32px rgba(0, 0, 0, 0.5);
}

* { box-sizing: border-box; }

/* ---- Elevation ------------------------------------------------------------
   Raised tiles catch a light from above. This is one rule rather than a
   box-shadow repeated across thirty component blocks, so the whole system
   moves together — and so a component that genuinely needs a different
   treatment can just set box-shadow and win on cascade order.

   The pairing is deliberate: the inset highlight does the work on dark (where
   a drop shadow barely registers against a near-black ground), the contact
   shadow does it on light. Both tokens are themed, so each surface gets the
   one that reads. */
.stat,
.segment,
.rival,
.insight,
.est,
.chart-card,
.charts-table,
.product-card,
.confirm-item,
.org-fn,
.cap {
  box-shadow: inset 0 1px 0 var(--elev-hi), var(--shadow-1);
}

html, body { height: 100%; margin: 0; }

body {
  background: var(--bg);
  color: var(--ink);
  font: var(--fs-md)/1.6 var(--font-body);
  display: flex;
  flex-direction: column;
}

header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-3) var(--sp-5);
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, var(--header-grad-a), var(--header-grad-b));
}
header h1 {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: 600;
  font-size: var(--fs-2xl);
  margin: 0;
  letter-spacing: 0.2px;
}
.header-meta { display: flex; align-items: center; gap: var(--sp-3); }
/* The scheme switcher: a swatch in the current accent and the scheme's name,
   so two schemes can be compared by clicking back and forth. */
#theme-toggle { display: inline-flex; align-items: center; gap: var(--sp-2); }
.theme-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--accent); border: 1px solid var(--line); flex-shrink: 0; }
.theme-name { font-size: var(--fs-sm); }

.badge {
  font-size: var(--fs-xs);
  padding: var(--sp-0) var(--sp-2);
  border-radius: var(--radius-round);
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--muted);
}
.badge.on { color: var(--good); border-color: var(--badge-on-line); }
.badge.off { color: var(--warn); border-color: var(--badge-off-line); }
.badge.subtle { opacity: 0.6; }

button {
  cursor: pointer;
  font: inherit;
  border-radius: var(--radius-2);
  border: 1px solid var(--line);
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
  padding: var(--sp-2) var(--sp-4);
}
button.ghost { background: transparent; color: var(--ink); }
button.icon { padding: var(--sp-2) var(--sp-3); line-height: 1; }
button:disabled { opacity: 0.5; cursor: default; }

main {
  flex: 1;
  display: grid;
  /* Half chat, half dashboard (Jul 2026): the charts earn the real estate. */
  grid-template-columns: 1fr 1fr;
  gap: 0;
  min-height: 0;
}
/* On narrower windows the panel falls back to a fixed rail so the chat
   stays usable; below 820px everything stacks (see the media query below). */
@media (max-width: 1200px) {
  main { grid-template-columns: 1fr 420px; }
}

/* ---- Chat / log ---- */
.chat { display: flex; flex-direction: column; min-height: 0; padding: var(--sp-3) var(--sp-5) var(--sp-4); }

/* ---- Charts ---- */
button.mini { font-size: var(--fs-xs); font-weight: 600; padding: var(--sp-0) var(--sp-2); color: var(--muted); border-radius: var(--radius-2); }
button.mini:hover { color: var(--ink); border-color: var(--muted); }
.chart-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius-3); padding: var(--sp-2) var(--sp-3) var(--sp-2); }
/* In the side panel, chart cards stack vertically on the panel-2 surface. */
.tab-pane .chart-card { background: var(--panel-2); margin-bottom: var(--sp-2); }
.chart-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); margin-bottom: var(--sp-0); }
.chart-head h4 { margin: 0; font-size: var(--fs-xs); font-weight: 600; color: var(--muted); letter-spacing: 0.2px; }
.chart-legend { display: flex; gap: var(--sp-2); font-size: var(--fs-xs); color: var(--muted); white-space: nowrap; }
.chart-legend span { display: inline-flex; align-items: center; gap: var(--sp-1); }
.chart-legend .sw { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.sw-rev, .sw-sold { background: var(--viz-rev); }
.sw-cost { background: var(--viz-cost); }
.sw-unmet { background: var(--viz-unmet); }
.sw-c1 { background: var(--viz-c1); }
.sw-c2 { background: var(--viz-c2); }
.sw-c3 { background: var(--viz-c3); }
.sw-c4 { background: var(--viz-c4); }
.chart-body svg { display: block; width: 100%; height: auto; }
.chart-empty { color: var(--muted); font-size: var(--fs-xs); text-align: center; padding: var(--sp-6) 0; }

.chart-tip {
  position: fixed;
  z-index: 60;
  pointer-events: none;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  padding: var(--sp-2) var(--sp-2);
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--ink);
  box-shadow: var(--shadow-2);
  max-width: 220px;
}
.chart-tip.hidden { display: none; }
/* Generic hide (product card, planner subnote, …). Scoped .hidden rules above
   and below predate this and are kept for clarity. */
.hidden { display: none !important; }
.chart-tip .tip-q { color: var(--muted); font-weight: 600; }

.charts-table { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius-3); padding: var(--sp-2) var(--sp-3); overflow-x: auto; }
.charts-table.hidden { display: none; }
.charts-table table { border-collapse: collapse; width: 100%; font-size: var(--fs-xs); }
.charts-table th, .charts-table td { text-align: right; padding: var(--sp-1) var(--sp-2); font-variant-numeric: tabular-nums; }
.charts-table th { color: var(--muted); font-weight: 600; font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.4px; }
.charts-table th:first-child, .charts-table td:first-child { text-align: left; }
.charts-table tr + tr td { border-top: 1px solid var(--line); }
.charts-table .neg { color: var(--bad); }
.log {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding-right: var(--sp-2);
}
.msg { max-width: 80%; padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-3); white-space: pre-wrap; }
/* Scene-setting beats (the intro, endings): a title card, not a footnote.
   Deliberately not italic — it should read like the world, not an aside. */
.msg.system {
  align-self: center;
  max-width: 92%;
  width: 92%;
  background: linear-gradient(180deg, var(--panel), transparent);
  border: 1px solid var(--line);
  border-radius: var(--radius-3);
  color: var(--ink);
  text-align: left;
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: var(--fs-lg);
  line-height: 1.65;
}
.msg.player { align-self: flex-end; background: var(--player-bg); border: 1px solid var(--player-line); }
.msg.engine {
  align-self: flex-start;
  background: var(--panel);
  border: 1px solid var(--line);
  font-size: var(--fs-md);
  line-height: 1.65;
}
.msg.error { align-self: center; background: var(--error-bg); border: 1px solid var(--error-line); color: var(--bad); }
.msg .intel { margin-top: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-2); font-size: var(--fs-sm); line-height: 1.5; }
/* Clues and reality checks read as tinted pills so they stand apart from prose. */
.msg .intel .clue,
.msg .intel .reality {
  border-radius: var(--radius-3);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid;
}
.msg .intel .clue {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 35%, transparent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.msg .intel .reality {
  color: var(--warn);
  border-color: color-mix(in srgb, var(--warn) 35%, transparent);
  background: color-mix(in srgb, var(--warn) 10%, transparent);
}

/* ---- The standing plan (moves stacked for this quarter) ---- */
/* Anchored at the top of the chat column so the pending plan never scrolls away. */
.plan-bar {
  margin-bottom: var(--sp-3);
  background: var(--panel);
  border: 1px dashed var(--accent);
  border-radius: var(--radius-3);
  padding: var(--sp-2) var(--sp-3);
}
.plan-bar.empty { border-color: var(--line); }
.plan-bar.empty #plan-clear { display: none; }
.plan-head { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.plan-title {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: 600;
  font-size: var(--fs-sm);
}
.plan-outlay { flex: 1; color: var(--muted); font-size: var(--fs-xs); }
.plan-items { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.plan-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  font-size: var(--fs-xs);
  padding: var(--sp-0) var(--sp-2);
  border-radius: var(--radius-round);
  background: var(--panel-2);
  border: 1px solid var(--line);
}
/* The × that removes one staged move from the plan. */
.chip-x {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  width: 14px;
  height: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: var(--muted);
  font-size: var(--fs-sm);
  line-height: 1;
  font-weight: 600;
}
.chip-x:hover { color: var(--bad); }

.composer { display: flex; gap: var(--sp-2); margin-top: var(--sp-3); }
.composer-btns { display: flex; flex-direction: column; gap: var(--sp-2); }
.composer-btns button { white-space: nowrap; }

/* Dictation mic, tucked into the input's corner. */
.input-wrap { flex: 1; position: relative; display: flex; }
.input-wrap textarea { flex: 1; padding-right: 42px; }
.mic {
  position: absolute;
  right: 8px;
  bottom: 8px;
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: 50%;
  background: transparent;
  border: 1px solid var(--line);
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
}
.mic:hover { color: var(--ink); border-color: var(--accent); }
.mic.hidden { display: none; }
.mic.listening {
  background: var(--bad);
  border-color: var(--bad);
  /* The ground colour, not white: it themes correctly and reads better on
     terracotta in both modes (5.1:1 dark, 5.6:1 light, vs 3.6:1 for white). */
  color: var(--bg);
  animation: mic-pulse 1.4s ease-out infinite;
}
@keyframes mic-pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--bad) 45%, transparent); }
  70% { box-shadow: 0 0 0 9px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.composer textarea {
  flex: 1;
  resize: none;
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--ink);
  border-radius: var(--radius-3);
  padding: var(--sp-3) var(--sp-3);
  font: inherit;
}
.composer textarea:focus { outline: 1px solid var(--accent); }
/* Left padding keeps the hint clear of the fixed tutorial button. */
.hint { color: var(--muted); font-size: var(--fs-sm); margin: var(--sp-2) var(--sp-0) 0; padding-left: 96px; min-height: 34px; }
.hint em { color: var(--hint-ink); font-style: normal; background: var(--panel-2); padding: var(--sp-0) var(--sp-2); border-radius: var(--radius-2); }

/* ---- State panel ---- */
.panel {
  border-left: 1px solid var(--line);
  background: var(--panel);
  padding: var(--sp-4);
  overflow-y: auto;
}
.panel h3 {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: 600;
  font-size: var(--fs-md);
  letter-spacing: 0.2px;
  color: var(--ink);
  margin: var(--sp-5) 0 var(--sp-1);
}
.panel-note { color: var(--muted); font-size: var(--fs-xs); line-height: 1.45; margin: 0 0 var(--sp-2); }
.turn-row { margin-bottom: var(--sp-3); display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); }
.turn-cash { cursor: help; text-align: right; }
.turn-cash .k { color: var(--muted); font-size: var(--fs-xs); border-bottom: 1px dotted var(--muted); }
.turn-cash .v { font-weight: 600; font-size: var(--fs-md); margin-left: var(--sp-1); }

/* ---- Sidebar tabs ---- */
/* Pinned to the top of the panel's scroll area, so switching tabs never means
   scrolling back up. The solid background masks content sliding underneath. */
.tabs {
  display: flex;
  gap: var(--sp-0);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--sp-3);
  position: sticky;
  /* -16px cancels the panel's top padding so the strip pins flush with the
     visible top edge instead of hovering a padding-gap below it. */
  top: calc(var(--sp-4) * -1);
  z-index: 6;
  background: var(--panel);
  padding-top: var(--sp-1);
}
.tabs button {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  color: var(--muted);
  font-size: var(--fs-xs); /* six tabs now — "Competitors" has to fit on one line */
  font-weight: 600;
  padding: var(--sp-2) var(--sp-0) var(--sp-2);
  white-space: nowrap;
}

/* The sprite itself is markup, never painted. */
.icon-sprite { display: none; }

/* Icons take their colour from the button, so the active/hover states below
   already cover them and nothing needs a second colour rule. They are
   decorative: every tab keeps its text label, and the SVG is aria-hidden, so
   the icon is never the only thing carrying the meaning. */
.tab-ic {
  width: 20px;
  height: 20px;
  fill: currentColor;
  flex: none;
}
.tabs button:hover { color: var(--ink); }
.tabs button.active { color: var(--ink); border-bottom-color: var(--accent); }
.tab-pane { display: none; }
.tab-pane.active { display: block; }
.tab-pane > h3:first-child { margin-top: var(--sp-1); }
.pane-btn { margin-top: var(--sp-3); }
.pane-legend, .canvas-legend { margin-bottom: var(--sp-1); }

/* Customers tab */
.segments { display: flex; flex-direction: column; gap: var(--sp-2); }
.segment { background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--radius-2); padding: var(--sp-2) var(--sp-3); font-size: var(--fs-sm); cursor: help; }
.segment .segment-name { font-weight: 600; }
.segment .segment-meta { color: var(--muted); font-size: var(--fs-xs); margin-top: var(--sp-0); }
/* How well the watch is aimed at a group: a short bar and a plain-English read.
   Deliberately not a number — it is coarsened by research depth, and a decimal
   would promise a precision the player has not bought yet. */
.segment .segment-fit { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-1); }
.segment .segment-fit .bar { flex: 0 0 56px; height: 4px; border-radius: var(--radius-1); background: var(--line); overflow: hidden; }
.segment .segment-fit .bar span { display: block; height: 100%; background: var(--viz-c1); }
.segment .segment-fit em { color: var(--muted); font-size: var(--fs-xs); font-style: normal; }

/* Costs tab */
.margin-box {
  display: flex;
  /* Bottom-align so the − and = operators sit on the same line as the numbers
     (the labels above the numbers vary in height; the value row doesn't). */
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--sp-2);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  padding: var(--sp-3);
}
.margin-cell .k { display: block; font-size: var(--fs-xs); color: var(--muted); white-space: nowrap; }
.margin-cell .v { display: block; font-size: var(--fs-md); font-weight: 600; margin-top: var(--sp-0); line-height: 1.35; }
.margin-cell .v small { font-weight: 500; color: var(--muted); }
.margin-result { margin-left: auto; text-align: right; }
.margin-op { color: var(--muted); font-weight: 600; font-size: var(--fs-md); line-height: 1.35; padding-bottom: var(--sp-0); }
.margin-note { flex-basis: 100%; margin: var(--sp-1) 0 0; }
.cost-structure { display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--fs-sm); }
.cost-row { display: flex; justify-content: space-between; gap: var(--sp-2); }
.cost-row span:first-child { color: var(--muted); }
.cost-row span:last-child { font-variant-numeric: tabular-nums; }
.cost-row.cost-total { border-top: 1px solid var(--line); padding-top: var(--sp-1); margin-top: var(--sp-0); font-weight: 600; }
.cost-row.cost-total span:first-child { color: var(--ink); }

/* Production tab */
.utilization { margin-top: var(--sp-3); font-size: var(--fs-sm); }
.utilization .cap-head { margin-bottom: var(--sp-0); }
.utilization .panel-note { margin-top: var(--sp-2); }

/* Capability ceiling marker (how far investment lets the level go). */
.bar { position: relative; }
.ceiling-mark {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 2px;
  margin-left: -1px;
  background: var(--warn);
  cursor: help;
}

/* ---- Capability planner (Capabilities tab) ---- */
/* Grey/dashed = committed last quarter; accent = provisional this quarter. */
.planner-pl { margin-bottom: var(--sp-3); }
.pl-strip {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  padding: var(--sp-2) var(--sp-3);
}
.pl-term label { display: block; font-size: var(--fs-xs); color: var(--muted); }
.pl-big {
  display: block;
  font-size: var(--fs-md);
  font-weight: 600;
  margin-top: var(--sp-0);
  font-variant-numeric: tabular-nums;
}
.pl-big.changed { color: var(--accent); }
.pl-big.good { color: var(--good); }
.pl-big.bad { color: var(--bad); }
.pl-was { display: block; font-size: var(--fs-xs); color: var(--muted); min-height: 13px; font-variant-numeric: tabular-nums; }
.pl-op { align-self: center; color: var(--muted); font-weight: 600; }
.pl-price { display: flex; align-items: center; gap: var(--sp-0); margin-top: var(--sp-0); }
.pl-price .cur { font-weight: 600; color: var(--muted); }
.pl-price button {
  width: 22px;
  height: 22px;
  padding: 0;
  border-radius: var(--radius-2);
  border: 1px solid var(--line);
  background: none;
  color: var(--ink);
  font-size: var(--fs-sm);
  line-height: 1;
}
.pl-price button:hover { border-color: var(--accent); color: var(--accent); }
.pl-price input {
  width: 5ch;
  padding: 0 var(--sp-0);
  text-align: center;
  font-weight: 600;
  font-size: var(--fs-md);
  background: transparent;
  border: none;
  border-bottom: 1px dashed var(--muted);
  border-radius: 0;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.pl-price input:focus { outline: none; border-bottom-color: var(--accent); }
.pl-chip {
  display: inline-block;
  font-size: var(--fs-xs);
  font-weight: 600;
  padding: 0 var(--sp-2);
  border-radius: var(--radius-round);
  margin-left: var(--sp-1);
  font-variant-numeric: tabular-nums;
}
.pl-chip.save { background: color-mix(in srgb, var(--good) 18%, transparent); color: var(--good); }
.pl-chip.rise { background: color-mix(in srgb, var(--bad) 18%, transparent); color: var(--bad); }
.pl-side {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--muted);
}
.pl-side .staged { color: var(--accent); font-weight: 600; }
.pl-subnote { margin-top: var(--sp-2); }

.plancard {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  padding: var(--sp-3);
  font-size: var(--fs-sm);
}
.plancard .contrib { font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.plancard .contrib s { color: var(--muted); margin-right: var(--sp-0); }
.plancard .contrib b { font-weight: 600; }
.plancard .contrib b.changed { color: var(--accent); }
.plancard .contrib .unit { color: var(--muted); font-size: var(--fs-xs); }
.plan-chart svg { display: block; width: 100%; height: auto; margin: var(--sp-0) 0 var(--sp-0); }
/* Level curves accept a drag: grab the dot (or anywhere on the plot) and pull. */
.plan-chart.draggable { cursor: grab; touch-action: none; }
.plan-chart.draggable:active { cursor: grabbing; }

/* ---- Supply chain tab: cost per unit + investment rows ---- */
.bom { display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--fs-sm); margin-bottom: var(--sp-4); }
.bom .bom-row { cursor: help; }
.bom .bom-cap { color: var(--muted); font-size: var(--fs-xs); }
.bom .changed { color: var(--accent); font-weight: 600; }
.bom .save { color: var(--good); }
.cap-rowline { display: flex; justify-content: space-between; align-items: baseline; margin-top: var(--sp-2); gap: var(--sp-2); }
.cap-rowline label { font-size: var(--fs-xs); font-weight: 600; }
.cap-rowline label em { font-style: normal; font-weight: 400; color: var(--muted); font-size: var(--fs-xs); }
.cap-rowline output { font-size: var(--fs-sm); font-weight: 600; font-variant-numeric: tabular-nums; }
.cap-rowline output .was { color: var(--muted); font-weight: 400; font-size: var(--fs-xs); }
.cap-rowline output .spend { color: var(--accent); }
.cap-rowline output.changed { color: var(--accent); }

.plancard input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  /* Match the chart's plot area (padL 34 / padR 10 of a 260-wide viewBox) so
     the thumb position lines up with the chart's x-axis — the ceiling line
     sits directly above where the slider actually stops. */
  display: block;
  width: 83.08%;
  margin: var(--sp-0) 0 0 13.08%;
  height: 20px;
  background: transparent;
  --pct: 0%;
  cursor: pointer;
}
.plancard input[type="range"]::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: var(--radius-1);
  background: linear-gradient(90deg, var(--accent) var(--pct), var(--bg) var(--pct));
  border: 1px solid var(--line);
}
.plancard input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--panel);
  box-shadow: var(--shadow-1);
  margin-top: -6px;
}
.plancard input[type="range"]::-moz-range-track {
  height: 6px;
  border-radius: var(--radius-1);
  background: var(--bg);
  border: 1px solid var(--line);
}
.plancard input[type="range"]::-moz-range-progress { height: 6px; border-radius: var(--radius-1); background: var(--accent); }
.plancard input[type="range"]::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--panel);
}
.plancard input[type="range"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-1); }

.stepper { display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-1); }
.stepper button {
  width: 30px;
  height: 26px;
  padding: 0;
  border-radius: var(--radius-2);
  border: 1px solid var(--line);
  background: none;
  color: var(--ink);
  font-size: var(--fs-md);
  line-height: 1;
}
.stepper button.plus { font-weight: 700; }
.stepper button:hover:not(:disabled) { border-color: var(--muted); }
.stepper button:disabled { opacity: 0.35; cursor: default; }
.ceilbar {
  flex: 1;
  height: 7px;
  border-radius: var(--radius-1);
  background: var(--bg);
  border: 1px solid var(--line);
  overflow: hidden;
  display: flex;
  cursor: help;
}
.ceilbar .lock { background: var(--bar-from); height: 100%; opacity: 0.55; }
.ceilbar .new {
  height: 100%;
  background: repeating-linear-gradient(-45deg, var(--accent), var(--accent) 3px, transparent 3px, transparent 6px);
}
.cap-info { margin: var(--sp-2) 0 0; font-size: var(--fs-xs); color: var(--muted); }
.cap-info b { color: var(--ink); font-variant-numeric: tabular-nums; }
.cap-info .save { color: var(--good); font-variant-numeric: tabular-nums; }

/* Marketing / production mini-planners (same idiom as the capability cards). */
.mini-planner {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  padding: var(--sp-3);
  margin-top: var(--sp-3);
  font-size: var(--fs-sm);
}
.mini-planner .cap-rowline:first-child { margin-top: 0; }
.prod-ctl { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-1); }
.prod-ctl input {
  flex: 1;
  min-width: 0;
  padding: var(--sp-1) var(--sp-2);
  font: inherit;
  font-variant-numeric: tabular-nums;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  color: var(--ink);
}
.prod-ctl input:focus { outline: none; border-color: var(--accent); }
.prod-ctl .unit { font-size: var(--fs-xs); color: var(--muted); }
.prod-ctl button.active { border-color: var(--muted); color: var(--ink); background: var(--panel-2); }

/* Generated imagery: the product shot and rival thumbnails. */
.product-card { margin-bottom: var(--sp-3); }
.product-card img {
  /* Never crop the device: `contain` letterboxes instead, and the studio
     backdrop in the renders makes the bars read as part of the shot. */
  display: block;
  width: 100%;
  max-height: 260px;
  object-fit: contain;
  background: var(--panel-2);
  border-radius: var(--radius-3);
  border: 1px solid var(--line);
}
.product-card .panel-note { margin-top: var(--sp-2); }
.rival { display: flex; align-items: center; gap: var(--sp-3); }
.rival-body { min-width: 0; flex: 1; }
.rival-thumb {
  width: 46px;
  height: 46px;
  object-fit: cover;
  border-radius: var(--radius-2);
  border: 1px solid var(--line);
  flex-shrink: 0;
}
.rival-thumb:not([src]) { display: none; }
.turn-label {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: var(--fs-xl);
  font-weight: 600;
}

.stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
.stat { background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--radius-2); padding: var(--sp-2) var(--sp-3); cursor: help; }
.stat .k { display: block; font-size: var(--fs-xs); color: var(--muted); }
/* Dotted underline marks anything with a hover explanation. */
.stat .k, .cap-head .cap-name {
  width: fit-content;
  border-bottom: 1px dotted var(--muted);
  padding-bottom: var(--sp-0);
}
.cap-head .cap-name { cursor: help; }
.stat .v { display: block; font-size: var(--fs-md); font-weight: 600; margin-top: var(--sp-0); }
.v.good { color: var(--good); }
.v.bad { color: var(--bad); }

.pending-section { margin-top: var(--sp-4); }
.pending-section.hidden { display: none; }
.pending-section h3 { margin: 0 0 var(--sp-1); }
.pending { display: flex; flex-direction: column; gap: var(--sp-2); }
.pending .pending-item {
  font-size: var(--fs-sm);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-2);
  background: var(--panel-2);
  border: 1px dashed var(--line);
  color: var(--ink);
}
.pending .pending-item .eta { color: var(--muted); font-size: var(--fs-xs); white-space: nowrap; }

.caps { display: flex; flex-direction: column; gap: var(--sp-2); }
.cap { font-size: var(--fs-sm); }
.cap-head { display: flex; justify-content: space-between; margin-bottom: var(--sp-0); }
.cap-head .invest { color: var(--muted); font-size: var(--fs-xs); }
.bar { height: 8px; background: var(--panel-2); border-radius: var(--radius-1); overflow: hidden; border: 1px solid var(--line); }
.bar > span { display: block; height: 100%; background: var(--accent); }

.rivals { display: flex; flex-direction: column; gap: var(--sp-2); }
.rival { background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--radius-2); padding: var(--sp-2) var(--sp-3); font-size: var(--fs-sm); }
.rival .rival-name { font-weight: 600; }
/* The rival's chart colour, as a key rather than a stripe down the card. */
.rival .rival-name::before { content: ''; display: inline-block; width: 8px; height: 8px; margin-right: var(--sp-2); border-radius: 2px; background: var(--rival-mark); vertical-align: 1px; }
/* The earned label leads; the evidence that earned it sits right under. */
.rival-head { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.rival-label { font-family: var(--font-display); font-weight: 600; color: var(--accent); font-size: var(--fs-sm); }
.rival-evidence { color: var(--muted); font-size: var(--fs-xs); margin-top: var(--sp-0); }
.rival-next { font-size: var(--fs-xs); color: var(--ink); margin-top: var(--sp-1); }
.rival-next .next-glyph { display: inline-block; margin-right: var(--sp-1); color: var(--accent); font-weight: 700; }
.rival .rival-meta { color: var(--muted); font-size: var(--fs-xs); margin-top: var(--sp-0); }
.rival .rival-intel { color: var(--muted); font-size: var(--fs-xs); margin-top: var(--sp-0); }

.insights { display: flex; flex-direction: column; gap: var(--sp-2); }
.insight { font-size: var(--fs-sm); padding: var(--sp-2) var(--sp-2); border-radius: var(--radius-2); background: var(--panel-2); border: 1px solid var(--line); }
.insight.captured { border-color: var(--captured-line); }
.insight .tag { font-size: var(--fs-xs); color: var(--good); margin-left: var(--sp-2); }
.muted { color: var(--muted); font-size: var(--fs-sm); }

/* ---- Tutorial ---- */
.tutorial-btn {
  position: fixed;
  left: 16px;
  bottom: 16px;
  z-index: 40;
  background: var(--panel);
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: var(--radius-round);
  font-size: var(--fs-sm);
  font-weight: 600;
  padding: var(--sp-2) var(--sp-3);
  box-shadow: var(--shadow-2);
}
.tutorial-btn:hover { color: var(--ink); border-color: var(--accent); }

.tutorial-overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: var(--overlay);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-5);
}
.tutorial-overlay.hidden { display: none; }
/* Anchored steps: the backdrop dim comes from the ring's giant box-shadow
   (leaving a bright cutout over the spotlighted element), and the card docks
   next to that element instead of centering. app.js sets its width, position
   and height cap, so it never runs off the screen or over the thing it points
   at. */
.tutorial-overlay.anchored { background: transparent; display: block; padding: 0; }
.tutorial-ring {
  position: fixed;
  border: 2px solid var(--accent);
  border-radius: var(--radius-3);
  box-shadow: 0 0 0 9999px var(--overlay);
  pointer-events: none;
  transition: top var(--dur-2) var(--ease-standard), left var(--dur-2) var(--ease-standard),
    width var(--dur-2) var(--ease-standard), height var(--dur-2) var(--ease-standard);
}
.tutorial-ring.hidden { display: none; }
.tutorial-overlay.anchored .tutorial-card { position: fixed; max-width: none; }
#tutorial .tutorial-card { display: flex; flex-direction: column; }
.tutorial-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-3);
  max-width: 480px;
  width: 100%;
  min-width: 0; /* a flex item defaults to its content's width; the nav row is wider than a phone */
  max-height: calc(100vh - 16px);
  overflow-y: auto;
  padding: var(--sp-4) var(--sp-5) var(--sp-3);
  box-shadow: var(--shadow-3);
}
.tutorial-card.sheet { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.tutorial-step-label { font-size: var(--fs-xs); color: var(--muted); font-family: var(--font-figures); font-variant-numeric: tabular-nums; }
.tutorial-card h2 {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: 600;
  font-size: var(--fs-xl);
  margin: var(--sp-1) 0 var(--sp-3);
}
/* The body scrolls on its own when the cap bites, so Back and Next stay put. */
.tutorial-body { font-size: var(--fs-md); line-height: 1.55; overflow-y: auto; min-height: 0; }
.tutorial-body p { margin: 0 0 var(--sp-3); }
.tutorial-body p:last-child { margin-bottom: 0; }
.tutorial-body ul { margin: 0 0 var(--sp-3); padding-left: var(--sp-5); }
.tutorial-body li { margin-bottom: var(--sp-1); }
.tutorial-body b { font-weight: 600; }
.tutorial-body .ex {
  color: var(--hint-ink);
  background: var(--panel-2);
  padding: var(--sp-0) var(--sp-2);
  border-radius: var(--radius-2);
  font-style: normal;
  font-size: var(--fs-sm);
}

/* The diagrams. Small, one idea each, drawn from the same palette as the
   dashboard so they read as part of the game rather than a slideshow. */
.tut-visual { margin: 0 0 var(--sp-3); }
.tut-formula { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.tut-box {
  flex: 1 1 100px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  padding: var(--sp-2) var(--sp-3);
  line-height: 1.3;
}
.tut-box b { display: block; font-weight: 600; font-size: var(--fs-sm); }
.tut-box small { display: block; color: var(--muted); font-size: var(--fs-xs); margin-top: var(--sp-0); }
.tut-box.tut-score { border-color: var(--accent); }
.tut-op { font-family: var(--font-display); font-size: var(--fs-xl); color: var(--muted); flex: none; }

.tut-chain { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-2); }
.tut-node {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-round);
  padding: var(--sp-1) var(--sp-3);
  font-size: var(--fs-sm);
  line-height: 1.35;
}
.tut-node b { color: var(--accent); }
.tut-arrow { color: var(--muted); font-size: var(--fs-md); }

.tutorial-body ul.tut-moves {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--sp-3);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-1) var(--sp-3);
}
.tut-moves li { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); margin: 0; line-height: 1.3; }
.tut-ic { width: 18px; height: 18px; flex: none; fill: currentColor; color: var(--accent); }
.tut-ex { margin-top: calc(-1 * var(--sp-1)); }

.tut-levers { display: flex; flex-direction: column; gap: var(--sp-2); }
.tut-lever {
  display: grid;
  grid-template-columns: 64px 1fr;
  grid-template-rows: auto auto;
  column-gap: var(--sp-3);
  align-items: center;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  padding: var(--sp-2) var(--sp-3);
}
.tut-lever > b { font-size: var(--fs-sm); font-weight: 600; }
.tut-lever > small { grid-column: 2; color: var(--muted); font-size: var(--fs-xs); line-height: 1.35; }
.tut-track, .tut-stepper { grid-row: 1 / span 2; }
.tut-track { position: relative; height: 5px; border-radius: var(--radius-1); background: var(--line); }
.tut-track i { display: block; height: 100%; border-radius: var(--radius-1); background: var(--accent); }
.tut-track em {
  position: absolute;
  top: 50%;
  width: 12px;
  height: 12px;
  margin: -6px 0 0 -6px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--panel);
}
.tut-stepper { display: flex; gap: var(--sp-1); }
.tut-stepper span {
  flex: 1;
  text-align: center;
  border: 1px solid var(--accent);
  color: var(--accent);
  border-radius: var(--radius-1);
  font-weight: 700;
  font-size: var(--fs-sm);
  line-height: 22px;
}

/* A phone is too narrow for a row of three boxes or three chain links, so
   both stand up as a column and the arrows point down. */
@media (max-width: 480px) {
  .tut-formula { flex-direction: column; align-items: stretch; }
  .tut-box { flex: none; } /* the 100px basis would become a height here */
  .tut-op { text-align: center; line-height: 1; }
  .tut-chain { flex-direction: column; align-items: flex-start; }
  .tut-arrow { transform: rotate(90deg); margin-left: var(--sp-4); line-height: 1; }
  /* Skip, seven dots, Back and Next on one row of a 374px card. */
  .tutorial-card { padding: var(--sp-4) var(--sp-4) var(--sp-3); }
  .tutorial-nav { gap: var(--sp-2); }
  .tutorial-dots { gap: 6px; }
  .tutorial-dots button, .tutorial-dots span { width: 6px; height: 6px; }
}

/* The fold: the longer note, closed by default. */
.tut-more { margin-top: var(--sp-3); border-top: 1px solid var(--line); padding-top: var(--sp-2); font-size: var(--fs-sm); }
.tut-more summary { cursor: pointer; color: var(--muted); font-weight: 600; font-size: var(--fs-sm); list-style-position: inside; }
.tut-more summary:hover { color: var(--ink); }
.tut-more[open] summary { margin-bottom: var(--sp-2); }
.tut-more p { margin: 0 0 var(--sp-2); }

/* Starter moves on the last card. */
.tut-try-label { color: var(--muted); font-size: var(--fs-sm); margin-bottom: var(--sp-1) !important; }
.tut-try { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.tut-chip {
  background: var(--panel-2);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-round);
  font-size: var(--fs-sm);
  padding: var(--sp-1) var(--sp-3);
}
.tut-chip:hover { border-color: var(--accent); color: var(--accent); }
.tut-replay { color: var(--muted); font-size: var(--fs-xs); margin-top: var(--sp-3) !important; }

.tutorial-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--line);
  flex: none;
}
.tutorial-nav-right { display: flex; gap: var(--sp-2); }
.tutorial-dots { display: flex; gap: var(--sp-2); }
.tutorial-dots button,
.tutorial-dots span {
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--line);
}
.tutorial-dots button.active,
.tutorial-dots span.active { background: var(--accent); }
.tutorial-dots button:hover { background: var(--muted); }

/* ---- Finances tab extras ---- */
.pane-table { max-height: 280px; overflow: auto; }

.dilution-input { display: flex; align-items: center; gap: var(--sp-2); color: var(--muted); font-weight: 600; }
.dilution-input input {
  width: 90px;
  font: inherit;
  font-weight: 600;
  color: var(--ink);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  padding: var(--sp-2) var(--sp-2);
}
.dilution-input input:focus { outline: 1px solid var(--accent); }

/* ---- End-turn confirmation ---- */
.confirm-card { max-width: 480px; }
.confirm-plan { display: flex; flex-direction: column; gap: var(--sp-1); margin: var(--sp-3) 0; }
.confirm-item {
  font-size: var(--fs-sm);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-2);
  background: var(--panel-2);
  border: 1px solid var(--line);
}
.confirm-item.confirm-flows { border-style: dashed; color: var(--muted); }
.confirm-decisions { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); margin: var(--sp-3) 0; }
.decision label { display: block; font-size: var(--fs-xs); font-weight: 600; margin-bottom: var(--sp-1); }
.required-tag, .optional-tag {
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: var(--sp-0) var(--sp-2);
  border-radius: var(--radius-round);
  margin-left: var(--sp-1);
}
.required-tag { color: var(--warn); border: 1px solid var(--warn); }
.optional-tag { color: var(--muted); border: 1px solid var(--line); }
.decision .panel-note { margin-top: var(--sp-1); }
.confirm-subhead { margin: var(--sp-2) 0 var(--sp-2); font-size: var(--fs-xs); font-weight: 600; color: var(--muted); letter-spacing: 0.2px; }
.est-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-2); }
.est { background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--radius-2); padding: var(--sp-2) var(--sp-2); }
.est .k { display: block; font-size: var(--fs-xs); color: var(--muted); }
.est .v { display: block; font-size: var(--fs-sm); font-weight: 600; font-variant-numeric: tabular-nums; }
.est-notes { display: flex; flex-direction: column; gap: var(--sp-1); margin-top: var(--sp-2); font-size: var(--fs-xs); }
.est-notes .reality {
  border-radius: var(--radius-2);
  padding: var(--sp-1) var(--sp-3);
  color: var(--warn);
  border: 1px solid color-mix(in srgb, var(--warn) 35%, transparent);
  background: color-mix(in srgb, var(--warn) 10%, transparent);
}
.confirm-estimate .panel-note { margin: var(--sp-2) 0 0; }

/* ---- The phone layout ------------------------------------------------------
 *
 * Desktop is the primary target and nothing above this breakpoint changes.
 *
 * Stacking the two desktop columns was the old behaviour and it gave a phone
 * two letterboxes: measured on a 390x844 screen, the chat log came out 47px
 * tall holding 594px of story, and the dashboard 373px holding 1618px. Three
 * nested scrollers inside a page that also scrolled, so no swipe had an
 * obvious owner. The header overflowed to 561px on a 390px screen too, which
 * put "New game" past the right edge where it could not be reached at all.
 *
 * So the phone shows one surface at a time, full height, and the switcher at
 * the bottom of the page moves between them.
 */
.view-switch { display: none; }

/* A phone turned sideways is 844x390: wide enough for the desktop columns and
 * far too short for them. Measured there, the chat log came out 3px tall, the
 * plan bar and composer having eaten the column. So the second condition
 * catches it — short, and a finger rather than a mouse, which is a handheld in
 * landscape and not a desktop window someone dragged shorter. */
@media (max-width: 820px), (max-height: 500px) and (pointer: coarse) {
  /* The page itself neither scrolls nor pans. Whichever surface is showing
     owns the only scrollbar, so a swipe always has one obvious meaning. */
  html, body { overflow-x: hidden; }
  body { height: 100dvh; overflow-y: hidden; }
  main { grid-template-columns: 1fr; min-height: 0; }

  /* One row that fits, rather than two that overflow. The seed is for support
     and export, not for playing, and the model name truncates rather than
     pushing the buttons off the screen. */
  header { padding: var(--sp-2) var(--sp-3); gap: var(--sp-2); flex-wrap: nowrap; }
  header h1 { font-size: var(--fs-xl); white-space: nowrap; }
  .header-meta { gap: var(--sp-2); min-width: 0; flex-shrink: 0; }
  .theme-name { display: none; } /* the swatch alone on a phone; the name is in the title */
  .header-meta button { white-space: nowrap; }
  #seed-badge { display: none; }
  /* Which model is answering is a support question, not a playing one, and on
     a phone it costs the row its second line. The offline case still announces
     itself: the badge below 480px is gone, but offline mode says so in the
     opening message and in every templated report. */
  #llm-badge { max-width: 96px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* One surface at a time. */
  body.view-chat .panel,
  body.view-panel .chat { display: none; }
  .panel { border-left: none; padding: var(--sp-3) var(--sp-3) var(--sp-1); }
  .chat { padding: var(--sp-3) var(--sp-3) var(--sp-2); }

  /* Full-width field with the buttons under it, the shape a phone keyboard
     expects. 16px is not a taste call: iOS zooms the whole page in when a
     focused field is smaller than that, and the zoom does not come back. */
  .composer { flex-direction: column; gap: var(--sp-2); }
  .composer textarea { min-height: 52px; }

  /* iOS zooms the whole page in when a focused field is under 16px and does
     not zoom back out, which strands the player at 1.4x with the layout half
     off-screen. It applies to every field that opens a keyboard, not just the
     composer: the price on the confirm screen, the dilution amount, the price
     test, the build order, the setup names. Sliders are exempt, having no
     keyboard to open.

     Forced, because a dozen component rules set `font: inherit` or their own
     size and each would otherwise need chasing individually. The alternative
     fix, `maximum-scale=1` on the viewport, also kills pinch-zoom, and taking
     zoom away from people who need it to read is not a trade worth making. */
  input[type='text'],
  input[type='number'],
  input[type='search'],
  textarea,
  select {
    font-size: var(--fs-lg) !important;
  }
  .composer-btns { flex-direction: row; }
  .composer-btns button { flex: 1; min-height: 44px; }
  /* The left gutter existed to clear the floating tutorial button, which is
     now in the switcher instead. */
  .hint { padding-left: 0; min-height: 0; margin-bottom: var(--sp-0); }
  .tutorial-btn { display: none; }

  /* Six tabs will not fit across a phone at a tappable size, so they scroll
     sideways instead of being squeezed to 11px and 32px tall. */
  .tabs { gap: 0; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; top: -12px; }
  .tabs::-webkit-scrollbar { display: none; }
  .tabs button {
    flex: 0 0 auto;
    font-size: var(--fs-sm);
    padding: var(--sp-3) var(--sp-4);
    min-height: 44px;
  }

  .view-switch { display: flex; }

  /* Roomier tap targets on the controls that stage moves. */
  .stat-step { min-width: 34px; min-height: 34px; }

  /* A bubble sized for half a desktop column wastes a third of a phone's
     width, and the story is most of what there is to read. */
  .msg { max-width: 92%; }
  .msg.scene { max-width: 100%; }

  .confirm-decisions { grid-template-columns: 1fr; }
  .est-grid { grid-template-columns: 1fr 1fr; }
}

/* The switcher itself. A row at the foot of the page rather than a floating
   pill, so it never covers the composer, and padded for the home indicator on
   phones that have one. */
.view-switch {
  border-top: 1px solid var(--line);
  background: var(--panel);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  flex: 0 0 auto;
}
.view-switch .vs-tab {
  position: relative;
  flex: 1;
  min-height: 52px;
  border: none;
  border-radius: 0;
  background: transparent;
  color: var(--muted);
  font-size: var(--fs-md);
  font-weight: 600;
}
.view-switch .vs-tab[aria-selected='true'] {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  box-shadow: inset 0 2px 0 var(--accent);
}
/* Something arrived in the conversation while the dashboard was up. */
.view-switch .vs-dot[hidden] { display: none; }
.view-switch .vs-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-left: var(--sp-1);
  border-radius: 50%;
  background: var(--accent);
  vertical-align: 2px;
}
.view-switch .vs-help {
  flex: 0 0 auto;
  width: 52px;
  min-height: 52px;
  border: none;
  border-left: 1px solid var(--line);
  border-radius: 0;
  background: transparent;
  color: var(--muted);
  font-size: var(--fs-md);
  font-weight: 600;
}

/* Narrow phones. Which model is answering is a support question rather than a
   playing one, and at this width it costs the header row its second line.
   Offline mode still announces itself in the opening message and in every
   templated report, so nothing about how the game behaves goes unsaid. */
@media (max-width: 480px) {
  #llm-badge { display: none; }
  header h1 { font-size: var(--fs-xl); }
}

/* Touch, at any size. A 16px dot is a comfortable mouse target and a coin toss
   for a fingertip, and these sliders are how a capability level gets set. */
@media (pointer: coarse) {
  .plancard input[type='range']::-webkit-slider-thumb {
    width: 24px;
    height: 24px;
    margin-top: -10px;
  }
  .plancard input[type='range']::-moz-range-thumb {
    width: 20px;
    height: 20px;
  }
}

/* Sideways, there is no vertical budget for anything that is not the game.
   The worked examples under the composer are onboarding, and by the time
   someone has turned the phone to read a chart they have seen them. */
@media (max-height: 500px) and (pointer: coarse) {
  header { padding: var(--sp-1) var(--sp-3); }
  header h1 { font-size: var(--fs-lg); }
  .hint { display: none; }
  .view-switch .vs-tab,
  .view-switch .vs-help { min-height: 44px; }
}

/* ---- Character setup (who's running the company) ---- */
.setup-card { max-width: 420px; }
.setup-label {
  display: block;
  margin: var(--sp-4) 0 var(--sp-2);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}
.setup-card input[type='text'] {
  width: 100%;
  font: inherit;
  font-weight: 600;
  color: var(--ink);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  padding: var(--sp-2) var(--sp-3);
}
.setup-card input[type='text']:focus { outline: 1px solid var(--accent); }
.setup-genders { display: flex; gap: var(--sp-2); }
.setup-genders button {
  flex: 1;
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  padding: var(--sp-2) 0;
}
.setup-genders button.active {
  border-color: var(--accent);
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.setup-card .tutorial-nav { margin-top: var(--sp-4); }

/* ---- Image beats in the chat (founder portrait, quarterly scene stills) ---- */
.msg.scene {
  /* Centered under the story it belongs to (the founder portrait sits right
     below the intro; quarterly stills sit under their reports). */
  align-self: center;
  max-width: 68%;
  padding: var(--sp-2);
  background: var(--panel);
  border: 1px solid var(--line);
}
/* The frame holds the picture's space from the moment the message appears, so
   a render finishing 8 seconds later fills a box that was always there instead
   of shoving the text the player is reading down the page. */
.msg.scene .scene-frame {
  aspect-ratio: 3 / 2;
  max-height: 300px;
  border-radius: var(--radius-2);
  overflow: hidden;
  background: var(--bg);
}
.msg.scene img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: var(--radius-2);
}
.msg.scene.pending .scene-frame {
  /* A slow shimmer, so a blank box reads as "coming" rather than "broken". */
  background: linear-gradient(100deg, var(--bg) 30%, var(--panel) 50%, var(--bg) 70%);
  background-size: 300% 100%;
  animation: scene-shimmer 1.6s ease-in-out infinite;
}
.msg.scene.pending img { opacity: 0; }
@keyframes scene-shimmer {
  from { background-position: 150% 0; }
  to { background-position: -50% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .msg.scene.pending .scene-frame { animation: none; }
}
.msg.scene .scene-cap {
  padding: var(--sp-2) var(--sp-2) var(--sp-0);
  font-size: var(--fs-sm);
  color: var(--muted);
}
.msg.scene.hidden { display: none; }

/* ---- The DM's unprompted beat (a card drawn between quarters) ---- */
.msg.engine.hook {
  border: 1px solid var(--line);
}

/* ---- World events (scripted external shocks) ----
   A banner of their own: the world acting, not the GM talking. */
.msg.event {
  align-self: center;
  width: 92%;
  max-width: 92%;
  border: 1px solid color-mix(in srgb, var(--warn) 55%, var(--line));
  border-radius: var(--radius-3);
  background: var(--panel);
}
.msg.event .event-title { font-weight: 600; color: var(--warn); margin-bottom: var(--sp-1); }
.msg.event .event-body { font-size: var(--fs-md); line-height: 1.55; }
.msg.event.event-ended { opacity: 0.85; border-color: var(--line); }
.msg.event.event-ended .event-title { color: var(--muted); }
.pending .pending-item.event-item { color: var(--warn); }

/* ---- Segments & market share (Customers tab): one row per segment, its
   ownership donut beside the card ---- */
.seg-row { display: flex; align-items: center; gap: var(--sp-3); }
.seg-row .segment { flex: 1; min-width: 0; }
.seg-donut { width: 88px; flex-shrink: 0; }
.seg-donut svg { display: block; width: 100%; height: auto; }
.chart-legend .sw-dash { background-image: linear-gradient(90deg, currentColor 60%, transparent 40%); }

/* ---- Company tab: org chart, facilities, contracts, relationships ---- */
.org-chart { margin-bottom: var(--sp-2); }
.org-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: var(--sp-3) var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-3);
  background: var(--panel-2);
  margin-bottom: var(--sp-2);
}
.org-top .org-name { font-weight: 700; }
.org-top .org-count { color: var(--muted); font-size: var(--fs-sm); }
.org-fns { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
.org-fn { border: 1px solid var(--line); border-radius: var(--radius-3); padding: var(--sp-2) var(--sp-3); }
.org-fn-name { font-weight: 600; font-size: var(--fs-sm); }
.org-fn-meta { color: var(--muted); font-size: var(--fs-xs); margin-top: var(--sp-0); }
.org-fn-doing { margin: var(--sp-2) 0 0; font-size: var(--fs-xs); line-height: 1.45; }
.org-fn-note { margin: var(--sp-1) 0 0; font-size: var(--fs-xs); line-height: 1.45; color: var(--muted); }
/* The "try asking" hint: clicking drops the move into the chat box. */
.org-ask {
  display: block;
  margin-top: var(--sp-2);
  padding: var(--sp-0) var(--sp-2);
  font-size: var(--fs-xs);
  font-weight: 500;
  text-align: left;
  border: none;
  padding: 0;
  background: transparent;
  color: var(--muted);
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-underline-offset: 3px;
}
.org-ask:hover { color: var(--ink); text-decoration-color: currentColor; }

/* Workload gauge: fills toward what the team supports; red past it. */
#org-strain { margin-bottom: var(--sp-4); font-size: var(--fs-sm); }
.strain-bar.over > span { background: var(--bad); }
.strain-warn { color: var(--warn); }
.org-list { display: flex; flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.org-row {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-3);
  font-size: var(--fs-sm);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
}
.org-row .org-note { color: var(--muted); text-align: right; }
.org-kind {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  margin-left: var(--sp-2);
}

/* Company name atop the org chart */
.org-company { font-weight: 700; font-size: var(--fs-md); }
.org-top .org-name.sub { font-weight: 500; font-size: var(--fs-sm); color: var(--muted); margin-top: var(--sp-0); }

/* ---- Wide-panel reflow (the 50/50 split) ---- */
/* Capability cards pair up when the panel is wide. */
@media (min-width: 1201px) {
  .caps { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
  .chart-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
  .chart-grid .chart-card { margin-bottom: 0; }
  /* Solo charts shouldn't become billboards at full panel width. */
  .tab-pane > .chart-body svg,
  .mini-planner .chart-body svg,
  .mini-planner svg { max-width: 560px; margin: 0 auto; }
  .org-fns { grid-template-columns: repeat(4, 1fr); }
}

/* ---- Capability radar ---- */
.radar-body { margin-bottom: var(--sp-4); }
.radar-body svg { display: block; width: 100%; max-width: 460px; margin: 0 auto; height: auto; }
.chart-legend .sw-dotted { border-radius: var(--radius-1); height: 3px; width: 12px; }
.chart-legend .depth { font-style: normal; color: var(--muted); opacity: 0.8; }
.canvas-legend { flex-wrap: wrap; margin-bottom: var(--sp-1); }

/* ---- Finance tab: editable Position tiles ----
   The numbers themselves are the controls: price and debt edit in place, the
   business model toggles on click. A visible border on the value marks what
   can be changed; everything stages into the plan like a typed move. */
.stat.stat-edit { cursor: default; }
.stat-editline { display: flex; align-items: center; gap: var(--sp-1); margin-top: var(--sp-0); }
.stat-editline .cur,
.stat-editline .unit { font-weight: 600; color: var(--muted); font-size: var(--fs-sm); }
.stat-editline input {
  width: 56px;
  font: inherit;
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--ink);
  background: transparent;
  border: none;
  border-bottom: 1px dashed var(--muted);
  padding: 0 var(--sp-0) var(--sp-0);
  font-variant-numeric: tabular-nums;
}
/* Where supported, the input hugs its number so the dashed underline runs
   exactly under the digits instead of trailing off into empty space. */
@supports (field-sizing: content) {
  .stat-editline input { field-sizing: content; width: auto; min-width: 26px; max-width: 90px; }
}
.stat-editline input:focus { outline: none; border-bottom: 1px solid var(--accent); }
.stat-editline input.changed { color: var(--accent); border-bottom-color: var(--accent); }
.stat-step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border-radius: var(--radius-2);
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--ink);
  font-size: var(--fs-md);
  line-height: 1;
  padding: 0;
  cursor: pointer;
}
.stat-step:hover { border-color: var(--accent); color: var(--accent); }
.stat-sub { display: block; font-size: var(--fs-xs); color: var(--muted); margin-top: var(--sp-0); line-height: 1.4; }
.stat-toggle {
  display: block;
  font: inherit;
  font-size: var(--fs-md);
  font-weight: 600;
  margin-top: var(--sp-0);
  padding: 0 var(--sp-0) var(--sp-0);
  background: transparent;
  border: none;
  border-bottom: 1px dashed var(--muted);
  color: var(--ink);
  cursor: pointer;
  text-align: left;
}
.stat-toggle:hover { border-bottom-color: var(--accent); color: var(--accent); }
.stat-toggle.changed { color: var(--accent); border-bottom: 1px solid var(--accent); }
#equity-stage { margin-left: var(--sp-2); }

/* ---- Next-quarter forecast (production tab) ------------------------------- */
/* Demand and capacity shown as separate things, with the binding constraint
   named. Under build-to-order the engine builds exactly what buyers want, so
   showing "built" against "demand" alone looks broken: they are the same
   number whenever the factory has room. */
.forecast {
  margin-top: var(--sp-4);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--line);
}
.forecast-head {
  font-size: var(--fs-xs);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: var(--sp-2);
}
/* A stack of reasoning steps, not a grid of tiles. The forecast used to be
   four independent stat cells; it is now a derivation, and a derivation reads
   top to bottom. */
.forecast-grid { display: block; }
.fc-warn { color: var(--warn); }
.fc-ok { color: var(--accent); }
.fc-units { fill: none; stroke: var(--muted); stroke-width: 1.6; }
.fc-profit { fill: none; stroke: var(--accent); stroke-width: 2; }
.fc-peak { stroke: var(--line); stroke-width: 1; stroke-dasharray: 3 3; }
.fc-axis { fill: var(--muted); font-size: var(--fs-xs); }
.fc-legend {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
  font-size: var(--fs-xs);
  color: var(--muted);
  margin-top: var(--sp-1);
}
.fc-legend .sw {
  width: 14px;
  height: 2px;
  border-radius: var(--radius-1);
  display: inline-block;
}
.fc-legend .sw.units { background: var(--muted); }
.fc-legend .sw.profit { background: var(--accent); }
.fc-legend .sw + span, .fc-legend .sw { margin-left: var(--sp-1); }
.fc-peaklabel { margin-left: auto; color: var(--accent); }
.est-error { color: var(--warn); font-size: var(--fs-sm); }

/* ---- Quarter boundaries in the log ---------------------------------------- */
.quarter-rule {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin: var(--sp-1) 0;
  color: var(--muted);
  font-size: var(--fs-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.quarter-rule::before,
.quarter-rule::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}
/* A record of the decisions actually committed, kept beside the story so a
   player scrolling back can see what they did as well as what happened. */
.msg.decisions {
  align-self: center;
  max-width: 92%;
  width: 92%;
  background: transparent;
  border: 1px dashed var(--line);
  border-radius: var(--radius-3);
  padding: var(--sp-2) var(--sp-3);
  white-space: normal;
}
.decisions-head {
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: var(--sp-1);
}
.msg.decisions ul { margin: 0; padding-left: var(--sp-4); }
.msg.decisions li { font-size: var(--fs-sm); color: var(--hint-ink); line-height: 1.55; }

/* ---- Valuation breakdown --------------------------------------------------- */
.valuation {
  margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-3);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-3);
}
.val-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--sp-0) var(--sp-3);
  align-items: baseline;
  padding: var(--sp-0) 0;
}
.val-k { font-size: var(--fs-sm); }
.val-v { font-size: var(--fs-md); font-variant-numeric: tabular-nums; }
.val-note {
  grid-column: 1 / -1;
  font-size: var(--fs-xs);
  color: var(--muted);
  line-height: 1.45;
}
.val-total { border-top: 1px solid var(--line); margin-top: var(--sp-1); padding-top: var(--sp-2); font-weight: 600; }
.valuation .panel-note { margin: var(--sp-2) 0 0; }

/* ---- Analytical charts (demand, experience, scale) -------------------------- */
/* Continuous-axis charts: scatter with a fitted line and an uncertainty band.
   Everything is class-based so the theme toggle restyles without a re-render. */
.xy-band { fill: var(--accent); opacity: 0.13; stroke: none; }
.xy-line { fill: none; stroke-width: 2; }
.xy-fit { stroke: var(--accent); }
.chart-legend .sw-fit { background: var(--accent); }
.xy-variable { stroke: var(--viz-c2); stroke-dasharray: 4 3; stroke-width: 1.6; }
.xy-dot { stroke: var(--panel); stroke-width: 1.2; }
.xy-own { fill: var(--viz-c1); }
/* Bought with an experiment, so it earns a distinct shape in the reader's eye. */
.xy-test { fill: var(--good); stroke-width: 1.6; }
/* Someone else's product. Plotted for context, never fitted. */
.xy-rival { fill: none; stroke: var(--muted); stroke-width: 1.3; }
/* Describes a company that no longer exists, and left out of the fit. */
.xy-stale { fill: var(--muted); opacity: 0.4; }
.xy-mark { stroke: var(--line); stroke-width: 1; stroke-dasharray: 3 3; }
.xy-mark-now { stroke: var(--viz-c1); }
.xy-mark-best { stroke: var(--good); }
.chart-legend .sw-own { background: var(--viz-c1); }
.chart-legend .sw-test { background: var(--good); }
.chart-legend .sw-rival { background: transparent; border: 1.5px solid var(--muted); }
.chart-legend .sw-stale { background: var(--muted); opacity: 0.4; }
.chart-legend .sw-var { background: var(--viz-c2); }

/* The headline number, its range, and what it is. */
.readout {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  margin: var(--sp-0) 0 var(--sp-2);
}
.dm-value { font-size: var(--fs-2xl); font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1; }
.dm-band { font-size: var(--fs-xs); color: var(--muted); font-variant-numeric: tabular-nums; }
.dm-what { flex-basis: 100%; font-size: var(--fs-xs); color: var(--muted); }
.dm-none { font-size: var(--fs-md); color: var(--muted); }

/* How the reading has moved. Guards against treating one estimate as a law. */
.drift { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--sp-1) var(--sp-2); margin: var(--sp-1) 0 var(--sp-0); }
.dm-drift-head { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
.dm-drift-item {
  font-size: var(--fs-xs);
  color: var(--muted);
  padding: var(--sp-0) var(--sp-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-round);
  font-variant-numeric: tabular-nums;
}
.dm-drift-item b { color: var(--ink); }

/* The price test control. */
.pt-row { display: flex; align-items: center; gap: var(--sp-2); margin: var(--sp-1) 0; }
.pt-row input {
  flex: 1;
  min-width: 0;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  color: var(--ink);
  font: inherit;
  font-variant-numeric: tabular-nums;
  padding: var(--sp-1) var(--sp-2);
}
.pt-spend { margin-bottom: var(--sp-1); }

/* The forecast, decomposed into where each number came from. */
.fc-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--sp-0) var(--sp-3);
  padding: var(--sp-1) 0;
  border-bottom: 1px solid var(--line);
}
.fc-row:last-child { border-bottom: 0; }
.fc-label { font-size: var(--fs-sm); }
.fc-detail { grid-column: 1 / -1; font-size: var(--fs-xs); color: var(--muted); line-height: 1.4; }
.fc-row span:nth-child(2) { font-variant-numeric: tabular-nums; font-size: var(--fs-md); }
.fc-up { color: var(--good); }
.fc-down { color: var(--bad); }
.fc-none { color: var(--muted); font-size: var(--fs-xs); }
.fc-total { border-top: 1px solid var(--line); border-bottom: 0; margin-top: var(--sp-0); padding-top: var(--sp-2); font-weight: 600; }
.fc-range { font-size: var(--fs-lg) !important; color: var(--accent); font-variant-numeric: tabular-nums; }

/* ---- The quarterly report ------------------------------------------------------
   Its own object in the log, not a bubble. The chrome scales with the verdict
   the server decided from the numbers (see quarterVerdict in src/view.ts):
   a calm quarter is a plain card, a grave one changes the furniture. The
   severity word in the kicker says in text what the colour says in colour. */
.msg.report {
  align-self: center;
  width: 92%;
  max-width: 92%;
  white-space: normal;
  background: var(--panel);
  border: 1px solid var(--line);
  padding: var(--sp-3) var(--sp-4);
  box-shadow: inset 0 1px 0 var(--elev-hi), var(--shadow-1);
}
/* Severity shows as the card's edge colour and the kicker word, not a stripe. */
.msg.report.sev-notable { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.msg.report.sev-notable.tone-good { border-color: color-mix(in srgb, var(--good) 45%, var(--line)); }
.msg.report.sev-rough { border-color: color-mix(in srgb, var(--warn) 50%, var(--line)); }
.msg.report.sev-grave {
  border-color: color-mix(in srgb, var(--bad) 60%, var(--line));
  box-shadow: inset 0 1px 0 var(--elev-hi), var(--shadow-2);
}
.report-kicker {
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.sev-notable.tone-good .report-kicker { color: var(--good); }
.sev-rough .report-kicker { color: var(--warn); }
.sev-grave .report-kicker { color: var(--bad); }
.report-head {
  margin: var(--sp-1) 0 var(--sp-3);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-lg);
  line-height: 1.3;
}
.sev-rough .report-head { font-size: var(--fs-xl); }
.sev-grave .report-head { font-size: var(--fs-2xl); line-height: 1.2; }
.report-deltas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(104px, 1fr));
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
}
.rd {
  display: flex;
  flex-direction: column;
  gap: var(--sp-0);
  padding: var(--sp-1) var(--sp-2);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  box-shadow: inset 0 1px 0 var(--elev-hi), var(--shadow-1);
}
.rd-k { font-size: var(--fs-xs); color: var(--muted); }
.rd-v,
.rd-c {
  font-family: var(--font-figures);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.rd-v { font-weight: 600; font-size: var(--fs-md); }
.rd-c { font-size: var(--fs-xs); color: var(--muted); }
.rd-good .rd-c { color: var(--good); }
.rd-bad .rd-c { color: var(--bad); }
.rd .delta-glyph { margin: 0 var(--sp-0) 0 0; color: inherit; }
.rd[data-tip] { cursor: help; }
.rd[data-tip]:hover,
.rd[aria-expanded="true"] { border-color: var(--accent); }
/* The full "why", opened by clicking a cell. */
.rd-why {
  margin: 0 0 var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  font-size: var(--fs-sm);
}
.rd-why-head { font-size: var(--fs-xs); letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); margin-bottom: var(--sp-1); }
.rd-why ul { margin: 0; padding-left: var(--sp-4); }
.rd-why li { line-height: 1.5; font-variant-numeric: tabular-nums; }
.report-story { border-top: 1px solid var(--line); padding-top: var(--sp-2); }
.report-story summary { cursor: pointer; font-size: var(--fs-sm); font-weight: 600; color: var(--muted); }
.report-story summary:hover { color: var(--ink); }
.report-story[open] summary { margin-bottom: var(--sp-2); }
.report-body { white-space: pre-wrap; font-size: var(--fs-md); line-height: 1.6; }
.msg.report .intel { margin-top: var(--sp-3); }

/* ---- The plan card ---------------------------------------------------------------
   A directive with no lever behind it. The chip was a pill built for three
   words holding forty; this is the container the content deserved. */
.plan-card {
  flex-basis: 100%;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  padding: var(--sp-2) var(--sp-3);
  box-shadow: inset 0 1px 0 var(--elev-hi), var(--shadow-1);
}
.plan-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-bottom: var(--sp-1);
}
.plan-badge {
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--warn);
  border: 1px solid var(--badge-off-line);
  border-radius: var(--radius-round);
  padding: var(--sp-0) var(--sp-2);
}
.plan-directive {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-md);
  line-height: 1.4;
  quotes: "\201C" "\201D";
}
.plan-caveat { margin: var(--sp-1) 0 0; font-size: var(--fs-xs); color: var(--muted); line-height: 1.45; }
.confirm-plan .plan-card { margin-bottom: var(--sp-2); }

/* ---- The wait ------------------------------------------------------------------
   Three named steps instead of one spinner. The mark and the word both change,
   so the step is readable without the colour or the pulse. */
.commit-steps {
  list-style: none;
  margin: var(--sp-3) 0 0;
  padding: var(--sp-2) var(--sp-3);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--muted);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
}
.commit-steps li { display: flex; align-items: center; gap: var(--sp-2); }
.step-mark {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: 1px solid var(--muted);
  flex-shrink: 0;
}
.commit-steps li.now { color: var(--ink); font-weight: 600; }
.commit-steps li.now .step-mark { border-color: var(--accent); background: var(--accent); animation: step-pulse 900ms var(--ease-standard) infinite alternate; }
.commit-steps li.now::after { content: "…"; }
.commit-steps li.done .step-mark { border-color: var(--good); background: var(--good); }
.commit-steps li.done::after { content: "✓"; color: var(--good); }
@keyframes step-pulse {
  to { transform: scale(1.6); opacity: 0.45; }
}

/* ---- Motion ------------------------------------------------------------------
   Everything that moves, in one place. Two rules hold throughout: durations
   and curves come from the tokens above, and every moving signal has a static
   twin (a glyph, a held tint) so a player with motion turned off still gets
   the information. That is WCAG C39, not a nicety. */

/* Interactive chrome settles on the standard curve. Transform sits on the
   short duration so a press feels immediate. */
button,
.tabs button,
.stat-step,
.stat-editline input,
.stat-toggle,
.badge,
.plan-chip {
  transition:
    background-color var(--dur-2) var(--ease-standard),
    border-color var(--dur-2) var(--ease-standard),
    color var(--dur-2) var(--ease-standard),
    box-shadow var(--dur-2) var(--ease-standard),
    opacity var(--dur-2) var(--ease-standard),
    transform var(--dur-1) var(--ease-standard);
}

/* Chat lines arrive rather than appear. */
@keyframes msg-in {
  from { opacity: 0; transform: translateY(var(--sp-1)); }
}
.msg { animation: msg-in var(--dur-2) var(--ease-out) backwards; }

/* The one overshoot. The commit button lands with a little spring when the
   confirm sheet opens and again under the pointer; nothing else in the UI
   bounces, which is what makes this one read as decisive. */
@keyframes commit-arrive {
  from { transform: scale(0.88); opacity: 0.6; }
}
#confirm-go {
  transition:
    transform var(--dur-2) var(--ease-overshoot),
    background-color var(--dur-2) var(--ease-standard),
    border-color var(--dur-2) var(--ease-standard),
    opacity var(--dur-2) var(--ease-standard);
}
#confirm:not(.hidden) #confirm-go { animation: commit-arrive var(--dur-3) var(--ease-overshoot) backwards; }
#confirm-go:hover:not(:disabled) { transform: scale(1.04); }
#confirm-go:active:not(:disabled) { transform: scale(0.96); }

/* ---- Deltas: what moved this quarter ------------------------------------------
   The delta shim in app.js (markDeltas) marks any [data-delta] element whose
   number differs from the start of the quarter with .moved and a data-dir,
   and appends a ▲/▼ glyph. Colour is never the only carrier: the glyph is
   always there, and only the glyph takes the good/bad colour, so it doesn't
   fight the cash figure's own red-when-negative. */
.delta-glyph {
  display: inline-block;
  margin-left: var(--sp-1);
  font-size: var(--fs-xs);
  line-height: 1;
  vertical-align: 0.15em;
  color: var(--accent);
}
[data-sense="up-good"][data-dir="up"] > .delta-glyph,
[data-sense="up-bad"][data-dir="down"] > .delta-glyph { color: var(--good); }
[data-sense="up-good"][data-dir="down"] > .delta-glyph,
[data-sense="up-bad"][data-dir="up"] > .delta-glyph { color: var(--bad); }
.rival .delta-glyph { margin-left: var(--sp-0); }

/* On a share donut the glyph sits as a small badge on the ring's shoulder. */
.seg-donut { position: relative; border-radius: 50%; }
.seg-donut > .delta-glyph {
  position: absolute;
  top: 0;
  right: 0;
  margin: 0;
  padding: var(--sp-0) var(--sp-1);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-round);
}

/* The pulse: one breath of tint on the tile whose number just changed. A
   background change only, never a shape change, so it doesn't fight the
   roll-up running inside it. */
@keyframes delta-pulse {
  from { background-color: var(--pulse); }
  to { background-color: var(--pulse-rest, transparent); }
}
.stat,
.rival { --pulse-rest: var(--panel-2); }
.turn-cash { border-radius: var(--radius-1); }
.flash { animation: delta-pulse var(--dur-4) var(--ease-standard); }

/* The roll-up. A tile that opts in with data-roll gets its digits wrapped in
   .roll; the shim sets --roll-n to the old number, then to the new one, and
   the registered property transitions between them while a CSS counter prints
   the in-between values. No tweening library, and the formatted text the
   render path wrote is still the element's real content underneath, hidden
   only while the count runs.

   The counter can't group thousands or place a decimal point on its own, so
   the digit layout is split with round() and printed piecewise. The shim only
   rolls when old and new share a layout; anything else just pulses. */
@property --roll-n {
  syntax: '<integer>';
  inherits: true;   /* the ::before that prints it must see the animated value */
  initial-value: 0;
}
@counter-style roll-pad2 { system: extends decimal; pad: 2 "0"; }
@counter-style roll-pad3 { system: extends decimal; pad: 3 "0"; }
.roll {
  display: inline-grid;
  transition: --roll-n var(--dur-3) var(--ease-standard);
}
.roll > .roll-txt,
.roll.rolling::before { grid-area: 1 / 1; }
.roll.rolling > .roll-txt { visibility: hidden; }
.roll.rolling::before {
  content: counter(rn);
  counter-reset: rn var(--roll-n);
}
.roll.rolling[data-groups="2"]::before {
  --rk: round(down, var(--roll-n) / 1000, 1);
  counter-reset: rk var(--rk) ru calc(var(--roll-n) - var(--rk) * 1000);
  content: counter(rk) "," counter(ru, roll-pad3);
}
.roll.rolling[data-groups="3"]::before {
  --rm: round(down, var(--roll-n) / 1000000, 1);
  --rk: round(down, (var(--roll-n) - var(--rm) * 1000000) / 1000, 1);
  counter-reset: rm var(--rm) rk var(--rk) ru calc(var(--roll-n) - var(--rm) * 1000000 - var(--rk) * 1000);
  content: counter(rm) "," counter(rk, roll-pad3) "," counter(ru, roll-pad3);
}
.roll.rolling[data-decimals="1"]::before {
  --rw: round(down, var(--roll-n) / 10, 1);
  counter-reset: rw var(--rw) rf calc(var(--roll-n) - var(--rw) * 10);
  content: counter(rw) "." counter(rf);
}
.roll.rolling[data-decimals="2"]::before {
  --rw: round(down, var(--roll-n) / 100, 1);
  counter-reset: rw var(--rw) rf calc(var(--roll-n) - var(--rw) * 100);
  content: counter(rw) "." counter(rf, roll-pad2);
}

/* Motion off: nothing transitions or pulses, and the pulse becomes a tint the
   tile holds for the quarter. The glyphs need no substitute; they were never
   motion. The shim skips the roll-up itself, so the number simply appears. */
@media (prefers-reduced-motion: reduce) {
  button,
  .tabs button,
  .stat-step,
  .stat-editline input,
  .stat-toggle,
  .badge,
  .plan-chip,
  #confirm-go,
  .roll { transition: none; }
  .msg,
  .flash,
  .commit-steps li.now .step-mark,
  #confirm:not(.hidden) #confirm-go { animation: none; }
  #confirm-go:hover:not(:disabled),
  #confirm-go:active:not(:disabled) { transform: none; }
  .stat:has(> .moved),
  .rival:has(.moved) { background-image: linear-gradient(var(--pulse-held), var(--pulse-held)); }
  .turn-cash:has(.moved),
  .seg-donut.moved { background-color: var(--pulse-held); }
}

/* ---- Sep 23 meeting: graphics first, words on demand -------------------- */

/* The (i) beside a heading: the section's explanation, on hover, tap or focus. */
.info {
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  margin-left: var(--sp-1);
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: var(--muted);
  font: 600 var(--fs-xs) / 1 var(--font-body, inherit);
  font-style: normal;
  vertical-align: 2px;
  cursor: help;
}
.info:hover, .info:focus-visible { color: var(--ink); border-color: var(--muted); }

.sub-head { margin: var(--sp-3) 0 0; font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }

/* Folded detail: "how this is worked out", the part-by-part cost, the ledger. */
details.more { margin-top: var(--sp-2); font-size: var(--fs-sm); }
details.more > summary { cursor: pointer; color: var(--muted); font-weight: 600; font-size: var(--fs-xs); }
details.more > summary:hover { color: var(--ink); }
details.more[open] > summary { margin-bottom: var(--sp-2); }
details.more.fold { margin-top: var(--sp-5); border-top: 1px solid var(--line); padding-top: var(--sp-3); }
details.more.fold > summary { font-size: var(--fs-sm); }

/* A plain horizontal meter: brand health, breakthrough odds. */
.meter { position: relative; height: 10px; border-radius: var(--radius-1); background: var(--panel-2); border: 1px solid var(--line); overflow: hidden; }
.meter > span { display: block; height: 100%; background: var(--accent); transition: width var(--dur-3, 300ms) ease; }
.meter[data-tier="bad"] > span { background: var(--bad); }
.meter[data-tier="warn"] > span { background: var(--warn); }
.meter[data-tier="good"] > span { background: var(--good); }

.brand-health { margin-top: var(--sp-2); }
.brand-score { display: flex; align-items: baseline; gap: var(--sp-1); margin-bottom: var(--sp-2); }
.brand-num { font-size: var(--fs-2xl); font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1; }
.brand-of { color: var(--muted); font-size: var(--fs-sm); }
.brand-word { margin-left: var(--sp-2); font-size: var(--fs-sm); font-weight: 600; }
.brand-word[data-tier="bad"] { color: var(--bad); }
.brand-word[data-tier="warn"] { color: var(--warn); }
.brand-word[data-tier="good"] { color: var(--good); }

.rd-meter { margin-top: var(--sp-2); font-size: var(--fs-sm); }
.rd-line { display: flex; align-items: baseline; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.rd-num { font-size: var(--fs-2xl); font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1; }
.rd-what { color: var(--muted); }
.rd-bar { overflow: visible; }
.rd-tick { position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px; background: var(--ink); opacity: 0.5; }
.rd-scale { display: flex; justify-content: space-between; margin-top: var(--sp-1); color: var(--muted); font-size: var(--fs-xs); }

/* The score, first thing on Finance. */
.score-card { background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--radius-2); padding: var(--sp-3) var(--sp-4); }
.score-line { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); }
.score-k { font-weight: 600; }
.score-v { font-size: var(--fs-2xl); font-weight: 600; font-variant-numeric: tabular-nums; }
.score-card .valuation { margin: 0; padding: 0; border: none; background: none; box-shadow: none; }
.val-foot { margin: var(--sp-2) 0 0; color: var(--muted); font-size: var(--fs-xs); }
