/* Portal-specific components on top of the vendored brand system (SF-266).
   Extends — never overrides — tokens.css + style.css. Token vars only;
   no raw colors, sizes, or fonts (brand SYSTEM.md rule). */

/* ---- status regions (loading / error / empty) ---------------------- */
.state {
  font-family: var(--f-mono);
  font-size: var(--text-sm);
  color: var(--ink-2);
  padding: var(--space-6) 0;
  line-height: var(--leading-snug);
}
.state-error { color: var(--blind); }
.state-empty, .state-loading { color: var(--ink-3); }
.state[hidden] { display: none; }
[hidden] { display: none !important; }

/* ---- sortable table headers ---------------------------------------- */
/* The button inherits the thead label treatment from style.css; only the
   chrome reset and the sort arrow live here. */
.sort-button {
  background: none;
  border: none;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  cursor: pointer;
  padding: 0;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}
.sort-button:hover { color: var(--ink); }
.sort-button .arrow { opacity: 0; }
th[aria-sort="ascending"] .sort-button .arrow,
th[aria-sort="descending"] .sort-button .arrow { opacity: 1; }

/* ---- verified badge -------------------------------------------------- */
/* Square, mono, gain-colored: color carries the one story meaning. */
.badge-verified {
  display: inline-block;
  font-family: var(--f-mono);
  font-size: var(--text-label);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--success-text-high);
  background: var(--success-bg-subtle);
  border: var(--border-hairline) solid var(--success-border);
  border-radius: var(--radius-none);
  padding: 0 var(--space-2);
  white-space: nowrap;
}

/* ---- tables: portal extras ------------------------------------------ */
.table-wrap { overflow-x: auto; margin: 0 0 var(--space-5); }
.table-wrap table { margin: 0; }
/* min-width keeps narrow viewports from crushing the column to a sliver —
   the .table-wrap x-scroll takes over instead. Derived from the space scale
   (2 × the largest step) so it stays tied to the token system. */
td.cell-wrap { white-space: normal; overflow-wrap: break-word; min-width: calc(2 * var(--space-12)); }
table .btn { white-space: nowrap; }

/* ---- spec page run region ------------------------------------------- */
.run-region { margin: 0 0 var(--space-5); }
.quiet { font-family: var(--f-mono); font-size: var(--text-micro); color: var(--ink-2); }

/* ---- screen-reader-only text ----------------------------------------- */
/* Non-visual a11y utility (standard clip pattern); carries meaning that
   color alone must not — e.g. the sota row highlight. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---- benchmark tab strip --------------------------------------------- */
/* Same visual language as .rail .crumbs (hairline underline for the active
   item) rather than a new pattern — one nav idiom for the whole portal. */
.tabstrip {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
  border-bottom: var(--border-hairline) solid var(--line);
  margin: 0 0 var(--space-5);
  font-family: var(--f-mono);
  font-size: var(--text-sm);
}
.tabstrip a {
  display: inline-block;
  padding: var(--space-3) 0;
  color: var(--ink-2);
  text-decoration: none;
  border-bottom: var(--border-strong) solid transparent;
}
.tabstrip a:hover { color: var(--ink); }
.tabstrip a[aria-current="page"] {
  color: var(--ink);
  border-bottom-color: var(--accent-solid);
}
/* WHY: benchmark.html ships the nav empty and initTabStrip's failure path is
   deliberately silent, so on an API error (or zero registered benchmarks) the
   bare element still painted its border-bottom — a hairline rule floating above
   the masthead — and still announced an empty "Benchmarks" navigation landmark. */
.tabstrip:empty { display: none; }

/* The long tail of non-featured boards, folded into a "More benchmarks" disclosure. The button sits
   at the strip's end; opening it drops a floating overlay (see .tabstrip-more-panel below) — a
   search over a single vertical, scrollable column. Styled as the portal's other inputs: square,
   hairline, mono, neutral ink — accent only on focus/open. */
.tabstrip-more-btn {
  margin-left: auto;
  align-self: center;
  font-family: var(--f-mono);
  font-size: var(--text-sm);
  color: var(--ink-2);
  background: var(--bg);
  padding: var(--space-2) var(--space-3);
  border: var(--border-hairline) solid var(--line-2);
  border-radius: var(--radius-none);
  cursor: pointer;
}
.tabstrip-more-btn:hover { color: var(--ink); }
.tabstrip-more-btn[aria-expanded="true"] { color: var(--ink); border-color: var(--accent-solid); }
/* An OVERLAY, not an inline block: absolute inside the position:relative .tabstrip, anchored under
   the button at the strip's right edge. It floats over the content below so opening it never
   shoves the page down. Depth reads from the seam + a single soft shadow is avoided (SFDS) — the
   hairline border and elevated surface carry it; z-index lifts it above the masthead below. */
.tabstrip-more-panel {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  z-index: 30;
  width: 20rem;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: var(--border-hairline) solid var(--line-2);
  border-radius: var(--radius-none);
}
.tabstrip-more-search {
  font-family: var(--f-mono);
  font-size: var(--text-sm);
  color: var(--ink);
  background: var(--bg);
  padding: var(--space-3);
  border: 0;
  border-bottom: var(--border-hairline) solid var(--line);
  border-radius: var(--radius-none);
  outline: none;
}
.tabstrip-more-search:focus { border-bottom-color: var(--accent-solid); }
.tabstrip-more-list { max-height: 16rem; overflow-y: auto; }
/* These links live inside the .tabstrip <nav>, so `.tabstrip a` (0,1,1) would otherwise force them
   inline-block with tab padding and an underline. Scope under .tabstrip-more-list (0,2,x) to win,
   so each benchmark renders as one full-width row, stacked vertically and scrollable. */
.tabstrip-more-list .tabstrip-more-item {
  display: block;
  padding: var(--space-2) var(--space-3);
  border-bottom: 0;
  color: var(--ink-2);
  text-decoration: none;
}
.tabstrip-more-list .tabstrip-more-item:hover { color: var(--ink); background: var(--surface-2); }
.tabstrip-more-list .tabstrip-more-item[aria-current="page"] { color: var(--ink); border-bottom: 0; }
.tabstrip-more-empty { padding: var(--space-3); color: var(--ink-3); font-size: var(--text-sm); }

/* ---- benchmark catalogue cards --------------------------------------- */
/* A grid of clickable cards (echoing the docs' card grid). Square, hairline-sealed, no shadow —
   depth reads from the seam (SFDS). Neutral ink body with one gold "→" accent, like the docs.
   The whole card is the link. Cards are revealed a page at a time; a hidden card uses [hidden]. */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--space-6);
  margin: 0 0 var(--space-6);
}
.cards:empty { display: none; }
.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-6);
  background: var(--bg);
  border: var(--border-hairline) solid var(--line);
  border-radius: var(--radius-none);
  color: var(--ink);
  text-decoration: none;
  transition: border-color .12s;
}
/* Only the edge (blue) and the arrow (gold) react to hover. `color: var(--ink)` keeps the title from
   inheriting the global link-hover blue (a:hover at 0,1,1 would otherwise beat .card at 0,1,0). */
.card:hover { border-color: var(--info-border-strong); color: var(--ink); }
.card:hover .card-go { color: var(--gain-text-high); }
.card:focus-visible { outline: var(--border-strong) solid var(--focus); outline-offset: 2px; }
/* Title row: the board name + a gold open-arrow pinned to the right edge. */
.card-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); }
.card-title {
  font-family: var(--f-sans);
  font-weight: var(--weight-semibold);
  font-size: var(--text-lead);
  line-height: var(--leading-snug);
}
.card-go { color: var(--gain-text-low); font-weight: var(--weight-medium); }
.card-focus { font-family: var(--f-mono); font-size: var(--text-sm); color: var(--ink-2); }
.card-desc { font-size: var(--text-sm); color: var(--ink-2); line-height: var(--leading-snug); }
/* Footer rule, pushed to the card's base so cards of differing text length keep their metric on
   one plane: Best-reproducible label at the left, its value at the right. */
.card-best {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: auto;
  padding-top: var(--space-4);
  border-top: var(--border-hairline) solid var(--line);
}
.card-best-label {
  font-family: var(--f-mono);
  font-size: var(--text-label);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--ink-3);
}
.card-best-val { font-size: var(--text-body); color: var(--gain-text-low); }
.cards-more { display: flex; justify-content: center; margin: 0 0 var(--space-8); }

/* ---- landing hero ---------------------------------------------------- */
/* The front page reads as a classic, research-register landing in the docs' own language: gold
   mono eyebrow, a Parastoo serif title, a quiet subtitle, the board's key terms, and one gold
   button. Generous whitespace; gold is the single accent, used sparingly (eyebrows, button, the
   card arrows) rather than a sales band. */
.hero { padding-top: var(--space-10); margin-bottom: var(--space-5); }
/* Title sits between the display size (38) and the full hero clamp — present and editorial, not a
   billboard. Floors at the display token, caps at ~52px, scaling with the viewport between. */
.hero-title { font-size: clamp(var(--text-display), 5vw, 3.25rem); line-height: var(--leading-tight); }
/* The subtitle: one line naming what the board is. Quiet, constrained measure, snug to read, and
   pulled close under the title so the two read as one unit. */
.hero-lead { max-width: 58ch; margin-top: var(--space-3); color: var(--ink-2); line-height: var(--leading-snug); }
/* The three terms sit directly under the title as the key to reading any board; the button follows
   close beneath them. */
.hero-defs { margin-bottom: var(--space-6); }
/* One monochrome, bold button — softer than a gold fill, still a clear call to start. */
.hero-cta { margin-bottom: var(--space-11); }
.benchmarks-section { margin-top: 0; scroll-margin-top: var(--space-8); }
/* The landing sits slightly narrower than the shared --col-wide (1000) so the hero and card grid
   read tighter; ~920px still holds a comfortable 3-up grid at the 260px card min. Scoped to the
   landing so the per-board leaderboard table keeps the full width. */
.wrap.wide.landing { max-width: 920px; }

/* Accents: gold and blue, rationed and SCOPED TO THE LANDING (`.landing`) so the benchmark, spec and
   data pages keep their neutral styling. Gold (brand) carries the landing's mono eyebrows, the card
   open-arrow and the best-reproducible figure; blue (the always-blue --info role, since --accent is
   gold in the marketing register) carries interaction — plain content links (`:not([class])`, so the
   card and button links are untouched) and the card hover edge. The card accents and hover live in
   the card rules above (card-only, landing-only already). The About page (also `.landing`) inherits
   these. */
.landing .eyebrow { color: var(--gain-text-low); }
.landing a:not([class]) { color: var(--info-text-low); }
.landing a:not([class]):hover { color: var(--info-text-high); }

/* ---- about page ------------------------------------------------------ */
/* Sections under a gold .section-label, prose at a readable measure, with the Thesis "needs to"
   list as square bullets and section links as .btn--link. Reuses the landing hero + .section-label. */
.about-section { margin: 0 0 var(--space-9); }
.about-section > .section-label { margin-bottom: var(--space-4); }
.about-section p { max-width: 66ch; margin: 0 0 var(--space-5); line-height: 1.65; color: var(--ink-2); }
.about-section p:last-child { margin-bottom: 0; }
.about-bullets { max-width: 68ch; margin: var(--space-2) 0 0; padding-left: var(--space-5); list-style: square; color: var(--ink); }
.about-bullets li { margin-bottom: var(--space-3); line-height: 1.55; color: var(--ink-2); }
.about-bullets li:last-child { margin-bottom: 0; }
.about-bullets li::marker { color: var(--ink-3); }
.about-links { display: flex; flex-wrap: wrap; gap: var(--space-5); margin: var(--space-5) 0 0; }

/* The catalogue is led by ONE small, subtle label — the same treatment as the hero eyebrow
   ("SCREAMINGFACE · OPEN LEADERBOARD"), not a big heading. It stays a semantic <h2> for
   screen-reader navigation, just styled as the gold mono micro-label. */
.section-label {
  font-family: var(--f-mono);
  font-weight: var(--weight-medium);
  font-size: var(--text-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  line-height: var(--leading-snug);
  color: var(--gain-text-low);
  margin: 0 0 var(--space-6);
}

/* ---- responsive ------------------------------------------------------ */
@media (max-width: 639px) {
  /* sf:// deep-links are not useful on narrow screens; collapse the column. */
  .col-run { display: none; }
}

/* ---- Weights line in the Backends cell --------------------------------- */
/* The SFDS .status recipe at full tone WITHOUT its .on state: .on is success green, and green
   means verified, which an open-weights verdict is not. The square stays
   ink; the word says open. Closed keeps the recipe's muted square, but its word is data, so it
   takes full --ink-2 instead of the whisper off-state, which misses WCAG AA in the light theme.
   Both rules carry :not(.on) so they out-rank style.css's .status:not(.on) by specificity, not
   by load order. */
.weights-line { display: block; margin-top: var(--space-1); white-space: nowrap; }
.status.status--open:not(.on) { color: var(--ink); }
.status.status--closed:not(.on) { color: var(--ink-2); }
.status.status--open .sq { background: var(--ink); }

/* ---- mark column ----------------------------------------------------- */
/* A column rather than a span inside the spec cell, so the browser handles the
   alignment — see the WHY in benchmark.js's COLUMNS. Narrow and never wrapping:
   it holds one mark or nothing. */
.col-mark {
  width: 1%;
  white-space: nowrap;
}

/* The Pareto-frontier mark identifies a row that is no worse on both axes and better on one.
   Drawn in CSS rather than set as a glyph: IBM Plex Mono is not guaranteed to carry
   U+25C6, and a font fallback would render this mark differently machine to machine.
   Colour is --info, deliberately NOT --gain: gold is rationed to the win and the
   highest-score row already holds it, so a gold mark here would collapse two separate
   claims into one look. Green is also reserved for verified states. */
.pareto-mark {
  display: inline-block;
  width: 8px;
  height: 8px;
  background: var(--info-text-low);
  transform: rotate(45deg);
}
/* Matches the markbox convention: the deep text-low tone reads on a light ground, the
   vivid solid reads on a dark one. */
[data-theme="dark"] .pareto-mark {
  background: var(--info-solid);
}

/* Forced-colors (Windows High Contrast) overrides `background` on non-text elements, which
   would erase this mark completely and leave the row with NO per-row signal — precisely the
   failure "never colour alone" exists to prevent, since the shape is the carrier here. Opt out
   of the override and paint with a system colour so the diamond survives. */
@media (forced-colors: active) {
  .pareto-mark {
    forced-color-adjust: none;
    background: CanvasText;
  }
}

/* ---- rail pinning: the one deliberate override in this file ---------- */
/* WHY: style.css ships `.rail { position: relative }` plus a `.rail.stuck`
   variant its own comment documents as "(JS toggles .stuck + a spacer to hold
   its place)" — the system expects the host page to supply that scroll
   listener. This portal never has, so the rail scrolled away while
   `.rail .toggle` (position: fixed, no background/border per the system) stayed
   pinned top-right — leaving a bare "◐ light" glyph floating over page content,
   and over benchmark.html's rightmost table cells at ~1000px viewports.
   Restoring `sticky` keeps the rail under the fixed toggle at all scroll
   offsets, which is the behavior this portal had before the v2 migration.
   This local override keeps the rail under the fixed toggle without adding a
   second JavaScript-controlled sticky state. */
.rail { position: sticky; top: 0; }

/* WHY: the byte-matched style.css gives .badge-verified a ::before glyph masked
   from /assets/remix/System/check-line.svg, an icon set this portal does not
   vendor — so every verified badge fired a 404. createVerifiedBadge() already
   renders a literal "✓ verified", so the pseudo-element is redundant here as
   well as broken; suppress it rather than vendoring an icon set for one glyph.
   `content: none` alone does not stop the fetch — Chrome still
   resolves the mask URL and fires the 404 (verified in DevTools). The mask
   itself has to be cleared, so keep all three declarations. */
.badge-verified::before {
  content: none;
  -webkit-mask: none;
  mask: none;
}

/* ---- fragment targets clear the rail ------------------------------- */
/* WHY: the rail is sticky at top:0 and its JS re-pins it as `fixed` once scrolled
   past (style.css:44), so a bare fragment jump parks the target under it. Measured
   in Chrome on `index.html#benchmarks`: the heading landed at y=7 with the rail's
   bottom at y=44 — 37px of a 57px heading hidden. Nothing in the vendored CSS sets
   scroll-padding, so this is additive and fixes every in-page anchor. --rail-h is
   the same token the rail's own
   height uses, so the two cannot drift. */
html { scroll-padding-top: calc(var(--rail-h) + var(--space-4)); }

/* ---- masthead nav links -------------------------------------------- */
/* These navigation links are portal-specific rather than part of the vendored style.css.
   WHY the group is a container and not three bare anchors: the theme toggle is
   `position: fixed; right: var(--space-5)` (style.css:58 — it pins itself because the
   rail's sticky is defeated by the page's overflow-x clipping), so it takes NO flex space
   and the rail will happily lay links out underneath it. Measured in Chrome, "◐ light"
   is 55px wide, and the collisions were real in both directions:
     1200px — the mockup's 32px end margin left `docs` overlapping the toggle by 23px;
      375px — the rail wraps (style.css:667) and `github` landed under the toggle.
   A container fixes both: --space-11 reserves the toggle's footprint on desktop, and
   `flex: 0 0 100%` moves the whole group onto its own wrapped line on mobile, where the
   toggle only ever shares row one. */
.rail .rail-nav { display: flex; gap: var(--space-4); margin-right: var(--space-11); }
.rail .rail-link { color: var(--ink-2); text-decoration: none; }
.rail .rail-link:hover { color: var(--ink); }
/* The brand is the home link: keep the wordmark looking exactly as it did as a span. */
.rail a.brand { text-decoration: none; }
/* Hover shifts tone like the other rail links do (ink-2 <-> ink), so the wordmark reads as a link. */
.rail a.brand:hover { color: var(--ink-2); }
@media (max-width: 620px) {
  .rail .rail-nav { flex: 0 0 100%; margin-right: 0; gap: var(--space-3); }
}
/* ---- two-card summary strip ---------------------------------------- */
/* style.css sets `.stats { grid-template-columns: repeat(3,1fr) }` and is vendored,
   so it is not edited. This leaderboard summary has two cards; without a modifier,
   the bordered strip renders them across two thirds of its width, leaving an empty third.
   Scoped to a new class so every other three-card `.stats` strip is untouched.

   This must stay inside a min-width query. style.css collapses `.stats`
   to one column at max-width 620px, but a media query adds NO specificity — both
   rules are a single class, and portal.css loads after style.css, so an
   unconditional `.stats--two` wins at every viewport and phones get two cramped
   side-by-side cards instead of a stack. 621px is the complement of that 620px
   breakpoint; if the vendored breakpoint moves, this must move with it. */
@media (min-width: 621px) {
  .stats--two { grid-template-columns: repeat(2, 1fr); }
}

/* ---- landing page ---------------------------------------------------------
   Everything else the landing page needs (.kv, .note, .o-mark, .btn, .eyebrow)
   comes from style.css. `.defs` carries no rule by design; it is a hook. */

/* The glossary's first key. Green because green means verified in this system
   and gold is reserved for the win. */
.kv .dt-repro { color: var(--success-text-low); }

/* The rail's last link, so nothing sits under the theme glyph. */
.rail .rail-link--end { margin-right: var(--space-7); }

/* The catalogue's Open link never breaks across lines. */
td.col-open { white-space: nowrap; }

/* The mark's key. `.meta` already carries the mono/micro/ink-2 treatment every small label on
   this page uses; this only lays it out. */
.legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
/* WHY a generated separator rather than markup: the frontier item hides itself on boards that
   can carry no mark, and a literal separator span would leave a dangling middot behind it. */
.legend-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
/* Keep `:not([hidden])` on both sides. `display: none` does not remove an element from
   the sibling chain, so a bare `+`/`~` still matches a hidden predecessor — with the frontier
   item hidden, the legend would render a LEADING middot. The
   general sibling combinator is deliberate: it stays correct if more than one item ever hides. */
.legend-item:not([hidden]) ~ .legend-item:not([hidden])::before {
  content: "·";
  color: var(--ink-3);
  margin-right: var(--space-2);
}
.legend-item[hidden] {
  display: none;
}

/* The scroll container is focusable (see benchmark.html), so it needs a visible focus ring like
   any other focus target — otherwise keyboard users land somewhere invisible. */
.table-wrap:focus-visible {
  outline: var(--border-strong) solid var(--focus);
  outline-offset: 2px;
}

/* ---- score/cost Pareto chart --------------------------------------- */
.pareto-chart-section { margin-top: var(--space-7); }
.pareto-chart-figure { background: var(--bg); }
.pareto-chart__svg { min-width: 560px; }
.pareto-chart-scroll { overflow-x: auto; }
.pareto-chart-scroll:focus-visible {
  outline: var(--border-strong) solid var(--focus);
  outline-offset: 2px;
}

.pareto-chart__grid {
  stroke: var(--line);
  stroke-width: var(--border-hairline);
}
.pareto-chart__axis,
.pareto-chart__tick-mark {
  stroke: var(--ink-3);
  stroke-width: var(--border-hairline);
}
.pareto-chart__tick,
.pareto-chart__gutter-label { fill: var(--ink-2); }
.pareto-chart__axis-label { fill: var(--ink); font-weight: var(--weight-semibold); }
.pareto-chart__frontier-line {
  fill: none;
  stroke: var(--info-text-low);
  stroke-width: var(--border-strong);
}
.pareto-chart__dominated-point { fill: var(--ink-3); }
.pareto-chart__frontier-point { fill: var(--info-text-low); stroke: var(--bg); stroke-width: 3px; }
.pareto-chart__unpriced-point { fill: var(--bg); stroke: var(--ink-3); stroke-width: var(--border-strong); }
.pareto-chart__leader-ring { fill: none; stroke: var(--gain); stroke-width: var(--border-strong); }
.pareto-chart__gutter-line {
  stroke: var(--line-2);
  stroke-width: var(--border-hairline);
  stroke-dasharray: 4 4;
}
.pareto-chart__point:hover .pareto-chart__dominated-point,
.pareto-chart__point:hover .pareto-chart__frontier-point,
.pareto-chart__point:hover .pareto-chart__unpriced-point { stroke: var(--ink); }

.pareto-chart-caption {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
}
.pareto-chart-key { display: inline-flex; align-items: center; gap: var(--space-2); }
.pareto-chart-key__dominated,
.pareto-chart-key__frontier,
.pareto-chart-key__leader,
.pareto-chart-key__unpriced {
  display: inline-block;
  width: 10px;
  height: 10px;
  box-sizing: border-box;
}
.pareto-chart-key__dominated { border-radius: 50%; background: var(--ink-3); }
.pareto-chart-key__frontier { width: 8px; height: 8px; background: var(--info-text-low); transform: rotate(45deg); }
.pareto-chart-key__leader { border-radius: 50%; border: var(--border-strong) solid var(--gain); }
.pareto-chart-key__unpriced { border-radius: 50%; border: var(--border-strong) solid var(--ink-3); }

[data-theme="dark"] .pareto-chart__frontier-line { stroke: var(--info-solid); }
[data-theme="dark"] .pareto-chart__frontier-point { fill: var(--info-solid); }
[data-theme="dark"] .pareto-chart-key__frontier { background: var(--info-solid); }

@media (forced-colors: active) {
  .pareto-chart__frontier-line,
  .pareto-chart__frontier-point,
  .pareto-chart__dominated-point,
  .pareto-chart__unpriced-point,
  .pareto-chart__leader-ring { forced-color-adjust: auto; stroke: CanvasText; }
  .pareto-chart__frontier-point { fill: CanvasText; }
  /* The key's swatches are spans coloured by `background`, which forced-colors strips — the
     block above rescues the chart's own marks but not the legend that explains them, leaving
     four labels with nothing to map them to. Same omission the table mark had. */
  .pareto-chart-key__dominated,
  .pareto-chart-key__frontier,
  .pareto-chart-key__leader,
  .pareto-chart-key__unpriced {
    forced-color-adjust: none;
    background: CanvasText;
    border-color: CanvasText;
  }
  .pareto-chart-key__leader,
  .pareto-chart-key__unpriced {
    background: Canvas;
  }
}

@media (max-width: 620px) {
  .pareto-chart-section { margin-top: var(--space-5); }
  .pareto-chart-caption { align-items: flex-start; }
}

/* ---- subscribe ---------------------------------------------------- */
/* The email forms rendered by subscribe.js: one per board, opened from "Follow this board" under
   the title, and one site-wide band above the footer. Extends the vendored .signup row. */
.subscribe { margin: var(--space-10) 0 0; padding-top: var(--space-6); border-top: var(--border-hairline) solid var(--line); }
.subscribe-heading { margin: 0 0 var(--space-2); padding: 0; border: 0; font-family: var(--f-sans); font-size: var(--text-body); font-weight: var(--weight-semibold); color: var(--ink); }
.subscribe-body { margin: 0 0 var(--space-4); font-size: var(--text-sm); color: var(--ink-2); }
.subscribe .signup { justify-content: flex-start; margin: 0 0 var(--space-3); }
.subscribe .signup input.err { border-color: var(--blind); }
/* Focus is the field's own border turning the button's gold, so the row reads as one outline. */
.subscribe .signup input:focus { border-color: var(--accent-solid); }
.subscribe .signup .btn--primary { padding: var(--space-3) var(--space-5); white-space: nowrap; }
.subscribe-trap { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.subscribe-also { display: flex; margin: 0 0 var(--space-3); font-size: var(--text-sm); color: var(--ink-2); }
/* The vendored tick is a masked icon file the portal does not ship, so the box draws its own. */
.subscribe .checkbox input:checked + .checkbox-box::after { -webkit-mask: none; mask: none;
  clip-path: polygon(12% 52%, 26% 38%, 42% 56%, 76% 20%, 90% 34%, 42% 84%); }
.subscribe-status { margin: 0; font-family: var(--f-mono); font-size: var(--text-sm); color: var(--ink-2); }
.subscribe-status:not(:empty) { margin-bottom: var(--space-2); }
.subscribe-status.is-error { color: var(--blind); }
.subscribe-status.is-done { color: var(--success-text-low); }
.subscribe-fine { margin: 0; font-family: var(--f-mono); font-size: var(--text-micro); color: var(--ink-2); }
.subscribe-follow { margin-top: var(--space-4); }
#subscribe-panel.subscribe { margin: calc(-1 * var(--space-6)) 0 var(--space-7); }
.hero-cta { display: flex; flex-wrap: wrap; gap: var(--space-3); }
@media (max-width: 620px) {
  .subscribe .signup { max-width: none; }
}

/* ---- grant banner: one thin strip above the rail on every page ----------------------- */
/* WHY plain tokens only: the strip is an announcement, not the win, so it takes no gold and
   no new colour. The surface fill plus a hairline seam set it apart from the rail below it,
   square and shadowless per the system, and both flip with the theme. It is not sticky: the
   rail pins itself at top 0, so the strip scrolls away and never stacks two bars. */
.grant-banner {
  display: block; padding: var(--space-2) var(--space-5);
  background: var(--surface); border-bottom: var(--border-hairline) solid var(--line);
  font-family: var(--f-sans); font-size: var(--text-sm); line-height: var(--leading-snug);
  text-align: center; color: var(--ink);
}
@media (max-width: 620px) {
  .grant-banner { padding: var(--space-2) var(--space-4); }
}
/* WHY the toggle anchors to the rail: style.css pins it `position: fixed` at half the rail
   height from the VIEWPORT top, which assumed the rail starts at y=0. With the banner above,
   it sat inside the banner until the page scrolled. The rail is already sticky (see "rail
   pinning" above), so positioning the toggle against the rail keeps the same offset inside
   the rail at every scroll position, on desktop and on the wrapped mobile rail. */
.rail .toggle { position: absolute; }
