/* ---------------------------------------------------------------------------
   Auction walkthrough — styles.

   Colour roles come from the dataviz reference palette. The chart uses a
   two-shade ramp of ONE hue (blue) because value-vs-bid is a before/after pair
   per bidder, not two independent identities. Both shade pairs were checked with
   the palette validator in ordinal mode and pass in light and dark:

     light  #86b6ef -> #2a78d6   (blue 250 -> blue 450, light end 2.06:1)
     dark   #256abf -> #3987e5   (blue 500 -> blue 450-dark, light end 3.23:1)

   The light end sits at ~2.1:1 against its surface, which is the documented
   ordinal floor and carries a "relief required" obligation: every bar is
   directly labelled AND repeated in the table view, so no value is colour-only.
   --------------------------------------------------------------------------- */

:root {
  color-scheme: light;

  --surface:    #fcfcfb;   /* card / chart surface */
  --plane:      #f9f9f7;   /* page behind the cards */
  --ink:        #0b0b0b;
  --ink-2:      #52514e;
  --ink-muted:  #898781;
  --grid:       #e1e0d9;
  --axis:       #c3c2b7;
  --border:     rgba(11, 11, 11, 0.10);
  --wash:       rgba(42, 120, 214, 0.07);  /* highlighted-row band */
  --sunken:     #f2f1ed;                    /* formula block, chips */

  --series-value: #86b6ef;   /* the lighter shade: what the item is worth to them */
  --series-bid:   #2a78d6;   /* the stronger shade: what they actually bid */
  --rule:         #6f6d67;   /* reference lines (reserve / price / clock ...) */

  /* Categorical slots — bidder identity on the bid-path chart, assigned in setup
     order and never by rank. Straight from the dataviz reference palette; the
     eight light steps were run through the palette validator against this
     surface and pass the band, chroma, CVD (worst adjacent ΔE 9.1) and
     normal-vision (19.6) gates. Three of them sit below 3:1 contrast here, which
     is a WARN carrying a relief obligation: the chart ships a legend, direct end
     labels and a full table view, so no bid is ever colour-only. */
  --cat-1: #2a78d6;   /* blue */
  --cat-2: #eb6834;   /* orange */
  --cat-3: #1baf7a;   /* aqua */
  --cat-4: #eda100;   /* yellow */
  --cat-5: #e87ba4;   /* magenta */
  --cat-6: #008300;   /* green */
  --cat-7: #4a3aa7;   /* violet */
  --cat-8: #e34948;   /* red */
  --cat-rest: #898781; /* past eight: one de-emphasis grey, never a ninth hue */

  --good:     #0ca30c;
  --critical: #d03b3b;

  /* The ledger's own rules: strong enough to print as a double line. */
  --border-strong: rgba(11, 11, 11, 0.30);
  --speed: 160ms;

  --font: system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* A serif masthead over a sans body: the one typographic move that reads as
     considered without touching a single measurement below it. */
  --display: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --radius: 10px;
  --shadow: 0 1px 2px rgba(11, 11, 11, 0.04), 0 8px 24px -12px rgba(11, 11, 11, 0.10);
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;

    --surface:   #1a1a19;
    /* Warmed off pure black: the cards still lift, but the page stops reading
       as a default dark dashboard. Chart colours were validated against
       --surface, which is unchanged. */
    --plane:     #121110;
    --ink:       #ffffff;
    --ink-2:     #c3c2b7;
    --ink-muted: #898781;
    --grid:      #2c2c2a;
    --axis:      #383835;
    --border:    rgba(255, 255, 255, 0.10);
    --wash:      rgba(57, 135, 229, 0.13);
    --sunken:    #232322;
    --border-strong: rgba(255, 255, 255, 0.32);

    --series-value: #256abf;
    --series-bid:   #3987e5;
    --rule:         #a8a69e;

    /* The same eight hues re-stepped for the dark surface, not a second palette.
       Validated against #1a1a19: all eight pass every gate including 3:1
       contrast (worst adjacent CVD ΔE 8.4, normal-vision 19.3). */
    --cat-1: #3987e5;
    --cat-2: #d95926;
    --cat-3: #199e70;
    --cat-4: #c98500;
    --cat-5: #d55181;
    --cat-6: #008300;
    --cat-7: #9085e9;
    --cat-8: #e66767;
    --cat-rest: #898781;

    --good:     #0ca30c;
    --critical: #e07070;

    /* On a dark plane a drop shadow is invisible; the lift has to come from the
       card being lighter than the page, which it already is. Keep a hairline
       ambient only. */
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
  }
}

/* --------------------------------------------------------------- base ---- */

* { box-sizing: border-box; }

body {
  margin: 0 auto;
  padding: 24px 20px 64px;
  max-width: 1280px;
  background: var(--plane);
  color: var(--ink);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
}

h1 {
  font-family: var(--display);
  font-size: clamp(34px, 4.5vw, 44px);
  font-weight: 500;
  margin: 0 0 8px;
  letter-spacing: -0.015em;
  line-height: 1.12;
}
/* Card headings set as ledger column-heads: small caps with the rule running
   out to the card's edge, the way a paper ledger heads each column. */
h2 {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 14px;
  margin: 0 0 10px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--ink-2);
}
h2::after { content: ""; flex: 1; border-top: 1px solid var(--grid); }
h3 { font-size: 13px; margin: 18px 0 8px; color: var(--ink-2); }

/* The page is bracketed by double rules, the accountant's "ruled off" — the
   same mark the settled totals carry below. */
.app-head { margin-bottom: 28px; padding-bottom: 22px; border-bottom: 4px double var(--border-strong); }
.app-head .eyebrow {
  margin: 0 0 12px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.app-head .sub { margin: 0; max-width: 68ch; color: var(--ink-2); }

/* One orchestrated load: header first, then the cards rise in. Cards revealed
   later (results) inherit the same short rise, so new evidence arrives rather
   than pops. */
@media (prefers-reduced-motion: no-preference) {
  .app-head, .starters, .card { animation: rise 380ms cubic-bezier(0.2, 0.7, 0.3, 1) backwards; }
  .starters { animation-delay: 60ms; }
  .col-side .card { animation-delay: 110ms; }
  .col-main .card { animation-delay: 160ms; }
  @keyframes rise {
    from { opacity: 0; transform: translateY(8px); }
  }
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* ------------------------------------------------------------- layout ---- */

.layout {
  display: grid;
  /* minmax(0, …) on both tracks is what keeps a wide table or chart from
     forcing the whole page to scroll sideways. Widened from 340px in phase 2:
     the bidder table gained a strategy column, and at 340 the value and bid
     inputs were squeezed down to a single visible digit. */
  grid-template-columns: minmax(0, 380px) minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}

@media (max-width: 900px) {
  .layout { grid-template-columns: minmax(0, 1fr); }
}

.col-side, .col-main { display: grid; gap: 18px; min-width: 0; }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 18px 20px 20px;
  min-width: 0;
}

.scroll-x { overflow-x: auto; }

/* ------------------------------------------------------------ controls --- */

.field { display: grid; gap: 5px; }
label { font-size: 12px; color: var(--ink-2); }

select, input {
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--axis);
  border-radius: 7px;
  padding: 6px 8px;
  width: 100%;
  min-width: 0;
}

input[type="number"] { font-variant-numeric: tabular-nums; }
select:focus-visible, input:focus-visible, button:focus-visible, summary:focus-visible,
.stage-list button:focus-visible {
  outline: 2px solid var(--series-bid);
  outline-offset: 2px;
}

button {
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--axis);
  border-radius: 7px;
  padding: 6px 12px;
  cursor: pointer;
  transition: background var(--speed), border-color var(--speed), color var(--speed),
              box-shadow var(--speed), transform var(--speed);
}
button:hover:not(:disabled) { background: var(--sunken); }
button:active:not(:disabled) { transform: translateY(1px); }
button:disabled { opacity: 0.42; cursor: default; }

button.primary {
  background: var(--series-bid);
  border-color: var(--series-bid);
  color: #ffffff;
  font-weight: 600;
  box-shadow: 0 6px 16px -10px color-mix(in srgb, var(--series-bid) 80%, transparent);
}
button.primary:hover:not(:disabled) { filter: brightness(1.08); background: var(--series-bid); }

button.ghost { border-style: dashed; color: var(--ink-2); width: 100%; margin-top: 8px; }

.mech-desc { margin: 8px 0 0; color: var(--ink-2); font-size: 13px; }

.params { display: grid; gap: 10px; margin-top: 14px; }
.params .param-desc { margin: 2px 0 0; font-size: 12px; color: var(--ink-muted); }

.error {
  margin: 12px 0 0;
  padding: 9px 11px;
  border-radius: 7px;
  border: 1px solid var(--critical);
  background: color-mix(in srgb, var(--critical) 9%, transparent);
  color: var(--ink);
  font-size: 13px;
}

/* -------------------------------------------------------- bidder table --- */

table { border-collapse: collapse; width: 100%; }

.bidder-table th {
  text-align: left;
  font-size: 11px;
  font-weight: 500;
  color: var(--ink-muted);
  padding: 0 6px 4px 0;
}
.bidder-table td { padding: 3px 6px 3px 0; }
.bidder-table td:last-child, .bidder-table th:last-child { width: 30px; padding-right: 0; }
.bidder-table .remove {
  padding: 4px 8px;
  line-height: 1;
  color: var(--ink-muted);
  border-color: transparent;
}
.bidder-table .remove:hover:not(:disabled) { color: var(--critical); border-color: var(--axis); }

/* --------------------------------------------------------- stage list ---- */

.stage-list { list-style: none; margin: 0; padding: 0; counter-reset: stage; }
.stage-empty { color: var(--ink-muted); font-size: 13px; }

.stage-list li + li { margin-top: 2px; }

.stage-list button {
  width: 100%;
  display: flex;
  align-items: baseline;
  gap: 9px;
  text-align: left;
  border: 1px solid transparent;
  background: none;
  padding: 6px 9px;
  color: var(--ink-muted);
}
.stage-list button:hover { background: var(--sunken); }

.stage-list .marker {
  flex: none;
  width: 1.5em;
  font-variant-numeric: tabular-nums;
  font-size: 12px;
}

.stage-list .is-done button { color: var(--ink-2); }
.stage-list .is-current button {
  color: var(--ink);
  font-weight: 600;
  background: var(--wash);
  border-color: color-mix(in srgb, var(--series-bid) 35%, transparent);
}

/* --------------------------------------------------------- step panel ---- */

.step-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.step-count { margin: 0; font-size: 12px; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
/* The one heading that changes as you step: same serif as the masthead, so the
   page has two typographic anchors rather than one lonely one. */
.step-label {
  display: block;
  font-family: var(--display);
  font-size: 26px;
  font-weight: 500;
  text-transform: none;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 2px 0 0;
}
.step-label::after { content: none; }

@media (prefers-reduced-motion: no-preference) {
  .step-label.is-in { animation: step-in 240ms cubic-bezier(0.2, 0.7, 0.3, 1); }
  @keyframes step-in {
    from { opacity: 0; transform: translateY(4px); }
  }
}

/* The walkthrough's progress, as a rail across the card's top edge. app.js sets
   --step-progress to (step+1)/steps on each render. */
.step-card { position: relative; overflow: hidden; }
.step-card::before {
  content: "";
  position: absolute;
  top: 0; left: 0;
  height: 3px;
  width: calc(var(--step-progress, 0) * 100%);
  background: var(--series-bid);
  transition: width 240ms ease;
}

.chip {
  display: inline-block;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--sunken);
  border: 1px solid var(--border);
  color: var(--ink-2);
  font-size: 12px;
  white-space: nowrap;
}
.chip-stage { font-family: var(--mono); }
.chip .k { color: var(--ink-muted); }

.detail { margin: 12px 0 0; max-width: 76ch; }

.formula {
  margin: 12px 0 0;
  padding: 10px 12px;
  background: var(--sunken);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--ink);
  overflow-x: auto;
  white-space: pre;
}

.transport { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--grid); }
.transport .hint { font-size: 12px; color: var(--ink-muted); margin-left: auto; }

/* -------------------------------------------------------------- chart ---- */

.caption { margin: -4px 0 12px; font-size: 13px; color: var(--ink-2); }

.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.chips:empty { display: none; }
/* A long id list (`ranked` with a dozen bidders) has to wrap inside the card
   rather than push the page sideways. */
.chips .chip { white-space: normal; overflow-wrap: anywhere; max-width: 100%; }

.chart svg { display: block; width: 100%; height: auto; }

.chart .grid-line { stroke: var(--grid); stroke-width: 1; }
.chart .axis-line { stroke: var(--axis); stroke-width: 1; }
.chart .tick-label { fill: var(--ink-muted); font-size: 11px; font-variant-numeric: tabular-nums; }
.chart .rule-line { stroke: var(--rule); stroke-width: 1.5; }
.chart .rule-label { fill: var(--ink-2); font-size: 11px; font-variant-numeric: tabular-nums; }

.chart .row-band { fill: var(--wash); }
.chart .name-label { fill: var(--ink-2); font-size: 12px; }
.chart .bar-label { fill: var(--ink-2); font-size: 11px; font-variant-numeric: tabular-nums; }

.chart .bar-value { fill: var(--series-value); }
.chart .bar-bid   { fill: var(--series-bid); }

/* The payment notch: a 2px surface gap doing the separating, then a thin tick. */
.chart .pay-gap  { stroke: var(--surface); stroke-width: 4; }
.chart .pay-tick { stroke: var(--ink-2); stroke-width: 2; }

/* Emphasis, not a second palette: unhighlighted rows recede but stay readable,
   and the two shades must still separate after they are dimmed. */
.chart .row.is-dim .bar-value,
.chart .row.is-dim .bar-bid { opacity: 0.5; }
.chart .row.is-dim .name-label,
.chart .row.is-dim .bar-label { fill: var(--ink-muted); }

.chart .row.is-marked .name-label { fill: var(--ink); font-weight: 600; }

.chart .hit { fill: transparent; }
.chart .row:hover .bar-value, .chart .row:hover .bar-bid { filter: brightness(1.1); }
.chart .hit:focus-visible { outline: 2px solid var(--series-bid); outline-offset: -2px; }

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
  font-size: 12px;
  color: var(--ink-2);
}
.legend li { display: flex; align-items: center; gap: 7px; }
.legend .swatch { width: 14px; height: 10px; border-radius: 2px; flex: none; }
.legend .key-line { width: 14px; height: 0; border-top: 2px solid var(--rule); flex: none; }
.legend .key-tick { width: 2px; height: 12px; background: var(--ink-2); flex: none; }
.legend .key-glyph { color: var(--ink); flex: none; }

/* --------------------------------------------------------- table view ---- */

.table-view { margin-top: 14px; }
.table-view summary { cursor: pointer; font-size: 12px; color: var(--ink-2); }

.data-table { margin-top: 10px; font-size: 13px; }
.data-table th, .data-table td {
  padding: 5px 12px 5px 0;
  text-align: right;
  font-variant-numeric: tabular-nums;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.data-table th:first-child, .data-table td:first-child { text-align: left; }
.data-table thead th { font-size: 11px; font-weight: 500; color: var(--ink-muted); }
.data-table .neg { color: var(--critical); }

/* ------------------------------------------------------------- result ---- */

.stat-row { display: flex; flex-wrap: wrap; gap: 10px 32px; margin-bottom: 6px; }
.stat { min-width: 88px; }
.stat .stat-label { display: block; font-size: 12px; color: var(--ink-2); }
.stat .stat-value { display: block; font-size: 26px; font-weight: 600; letter-spacing: -0.02em; }
/* The signature mark: accounting's double underline. A total wearing it is
   settled — the payments have been ruled off and nothing below changes it. */
.stat .stat-value.hero {
  display: inline-block;
  font-size: 40px;
  padding-bottom: 3px;
  border-bottom: 4px double var(--border-strong);
}
.stat .stat-value.muted { color: var(--ink-2); font-size: 22px; }

.badge { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; }
.badge.is-good { color: var(--good); }
.badge.is-bad  { color: var(--critical); }

.note { margin: 10px 0 0; color: var(--ink-2); font-size: 13px; }

/* ------------------------------------------------------------- footer ---- */

/* Matched to .app-head's rule so the page is bracketed rather than trailing off.
   body already carries 64px of bottom padding, which is the breathing room. */
.app-foot {
  margin-top: 32px;
  padding-top: 20px;
  border-top: 4px double var(--border-strong);
  color: var(--ink-2);
  font-size: 13px;
}
.app-foot .foot-line { margin: 0; max-width: 68ch; }
.app-foot .foot-meta { margin-top: 5px; color: var(--ink-muted); font-size: 12px; }

/* Links are underlined everywhere rather than colour-only: at --ink-2 on --plane a
   hue shift alone would be the sole cue, which fails for anyone who cannot see it. */
.app-foot a { color: var(--series-bid); text-decoration: underline; text-underline-offset: 2px; }
.app-foot a:hover { color: var(--ink); }

/* ------------------------------------------------------------ tooltip ---- */

.tooltip {
  position: fixed;
  z-index: 20;
  pointer-events: none;
  min-width: 132px;
  padding: 8px 10px;
  background: var(--surface);
  border: 1px solid var(--axis);
  border-radius: 8px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.16);
  font-size: 12px;
}
.tooltip .tt-head { font-weight: 600; color: var(--ink); margin-bottom: 4px; }
.tooltip .tt-row { display: flex; align-items: center; gap: 7px; }
.tooltip .tt-key { color: var(--ink-2); margin-right: auto; }
.tooltip .tt-val { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.tooltip .tt-line { width: 12px; height: 0; border-top: 2px solid currentColor; flex: none; }

/* ===========================================================================
   Phase 2 — strategies, rounds, bid paths. Everything below wraps around the
   phase 1 UI above; nothing above was restyled to make room for it.
   =========================================================================== */

/* -------------------------------------------------- strategy column ------- */

/* A number the reader cannot see is worse than no column at all: hold the
   existing inputs at a legible width and let the card scroll if the strategy
   column pushes past it, rather than letting the table crush them. */
.bidder-table td input[type="text"] { min-width: 44px; }
.bidder-table td input[type="number"] { min-width: 56px; }

.bidder-table .strategy-cell { width: 122px; min-width: 122px; }
.strategy-cell select { font-size: 12px; padding: 4px 6px; }

.row-params { display: grid; gap: 5px; margin-top: 5px; }
.row-param { display: grid; gap: 2px; font-size: 11px; color: var(--ink-muted); }
.row-param input { font-size: 12px; padding: 3px 6px; }

/* The typed bid, dimmed once a run has shown the strategy never read it. The
   input's own aria-label and title say so too, so opacity is never the only
   thing carrying the state. */
.bidder-table input.is-ignored { opacity: 0.45; }

.strategy-notes:empty { display: none; }
.strategy-notes { margin-top: 12px; display: grid; gap: 6px; }
.strategy-note { margin: 0; font-size: 12px; line-height: 1.4; color: var(--ink-muted); }
.strategy-note .k { color: var(--ink-2); font-weight: 600; }

.rand-row { display: flex; align-items: flex-end; gap: 10px; margin-top: 10px; }
.rand-row .rounds-field { width: 82px; flex: none; }
.rand-row button { flex: 1; padding: 9px 12px; }

/* ---------------------------------------------------- round timeline ------ */

.round-timeline { display: flex; flex-wrap: wrap; gap: 4px; list-style: none; margin: 0; padding: 0; }

.round-timeline button {
  min-width: 32px;
  padding: 5px 7px;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
  border-color: var(--border);
}
.round-timeline .is-current button {
  color: var(--ink);
  font-weight: 600;
  background: var(--wash);
  border-color: color-mix(in srgb, var(--series-bid) 45%, transparent);
}
/* The round the bids stopped changing, marked on the timeline as well as the
   chart — the two must never disagree. */
.round-timeline .is-settled button { box-shadow: inset 0 -3px 0 var(--rule); }

/* --------------------------------------------------------- verdict -------- */

/* Deliberately neutral. Converging is not "good" and still moving is not "bad";
   colouring them as status would state an opinion the data does not support. */
.verdict {
  display: flex;
  gap: 9px;
  align-items: baseline;
  margin: 0 0 14px;
  padding: 9px 12px;
  max-width: 78ch;
  border: 1px solid var(--border);
  border-left: 3px solid var(--rule);
  border-radius: 7px;
  background: var(--sunken);
  font-size: 13px;
  color: var(--ink);
}
.verdict .glyph { flex: none; color: var(--ink-2); font-weight: 700; }

#series-stats { margin-bottom: 4px; }
#series-stats .stat-value { font-size: 22px; }
#series-note { margin: 0 0 14px; }

/* ------------------------------------------------------ bid-path chart ---- */

.path-chart svg { display: block; width: 100%; height: auto; }

.path-chart .grid-line { stroke: var(--grid); stroke-width: 1; }
.path-chart .axis-line { stroke: var(--axis); stroke-width: 1; }
.path-chart .tick-label { fill: var(--ink-muted); font-size: 11px; font-variant-numeric: tabular-nums; }
.path-chart .axis-title { fill: var(--ink-muted); font-size: 11px; }
.path-chart .rule-label { fill: var(--ink-2); font-size: 11px; }

.path-chart .round-band { fill: var(--wash); }
.path-chart .settle-line { stroke: var(--rule); stroke-width: 1.5; }
.path-chart .cross-line { stroke: var(--axis); stroke-width: 1; }

/* The value is a ceiling, not a series: hairline and dashed so it reads as a
   threshold, in the bidder's own hue so it pairs with their bid line. */
.path-chart .value-line { stroke-width: 1; stroke-dasharray: 3 3; opacity: 0.55; }
.path-chart .bid-line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
/* The 2px surface ring, so two bidders on the same bid are still two marks. */
.path-chart .bid-dot { stroke: var(--surface); stroke-width: 2; }
.path-chart .end-label { fill: var(--ink-2); font-size: 11px; font-variant-numeric: tabular-nums; }

.path-chart .hit { fill: transparent; cursor: pointer; }

.legend .key-stroke { width: 16px; height: 0; border-top: 2px solid currentColor; flex: none; }
.legend .key-dash { width: 16px; height: 0; border-top: 2px dashed var(--ink-muted); flex: none; }

/* ------------------------------------------------------ decision panel ---- */

.decision { padding: 12px 0; border-top: 1px solid var(--border); }
.decision:first-child { padding-top: 0; border-top: 0; }

.decision-head { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; }
.decision-head .series-dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.decision-id { font-weight: 600; }
.decision-bid { font-size: 13px; color: var(--ink); font-variant-numeric: tabular-nums; }
.decision-value { font-size: 12px; color: var(--ink-muted); font-variant-numeric: tabular-nums; }

.decision-why { margin: 6px 0 0; max-width: 78ch; color: var(--ink-2); }

.considered { margin-top: 8px; }
.considered summary { cursor: pointer; font-size: 12px; color: var(--ink-2); }
.considered .data-table { max-width: 420px; }
.data-table .is-chosen { color: var(--ink); font-weight: 600; }

/* ===========================================================================
   Phase 3a — the slot ladder. Additive: nothing above was restyled, and a
   trace without an allocation never unhides #ladder-card, so single-winner
   mechanisms render exactly as they did in phase 2.

   The split bar reuses the bidder chart's OWN two-step blue ordinal ramp
   rather than opening a second colour language on one page: the light step is
   the gross quantity, the strong step is the committed one — value/bid above,
   utility/payment here. Re-checked with the dataviz palette validator in
   ordinal mode against these two surfaces:

     light  #86b6ef -> #2a78d6   light end 2.06:1 vs #fcfcfb   ALL CHECKS PASS
     dark   #256abf -> #3987e5   light end 3.23:1 vs #1a1a19   ALL CHECKS PASS

   The light end sits at the documented ordinal floor, which carries a "relief
   required" obligation: the ladder is a table, so every number the bar encodes
   is already a labelled cell in the same row, and no value is colour-only.
   =========================================================================== */

/* The whole ladder is its own table view, so the bar needs no separate twin. */
.ladder-table td.slot { color: var(--ink-2); }
.ladder-table td.bar { width: 34%; min-width: 120px; padding-right: 0; }

.ladder-bar { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 9px; align-items: center; }
.ladder-plot { min-width: 0; }

.ladder-track {
  display: flex;
  align-items: stretch;
  /* The surface gap doing the separating — never a border around a segment. */
  gap: 2px;
  height: 14px;
}
/* Rounded data-end, square at the baseline. */
.ladder-track span { border-radius: 0; }
.ladder-track .is-end { border-radius: 0 4px 4px 0; }
.ladder-track .seg-pays    { background: var(--series-bid); }
.ladder-track .seg-utility { background: var(--series-value); }

.ladder-total { flex: none; font-size: 11px; color: var(--ink-2); font-variant-numeric: tabular-nums; }

/* =========================================================================
   Phase 3b — combinatorial auctions.

   The gap bars reuse the same two-step ordinal ramp as the slot ladder rather
   than opening a third colour language on one page: the strong step is what
   greedy achieved, the light step what was available. Identity comes from each
   row's own text label, so there is no legend and nothing is encoded by colour
   alone.
   ========================================================================= */

.package-table td.items-cell input { min-width: 12ch; }
.package-table tr.xor-alt td { background: color-mix(in srgb, var(--series-value) 9%, transparent); }

.xor-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 10px;
  letter-spacing: 0.03em;
  color: var(--ink-2);
  background: color-mix(in srgb, var(--series-value) 22%, transparent);
  vertical-align: middle;
}

.gap-hero { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
/* Same settled-total double rule as the outcome hero stat. */
.gap-figure {
  font-size: 30px;
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  padding-bottom: 2px;
  border-bottom: 4px double var(--border-strong);
}
.gap-caption { font-size: 12px; color: var(--ink-2); }

.gap-bars { display: grid; gap: 7px; }
.gap-row { display: grid; grid-template-columns: minmax(0, 11ch) minmax(0, 1fr) auto; gap: 9px; align-items: center; }
.gap-label { font-size: 11px; color: var(--ink-2); }
.gap-plot { min-width: 0; }

.gap-bar {
  display: block;
  height: 14px;
  /* Rounded data-end, square at the baseline — same as every other bar here. */
  border-radius: 0 4px 4px 0;
}
.gap-bar.is-greedy  { background: var(--series-bid); }
.gap-bar.is-optimal { background: var(--series-value); }

.gap-value { font-size: 11px; color: var(--ink-2); font-variant-numeric: tabular-nums; }

.bundle-table td.items-cell { color: var(--ink); }

/* =========================================================================
   Phase 4 — the day: budgets, spend, and what steers them.

   The line charts reuse the categorical slot colours from the bid-path chart,
   so a bidder keeps one hue across every chart on the page. Budget ceilings are
   the same hue dashed, because a budget is not a second entity — it is that
   bidder's own limit.
   ========================================================================= */

.world-box { margin-top: 12px; border-top: 1px solid var(--border); padding-top: 10px; }
.world-box summary { cursor: pointer; font-size: 12px; color: var(--ink-2); }
.world-box > .caption { margin: 8px 0; }
.world-fields { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.world-fields .field { flex: 1 1 5.5rem; min-width: 0; }
.budget-table td:first-child { color: var(--ink-2); white-space: nowrap; }

.chart-figure { margin: 0 0 20px; }
.chart-figure:last-child { margin-bottom: 0; }
.chart-figure .caption { margin-top: 6px; }

.line-chart { width: 100%; height: auto; display: block; }
.line-chart .grid { stroke: var(--grid); stroke-width: 1; }
.line-chart .tick, .line-chart .axis-title { font-size: 10px; fill: var(--ink-muted); }
.line-chart .end-label { font-size: 10px; }
.line-chart .line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
/* A budget is a ceiling, not a measurement — dashed says "this is the limit". */
.line-chart .line.is-dashed { stroke-dasharray: 4 4; stroke-width: 1.5; opacity: 0.75; }
/* 2px surface ring so overlapping dots stay countable. */
.line-chart .dot { stroke: var(--surface); stroke-width: 2; }

/* =========================================================================
   Phase 6 — the front door: worked examples, and one run button at a time.

   No new colour: the active chip and the active mode both use the same --wash
   band and --series-bid border the stage list already uses for "this is the one
   you are looking at", so a third selected-thing on the page reads as the same
   idea rather than a new one.
   ========================================================================= */

.starters {
  margin-bottom: 18px;
  padding: 16px 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.starters-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 14px; }
.starters-head h2 { margin: 0; }
/* The sentence for the example currently loaded. It moves as chips are pressed,
   so it is the one line that says what the charts below are showing. */
.starters-now { margin: 0; flex: 1 1 32ch; min-width: 0; font-size: 13px; color: var(--ink-2); }

.starter-chips { margin: 12px 0 0; gap: 7px; }

.chip.starter {
  cursor: pointer;
  font-weight: 500;
  color: var(--ink-2);
  background: var(--surface);
  border-color: var(--axis);
  /* A chip is a label, not a paragraph: it may wrap, but the whole sentence
     lives in the tooltip and the accessible name rather than on the chip. */
  max-width: 34ch;
  text-align: left;
}
.chip.starter { transition: background var(--speed), border-color var(--speed), color var(--speed), transform var(--speed), box-shadow var(--speed); }
.chip.starter:hover {
  background: var(--sunken);
  color: var(--ink);
  transform: translateY(-1px);
  box-shadow: 0 3px 10px -6px rgba(0, 0, 0, 0.35);
}
.chip.starter[aria-pressed="true"] {
  color: var(--ink);
  font-weight: 600;
  background: var(--wash);
  border-color: color-mix(in srgb, var(--series-bid) 45%, transparent);
}

/* ---------------------------------------------------------- mode switch --- */

.mode-switch {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2px;
  margin-top: 18px;
  padding: 2px;
  background: var(--sunken);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.mode-switch button {
  border: 1px solid transparent;
  background: none;
  padding: 5px 6px;
  font-size: 12px;
  color: var(--ink-2);
  border-radius: 6px;
}
.mode-switch button:hover:not([aria-pressed="true"]) { color: var(--ink); background: none; }
.mode-switch button[aria-pressed="true"] {
  color: var(--ink);
  font-weight: 600;
  background: var(--surface);
  border-color: color-mix(in srgb, var(--series-bid) 35%, transparent);
}

.mode-desc { margin: 8px 0 0; font-size: 12px; color: var(--ink-muted); }

.run-bar { display: flex; align-items: flex-end; gap: 10px; margin-top: 12px; }
.run-bar .rounds-field { width: 82px; flex: none; }
.run-bar button { flex: 1; padding: 9px 12px; }

/* ------------------------------------------------ phase 5: equilibrium ---- */

/* One line, so one hue — the reply curve is a single series and a second colour
   would imply a second identity. Slot 1 for the same reason the bid-path chart
   starts there. */
#eq-curve .line-chart .line { stroke: var(--cat-1); }
#eq-curve .line-chart .dot { fill: var(--cat-1); }
/* The argmax, ringed rather than recoloured: which bid is best is also stated in
   the sentence under the chart, so the mark is a shortcut and never the only
   place the answer appears. */
#eq-curve .line-chart .dot.is-best { fill: var(--surface); stroke: var(--cat-1); stroke-width: 3; }
/* Zero earns the axis weight: under all-pay rules the curve crosses it, and
   "this bid loses money" is the whole reading. */
.line-chart .grid.is-zero { stroke: var(--axis); }
.line-chart .rule-line { stroke: var(--rule); stroke-width: 1.5; stroke-dasharray: 3 3; }

.chip.is-on { background: var(--wash); border-color: var(--series-bid); color: var(--ink); }

.verdict.is-good { border-left: 3px solid var(--good); }
.verdict.is-bad  { border-left: 3px solid var(--critical); }
.verdict { flex-direction: column; gap: 4px; }
.verdict-flag { font-weight: 600; }
.verdict.is-good .verdict-flag { color: var(--good); }
.verdict.is-bad  .verdict-flag { color: var(--critical); }

.data-table td.is-good { color: var(--good); }
.data-table td.is-bad  { color: var(--critical); }

#equilibrium-card h3 { margin: 22px 0 4px; font-size: 15px; }
#equilibrium-card h3:first-child { margin-top: 0; }
