  :root {
    --bg: #ffffff;
    --bg-soft: #f6f4f0;
    --panel: #ffffff;
    --panel-2: #faf8f5;
    --line: rgba(20,18,15,0.10);
    --line-strong: rgba(20,18,15,0.20);
    --ink: #1a1714;
    --ink-soft: #56524b;
    --ink-faint: #8b867d;
    --paper: #1a1714;
    --amber: #ef6a2b;
    --amber-soft: rgba(239,106,43,0.12);
    --teal: #168577;
    --teal-soft: rgba(22,133,119,0.10);
    --blue: #3b62d6;
    --blue-soft: rgba(59,98,214,0.10);
    --radius: 18px;
    --shadow: 0 20px 44px -28px rgba(20,18,15,0.30);
    --maxw: 1180px;
  }

  * { box-sizing: border-box; }
  html { scroll-behavior: smooth; }
  /* Short pages (connect, about) don't fill the viewport, so the footer would
     float mid-screen. Column flex + a growing main pins it to the bottom. */
  body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: "Hanken Grotesk", system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    line-height: 1.55;
    overflow-x: hidden;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
  }
  /* width:100% is load-bearing: main carries .wrap's `margin: 0 auto`, and an
     auto cross-axis margin cancels the flex stretch, shrinking it to fit-content. */
  body > main { flex: 1 0 auto; width: 100%; }

  a { color: inherit; }

  .wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 24px; }

  /* ---------- Nav ---------- */
  .nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding-bottom: 22px;
  }
  .nav-brand {
    font-family: "Fraunces", Georgia, serif;
    font-weight: 600;
    font-size: 20px;
    letter-spacing: -0.01em;
    text-decoration: none;
  }
  .nav-links { display: flex; gap: 24px; }
  /* Selection is a short amber underline, not a pill: the active item reads
     as ink over faint, with a 2px rule beneath it. No box, no oval. */
  .nav-links a {
    font-size: 16px;
    font-weight: 600;
    color: var(--ink-faint);
    text-decoration: none;
    padding-bottom: 3px;
    border-bottom: 2px solid transparent;
    transition: color .2s, border-color .2s;
  }
  .nav-links a:hover { color: var(--ink); }
  .nav-links a[aria-current="page"] {
    color: var(--ink);
    border-bottom-color: var(--amber);
  }
  @media (max-width: 520px) {
    .nav-links { gap: 18px; }
    .nav-links a { font-size: 15px; }
    .nav-brand { font-size: 18px; }
  }

  /* ---------- Hero ---------- */
  header.hero {
    position: relative;
    padding: 30px 0 22px;
    overflow: hidden;
    border-bottom: 1px solid var(--line);
    background:
      radial-gradient(900px 420px at 78% -8%, rgba(255,122,61,0.10), transparent 60%),
      radial-gradient(760px 420px at 8% 4%, rgba(102,194,184,0.08), transparent 60%);
  }
  .hero-arc {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    opacity: 0.5;
  }
  .hero-arc path {
    fill: none;
    stroke: var(--amber);
    stroke-width: 2;
    stroke-dasharray: 3 11;
    stroke-linecap: round;
    opacity: 0.55;
    animation: drift 9s linear infinite;
  }
  @keyframes drift { to { stroke-dashoffset: -140; } }

  /* A plain uppercase kicker with a dot — no pill, no border. */
  .eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    margin-bottom: 6px;
    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-faint);
  }
  .eyebrow .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--amber); box-shadow: 0 0 0 4px var(--amber-soft); }

  h1 {
    font-family: "Fraunces", Georgia, serif;
    font-weight: 600;
    font-size: clamp(30px, 4.2vw, 46px);
    line-height: 1.07;
    letter-spacing: -0.02em;
    margin: 6px 0 0;
    max-width: 26ch;
    text-wrap: balance;
  }
  /* The italic 'd' of "good" overhangs its own advance width, so against the
     h1's -0.02em tracking its ascender crosses the upright '?' that follows.
     0.07em clears the collision; 0.10em starts reading as a stray space. */
  h1 .toss, .lede .toss { font-style: italic; color: var(--amber); margin-right: 0.07em; }
  /* Questions are de-prioritised: smaller and quieter than the two
     prioritised lines (the headline and the framing tag) that flank them. */
  .lede {
    margin: 16px 0 0;
    max-width: 54ch;
    font-size: 14.5px;
    color: var(--ink-soft);
  }
  .lede strong { color: var(--ink); font-weight: 600; }
  /* The framing line is prioritised: darkest ink, bold, sized up. */
  .hero-tag {
    display: inline-flex;
    align-items: flex-start;
    gap: 10px;
    margin: 22px 0 0;
    font-size: 16px;
    font-weight: 700;
    letter-spacing: -0.005em;
    color: var(--ink);
  }
  .hero-tag .dot { flex: none; margin-top: 9px; width: 7px; height: 7px; border-radius: 50%; background: var(--amber); box-shadow: 0 0 0 4px var(--amber-soft); }

  /* ---------- Compare bar ---------- */
  .compare {
    margin: 26px auto 4px;
  }
  .compare-inner {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    background: var(--bg-soft);
    border: 1px solid var(--line);
    border-radius: 14px;
    padding: 16px 20px;
  }
  .compare-label {
    font-family: "Fraunces", Georgia, serif;
    font-weight: 600;
    font-size: 16px;
    letter-spacing: -0.01em;
    white-space: nowrap;
  }
  .compare-selects {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    flex: 1;
  }
  .select-wrap { position: relative; display: inline-flex; }
  .compare select {
    appearance: none;
    -webkit-appearance: none;
    font-family: inherit;
    font-size: 14.5px;
    font-weight: 600;
    color: var(--ink);
    background: var(--panel);
    border: 1px solid var(--line-strong);
    border-radius: 10px;
    padding: 10px 38px 10px 14px;
    cursor: pointer;
    min-width: 190px;
    transition: border-color .2s, box-shadow .2s;
  }
  .compare select:hover { border-color: var(--ink-faint); }
  .compare select:focus {
    outline: none;
    border-color: var(--amber);
    box-shadow: 0 0 0 3px var(--amber-soft);
  }
  .select-wrap::after {
    content: "";
    position: absolute;
    right: 15px;
    top: 50%;
    width: 8px;
    height: 8px;
    border-right: 2px solid var(--ink-faint);
    border-bottom: 2px solid var(--ink-faint);
    transform: translateY(-65%) rotate(45deg);
    pointer-events: none;
  }
  .compare .vs { color: var(--ink-faint); font-size: 13px; font-style: italic; }
  .compare-clear {
    font-family: inherit;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--ink-soft);
    background: transparent;
    border: 1px solid var(--line-strong);
    border-radius: 999px;
    padding: 9px 16px;
    cursor: pointer;
    transition: color .2s, border-color .2s, opacity .2s;
    white-space: nowrap;
  }
  .compare-clear:hover { color: var(--ink); border-color: var(--ink-faint); }
  .compare-clear[hidden] { display: none; }

  /* ---------- Section heading ---------- */
  .section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    margin: 24px 0 18px;
    flex-wrap: wrap;
  }
  .section-head h2 {
    font-family: "Fraunces", Georgia, serif;
    font-weight: 600;
    font-size: 24px;
    letter-spacing: -0.01em;
    margin: 0;
  }
  .section-head .count { color: var(--ink-faint); font-size: 14px; }

  /* ---------- Gallery: one flat tile grid ---------- */
  /* A single grid, no sections. The tile size is the driver: auto-fill of
     ~300px+ tracks yields three tiles per row on desktop, two on tablet, one
     on mobile. render() orders the tiles Claude-block then Codex, each by
     effort high→low then model. align-items:start so an expanded rating
     panel grows only its own tile, not the whole row. */
  .gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
    align-items: start;
    gap: 26px;
    padding-bottom: 40px;
  }
  /* Guarantee at least three tiles per row on desktop (the .wrap caps at
     1180px, so this never overflows to a fourth). */
  @media (min-width: 940px) {
    .gallery { grid-template-columns: repeat(3, 1fr); }
  }

  .card {
    background: linear-gradient(180deg, var(--panel), var(--bg-soft));
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
    box-shadow: var(--shadow);
    transition: transform .35s cubic-bezier(.2,.7,.2,1), border-color .35s;
    display: flex;
    flex-direction: column;
  }
  .card:hover { transform: translateY(-4px); border-color: var(--line-strong); }

  .stage {
    position: relative;
    aspect-ratio: 16 / 9;
    background: #060607;
    overflow: hidden;
  }
  .stage video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  .stage::after {
    content: "";
    position: absolute;
    inset: 0;
    box-shadow: inset 0 0 0 1px rgba(255,255,255,0.05);
    pointer-events: none;
  }

  /* pending / coming-soon stage */
  .stage.pending {
    display: grid;
    place-items: center;
    background:
      repeating-linear-gradient(135deg, rgba(20,18,15,0.04) 0 14px, transparent 14px 28px),
      #eeece8;
  }
  .pending-inner { text-align: center; color: var(--ink-faint); }
  .pending-inner .ring {
    width: 46px; height: 46px; margin: 0 auto 14px;
    border-radius: 50%;
    border: 2px dashed var(--line-strong);
    display: grid; place-items: center;
    font-size: 18px;
    animation: spin 14s linear infinite;
  }
  @keyframes spin { to { transform: rotate(360deg); } }
  .pending-inner span { font-size: 13px; letter-spacing: 0.04em; }

  .body { padding: 20px 22px 22px; display: flex; flex-direction: column; gap: 14px; flex: 1; }

  .titles { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; }
  .model {
    font-family: "Fraunces", Georgia, serif;
    font-size: 23px;
    font-weight: 600;
    letter-spacing: -0.01em;
    margin: 0;
    line-height: 1.1;
  }
  .model .fam { color: var(--ink-faint); font-weight: 400; font-style: italic; }
  .blurb { color: var(--ink-soft); font-size: 14.5px; margin: -4px 0 0; }

  .pills { display: flex; flex-wrap: wrap; gap: 8px; }
  .pill {
    display: inline-flex; align-items: center; gap: 7px;
    font-size: 12.5px;
    font-weight: 500;
    padding: 6px 11px;
    border-radius: 999px;
    border: 1px solid var(--line);
    color: var(--ink-soft);
    background: rgba(20,18,15,0.02);
    white-space: nowrap;
  }
  .pill .glyph { font-size: 12px; display: inline-flex; align-items: center; }
  .pill .glyph svg { display: block; }
  .pill.local { color: #0e6155; border-color: rgba(22,133,119,0.45); background: var(--teal-soft); }
  .pill.cloud { color: #2a48ad; border-color: rgba(59,98,214,0.40); background: var(--blue-soft); }

  /* ---------- Build figures ----------
     Build time is a lone scalar, so it gets its own line. Tokens and cost share
     the same input/output/total split, so they are the two rows of a small
     table with that split named once in the header rather than repeated per
     row. Alignment carries the table: the single rule above it is the only one.
     Token counts are abbreviated to three significant figures — the digits past
     that are noise on a gallery card, and three numeric columns of full-length
     integers overflow a 320px card. assets/data.js keeps the exact values. */
  .stats { padding-top: 12px; border-top: 1px solid var(--line); }
  .stats-time {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    font-size: 13px;
    padding-bottom: 11px;
  }
  .stats-time .k { color: var(--ink-soft); }
  .stats-time .v { font-weight: 600; font-variant-numeric: tabular-nums; }

  .figs { width: 100%; border-collapse: collapse; font-size: 13px; }
  .figs thead th {
    font-size: 9.5px;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--ink-faint);
    font-weight: 600;
    text-align: right;
    padding: 0 0 2px 14px;
  }
  .figs tbody th {
    text-align: left;
    font-weight: 400;
    color: var(--ink-soft);
    padding: 6px 0 0;
  }
  .figs td {
    text-align: right;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    padding: 6px 0 0 14px;
  }
  /* unrecoverable logs — recessive, so a gap never reads as a measurement */
  .figs .none { color: var(--ink-faint); font-weight: 400; }
  /* 320px cards leave ~16px of slack at the default gutter; tighten it so the
     narrowest phones keep a real margin rather than a coincidental one. */
  @media (max-width: 360px) {
    .figs thead th, .figs td { padding-left: 10px; }
  }

  .sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }

  .actions { margin-top: auto; padding-top: 6px; }
  .play {
    display: inline-flex; align-items: center; gap: 10px;
    font-weight: 600;
    font-size: 14.5px;
    padding: 12px 18px;
    border-radius: 12px;
    text-decoration: none;
    border: 1px solid transparent;
    background: var(--amber);
    color: #1a0d06;
    transition: transform .2s, box-shadow .2s, background .2s;
  }
  .play:hover { transform: translateY(-2px); box-shadow: 0 14px 30px -14px rgba(255,122,61,0.7); }
  .play .arrow { transition: transform .2s; }
  .play:hover .arrow { transform: translateX(3px); }

  .play.disabled {
    background: transparent;
    border: 1px solid var(--line-strong);
    color: var(--ink-faint);
    cursor: default;
    pointer-events: none;
  }

  .notes { margin: 8px 0 26px; }
  .notes h2 {
    font-family: "Fraunces", Georgia, serif;
    font-weight: 600;
    font-size: 22px;
    letter-spacing: -0.01em;
    margin: 0 0 14px;
  }
  .notes-box {
    background: var(--bg-soft);
    border: 1px solid var(--line);
    border-radius: 12px;
    padding: 18px 24px;
  }
  .notes-box .notes-list {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
  }
  .notes-box .notes-list p {
    font-size: 14px;
    line-height: 1.6;
    color: var(--ink-soft);
    margin: 0;
    padding-left: 22px;
    text-indent: -22px;
  }
  .notes-box .fn {
    display: inline-block;
    width: 22px;
    text-indent: 0;
    color: var(--ink-faint);
    font-weight: 600;
  }
  .notes-box code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.92em;
    padding: 1px 5px;
    border-radius: 5px;
    background: var(--bg);
    border: 1px solid var(--line);
    color: var(--ink-soft);
  }

  /* ---------- Evaluate ---------- */
  .eval { border-top: 1px solid var(--line); margin-top: 2px; padding-top: 14px; }
  .eval-summary {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; flex-wrap: wrap;
  }
  .eval-score { display: flex; align-items: center; gap: 9px; min-width: 0; }
  .eval-score .lbl { font-size: 12px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-faint); }
  .eval-score .num { font-weight: 600; font-size: 14px; color: var(--ink); }

  .eval-toggle {
    border: 1px solid var(--line-strong); background: rgba(20,18,15,0.02);
    color: var(--ink-soft); font: inherit; font-size: 13px; font-weight: 600;
    padding: 7px 13px; border-radius: 999px; cursor: pointer;
    transition: background .2s, color .2s, border-color .2s; white-space: nowrap;
  }
  .eval-toggle:hover { color: var(--ink); border-color: var(--ink-faint); }

  .eval-form { margin-top: 14px; display: none; flex-direction: column; gap: 2px; }
  .eval-form.open { display: flex; }

  /* header over the rating column */
  .crit-head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 12px; margin-bottom: 4px; padding-bottom: 8px;
    border-bottom: 1px solid var(--line);
  }
  .crit-head .hint { font-size: 12.5px; color: var(--ink-faint); }
  .crit-head .yours {
    font-size: 11px; font-weight: 600; letter-spacing: 0.09em;
    text-transform: uppercase; color: var(--ink-faint);
  }
  .eval.rated .crit-head { display: none; }

  .crit {
    display: flex; align-items: center;
    padding: 4px 8px; margin: 0 -8px; border-radius: 8px;
    transition: background .12s;
  }
  .crit:hover { background: rgba(20,18,15,0.035); }
  .eval.rated .crit:hover { background: none; }
  .crit .name { flex: 0 1 auto; font-size: 13.5px; color: var(--ink-soft); }
  /* flexible spacer pushing the thumbs to the right */
  .crit .lead { flex: 1 1 auto; min-width: 12px; }
  .crit .agg { flex: none; font-size: 12.5px; font-weight: 600; color: var(--ink); white-space: nowrap; }
  /* per-row community number shows only in the read-only breakdown */
  .eval:not(.rated) .crit .agg { display: none; }

  .picker { display: inline-flex; align-items: center; gap: 6px; flex: none; }
  .eval.rated .picker { display: none; } /* breakdown view hides the inputs */
  .vote {
    display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 26px; padding: 0; cursor: pointer; line-height: 0;
    border: 1px solid var(--line-strong); border-radius: 7px;
    background: rgba(20,18,15,0.02); color: var(--ink-faint);
    transition: color .12s, border-color .12s, background .12s, transform .12s;
  }
  .vote:hover { transform: translateY(-1px); color: var(--ink-soft); border-color: var(--ink-faint); }
  .vote.down svg { transform: rotate(180deg); }
  .vote.up.on {
    color: var(--teal); border-color: var(--teal); background: rgba(31,138,112,0.1);
  }
  .vote.down.on {
    color: #b5462b; border-color: #b5462b; background: rgba(181,70,43,0.1);
  }

  .eval-label {
    font-size: 13px; font-weight: 600; color: var(--ink-soft);
    margin-top: 8px; margin-bottom: 4px;
  }
  .eval.rated .eval-label { display: none; }
  .eval-comment {
    width: 100%; resize: vertical; min-height: 48px; font: inherit; font-size: 13.5px;
    color: var(--ink); padding: 9px 11px; border: 1px solid var(--line);
    border-radius: 10px; background: var(--panel-2);
  }
  .eval-comment:focus { outline: none; border-color: var(--amber); }
  .eval-actions { display: flex; align-items: center; gap: 12px; margin-top: 2px; }
  .eval-submit {
    border: 1px solid transparent; background: var(--amber); color: #1a0d06;
    font: inherit; font-weight: 600; font-size: 13.5px; padding: 9px 16px;
    border-radius: 10px; cursor: pointer; transition: transform .2s, box-shadow .2s, opacity .2s;
  }
  .eval-submit:hover { transform: translateY(-1px); box-shadow: 0 12px 26px -14px rgba(255,122,61,0.7); }
  .eval-submit:disabled { opacity: 0.55; cursor: default; transform: none; box-shadow: none; }
  .eval-msg { font-size: 12.5px; color: var(--ink-faint); }
  .eval-msg.ok { color: var(--teal); }
  .eval-msg.err { color: #b5462b; }

  /* post-submit: hide the inputs entirely, show a confirmation */
  .eval.rated .eval-comment,
  .eval.rated .eval-actions { display: none; }
  .eval-done {
    display: none; margin-top: 12px; font-size: 13px; font-weight: 600;
    color: var(--teal);
  }
  .eval.rated .eval-done { display: block; }

  /* ---------- Methodology prose ----------
     The article sets one measure for everything: prose and chart share the
     same width so the page reads as a single column rather than a narrow
     text ribbon with a wide figure bolted on. ~800px of content lands near
     90 characters per line, the top of the comfortable range; past that the
     eye starts losing its place on the return sweep. */
  .article { max-width: 900px; }
  .prose { max-width: none; margin: 0 0 42px; }
  .prose h2 {
    font-family: "Fraunces", Georgia, serif;
    font-weight: 600;
    font-size: 27px;
    letter-spacing: -0.01em;
    margin: 46px 0 12px;
  }
  .prose h2:first-child { margin-top: 0; }
  /* "More to come" rides in the heading rather than trailing the section, so a
     reader knows the list is unfinished at the point they decide whether to
     read it. Borrows the eyebrow's language: sans, uppercase, amber dot, but
     ink-soft type — amber on amber-soft only reaches 2.7:1, well under the
     4.5:1 this size needs. */
  .prose h2 .more {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    vertical-align: middle;
    margin-left: 12px;
    font-family: "Hanken Grotesk", system-ui, sans-serif;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-soft);
    background: var(--amber-soft);
    border-radius: 999px;
    padding: 6px 12px;
  }
  .prose h2 .more::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--amber);
  }
  /* Body size is set against the shared measure, not chosen in isolation: at
     15.5px an 850px column ran to 103 characters a line, well past the ~90
     where the eye starts losing the return sweep. Larger type is what buys a
     comfortable line length without narrowing the column away from the chart. */
  .prose p { font-size: 19px; line-height: 1.6; color: var(--ink-soft); margin: 0 0 16px; }
  .prose p.lead { color: var(--ink); font-weight: 500; }
  .prose ul { margin: 0 0 16px; padding-left: 22px; }
  .prose li { font-size: 19px; line-height: 1.6; color: var(--ink-soft); margin-bottom: 10px; }
  .prose strong { color: var(--ink); font-weight: 600; }
  .prose code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.9em;
    padding: 1px 5px;
    border-radius: 5px;
    background: var(--bg-soft);
    border: 1px solid var(--line);
  }
  .prose a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--line-strong); }
  .prose a:hover { border-bottom-color: var(--amber); }

  .pull {
    margin: 30px 0;
    padding: 4px 0 4px 22px;
    border-left: 3px solid var(--amber);
  }
  /* .prose .pull p rather than .pull p: the narrow-screen body rule further
     down matches .prose p at the same specificity and would otherwise win on
     source order, shrinking the quote to body size. */
  .prose .pull p {
    font-family: "Fraunces", Georgia, serif;
    font-size: 23px;
    line-height: 1.4;
    font-style: italic;
    color: var(--ink);
    margin: 0 0 10px;
  }
  .pull cite {
    font-style: normal;
    font-size: 15px;
    color: var(--ink-faint);
  }
  @media (max-width: 640px) {
    .pull { margin: 24px 0; padding-left: 16px; }
    .prose .pull p { font-size: 19px; }
  }

  .prose p.cta { margin-top: 30px; }
  .prose p.cta a {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-weight: 600;
    font-size: 16px;
    padding: 12px 20px;
    border-radius: 12px;
    border: 1px solid transparent;
    background: var(--amber);
    color: #1a0d06;
    transition: transform .2s, box-shadow .2s;
  }
  .prose p.cta a:hover { transform: translateY(-2px); box-shadow: 0 14px 30px -14px rgba(255,122,61,0.7); }

  .callout {
    background: var(--bg-soft);
    border: 1px solid var(--line);
    border-left: 3px solid var(--amber);
    border-radius: 12px;
    padding: 18px 22px;
    margin: 0 0 8px;
  }
  /* 19px suits an 850px column at ~90 characters a line. On a phone the same
     size drops the line to 34 characters, which is below the comfortable
     floor, so the type steps back down with the column. */
  @media (max-width: 640px) {
    .prose p, .prose li { font-size: 16.5px; }
    .prose h2 { font-size: 23px; margin-top: 36px; }
    /* The pill drops to its own line here, so the inline gap would leave it
       indented off the column edge. */
    .prose h2 .more { margin-left: 0; }
  }

  .callout p:last-child, .callout ul:last-child { margin-bottom: 0; }
  .asof {
    margin: 30px 0 0;
    padding-top: 16px;
    border-top: 1px solid var(--line);
    font-size: 15px;
    color: var(--ink-faint);
  }
  /* the opening statement sets up the page, so it carries a touch more weight
     than the sections that follow */
  .prose.intro { margin-bottom: 12px; }
  .prose.intro p { font-size: 20px; }
  @media (max-width: 640px) { .prose.intro p { font-size: 17px; } }
  .prose p.source { font-size: 14px; color: var(--ink-faint); margin-top: 18px; }

  /* A transcript screenshot inside the text column. The capture is portrait
     and nearly 1400px tall, so it is capped well short of the 900px measure:
     at full width the figure alone would outrun the viewport and split the
     argument it belongs to across two screens. */
  .prose figure.shot { margin: 26px 0 28px; }
  .prose figure.shot img {
    display: block;
    width: 100%;
    max-width: 430px;
    height: auto;
    margin: 0 auto;
    border: 1px solid var(--line);
    border-radius: 12px;
  }
  .prose figure.shot figcaption {
    max-width: 430px;
    margin: 12px auto 0;
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--ink-faint);
  }

  /* ---------- Chart ----------
     Four model families, four hues. Fifteen per-build hues would be an
     anti-pattern: past eight, categorical colours stop being separable under
     colour-vision deficiency. Effort tier is carried by a direct label, not a
     hue.

     Hue now carries the harness, so the chart answers "Claude or Codex?"
     before you reach the legend: the three Claude families are warm (amber,
     brick red, oxblood) and the Codex family is cool (blue). Within a
     temperature the families separate by LIGHTNESS, not hue, because
     red-green CVD collapses hue differences and lightness survives it. That is
     the whole trick — three warms only work as a light-to-dark ladder.

     The whole palette was re-validated against the #f6f4f0 chart surface
     with an all-pairs check — Machado-2009 severity-1 dichromat simulation +
     CIEDE2000 — for the four-hue set:
       · protanopia   worst pair ΔE 15.2  (opus~opus5)    floor 8
       · deuteranopia worst pair ΔE 12.9  (fable~opus5)   floor 8
       · tritanopia   worst pair ΔE 11.0  (fable~opus5)   floor 8
       · normal       worst pair ΔE 18.3  (fable~opus5)   floor 15
       · contrast     min 3.41:1 (fable)                  floor 3
     --fam-opus5 is a brick red in the slot between the amber and the oxblood,
     darker than the amber so lightness separates the two under red-green CVD;
     a saturated green/olive there failed protanopia hard, collapsing onto the
     amber at ΔE ~2. --fam-opus went teal -> oxblood in the same pass.
     Re-run the all-pairs check (method above) before changing any hue. */
  .chartwrap {
    --fam-fable: #d95f24;
    --fam-opus:  #6b0f0f;
    --fam-opus5: #bc383b;
    --fam-gpt56: #2c4fc0;
    --plot-axis: #c9c5bc;
    position: relative;
    background: var(--bg-soft);
    border: 1px solid var(--line);
    border-radius: 14px;
    padding: 18px 20px 14px;
    margin: 0 0 16px;
  }

  .chart-controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 6px;
  }
  .seg { display: inline-flex; gap: 3px; background: rgba(20,18,15,0.05); border-radius: 10px; padding: 3px; }
  .seg button {
    font: inherit;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--ink-soft);
    background: transparent;
    border: 0;
    border-radius: 8px;
    padding: 7px 14px;
    cursor: pointer;
    transition: background .18s, color .18s;
  }
  .seg button:hover { color: var(--ink); }
  .seg button[aria-pressed="true"] { background: var(--panel); color: var(--ink); box-shadow: 0 1px 2px rgba(20,18,15,.10); }
  .seg button:focus-visible { outline: 2px solid var(--amber); outline-offset: 1px; }

  .chart-legend { display: flex; flex-wrap: wrap; gap: 8px 18px; font-size: 14px; color: var(--ink-soft); }
  .chart-legend span { display: inline-flex; align-items: center; gap: 7px; }
  .chart-legend i { width: 11px; height: 11px; border-radius: 50%; display: block; }

  .chart-note { font-size: 13.5px; color: var(--ink-faint); margin: 2px 0 0; }

  /* The plot keeps a readable minimum width; when the card is narrower than
     that, this container scrolls sideways rather than the page doing so. */
  #plot { overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; }
  #plot.scrolls { cursor: grab; }
  .plot { display: block; overflow: visible; }
  .plot .axisline { stroke: var(--plot-axis); stroke-width: 1; }
  .plot text { font-family: "Hanken Grotesk", system-ui, sans-serif; }
  .plot .tick { font-size: 13px; fill: var(--ink-faint); }
  .plot .axistitle { font-size: 13px; fill: var(--ink-soft); font-weight: 600; }
  /* What the y-axis plots, and that it is logarithmic. This sits outside the
     SVG so the badge can be a real filled pill, and so it stays put when a
     narrow card scrolls the plot sideways. */
  .scaleline {
    display: flex;
    align-items: center;
    gap: 9px;
    flex-wrap: wrap;
    margin: 0 0 8px;
    font-size: 14px;
    color: var(--ink-soft);
  }
  .scaleline .what { font-weight: 600; }
  /* A log axis read as a linear one understates every gap by orders of
     magnitude, so the scale is bold and full-strength ink against the muted
     descriptor either side of it. */
  .scale-em {
    font-weight: 700;
    color: var(--ink);
    white-space: nowrap;
  }
  .scaleline .sep { color: var(--line-strong); }
  .scaleline .gloss { font-size: 13px; color: var(--ink-faint); }

  .plot .ptlabel { font-size: 13px; fill: var(--ink-soft); }

  /* Marks and the axis furniture animate when the scale changes, so a
     rescale is something the reader watches happen rather than a jump that
     could be misread as the data changing. */
  .plot .mark, .plot .ptlabel, .plot .ytick {
    transition: transform .55s cubic-bezier(.3,.7,.2,1), opacity .35s ease;
  }
  .plot .hit { fill: transparent; cursor: pointer; }
  .plot .pt { outline: none; }
  .plot .pt.off { opacity: 0; pointer-events: none; }
  .plot .pt:focus-visible .ring { stroke: var(--ink); stroke-width: 2.5; }

  /* resize recomputes the whole layout, so suppress the tween for that pass */
  .plot.no-anim .mark, .plot.no-anim .ptlabel,
  .plot.no-anim .ytick { transition: none; }

  @media (prefers-reduced-motion: reduce) {
    .plot .mark, .plot .ptlabel, .plot .ytick { transition: none; }
  }

  .tip {
    position: absolute;
    z-index: 5;
    min-width: 190px;
    background: var(--paper);
    color: #f7f5f1;
    border-radius: 10px;
    padding: 11px 13px;
    font-size: 13px;
    line-height: 1.5;
    pointer-events: none;
    opacity: 0;
    transform: translate(-50%, -100%);
    transition: opacity .15s;
    box-shadow: 0 18px 40px -18px rgba(20,18,15,.6);
  }
  .tip.on { opacity: 1; }
  .tip .t-model { font-weight: 700; margin-bottom: 5px; }
  .tip dl { display: grid; grid-template-columns: auto auto; gap: 2px 14px; margin: 0; }
  .tip dt { color: rgba(247,245,241,.62); }
  .tip dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }

  /* ---------- Connect page ---------- */
  /* Bare icons — no button chrome, no circle. They colour on hover; the
     focus ring appears only for keyboard users (an affordance, not decoration). */
  .connect-links {
    display: flex;
    gap: 26px;
    align-items: center;
    padding: 22px 0 40px;
  }
  .connect-link {
    display: inline-grid;
    place-items: center;
    padding: 6px;
    color: var(--ink-soft);
    transition: color .2s, transform .2s;
  }
  .connect-link:hover { color: var(--amber); transform: translateY(-2px); }
  .connect-link:focus-visible {
    outline: 2px solid var(--amber);
    outline-offset: 5px;
    border-radius: 8px;
  }

  /* ---------- Footer ---------- */
  footer {
    border-top: 1px solid var(--line);
    margin-top: 40px;
    padding: 34px 0 60px;
    color: var(--ink-faint);
    font-size: 13.5px;
  }
  footer .wrap { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
  footer a { color: var(--ink-soft); text-decoration: none; border-bottom: 1px solid var(--line-strong); }
  footer a:hover { color: var(--ink); }
