/* ==========================================================================
   app.css — Pooled Odds

   Direction: an editorial trading terminal. Near-black canvas, warm ink, one
   signal-green accent, hairlines instead of card-soup. Numbers are the
   subject, so they get the size and the tabular figures; labels shrink and
   track out to get out of their way.

   Data-series colours are a separately validated categorical palette (CVD
   separation + contrast checked in both modes). Chrome colours below are the
   brand layer and never encode data.
   ========================================================================== */

@layer base, layout, components, viz, utility;

@layer base {
  :root {
    color-scheme: dark;

    /* Blue-black rather than neutral grey. A dead-neutral #0b0b0c under a lime
       accent is the default dark-theme look; giving the blacks a cold cast and
       the accent warmth makes the two push against each other instead of
       sitting flat. */
    --canvas:     #08090D;
    --surface-1:  #0E1015;
    --surface-2:  #13161C;
    --surface-3:  #1B1F27;
    --surface-4:  #262B36;

    --ink-1: #F2F4F8;
    --ink-2: #9BA3B4;
    --ink-3: #626B7D;

    --hair:      rgba(148,163,196,.13);
    --hair-firm: rgba(148,163,196,.24);
    --grid:      rgba(148,163,196,.09);
    --edge-hint: rgba(255,255,255,.16);
    --axis:      rgba(148,163,196,.28);

    /* Signal accent — live market data, never a data encoding.
       Amber rather than lime: it reads as money against a cold canvas, and it
       leaves green free to mean "up" instead of competing with the brand. */
    --accent:      #FFB627;
    --accent-deep: #C97F09;
    --accent-ink:  #14100A;
    --accent-wash: rgba(255,182,39,.12);

    /* Secondary accent for live/streaming state, so "this is moving" and
       "this is the brand" are not the same colour. */
    --pulse:      #35D0EE;
    --pulse-wash: rgba(53,208,238,.13);

    /* Validated categorical palette (dark steps). */
    --s1:#3987e5; --s2:#d95926; --s3:#199e70; --s4:#c98500;
    --s5:#d55181; --s6:#008300; --s7:#9085e9; --s8:#e66767;

    --good:#18B368; --warning:#FFC53D; --serious:#FF8A4C; --critical:#F2555A;
    --up:#2BD576; --down:#FF5C77;

    --r-xs: 4px; --r-sm: 7px; --r: 11px; --r-lg: 16px;

    --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
    --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace;

    --ease: cubic-bezier(.32,.72,0,1);
    --shadow-1: 0 1px 2px rgba(0,0,0,.4);
    --shadow-2: 0 12px 40px -12px rgba(0,0,0,.75);
  }

  @media (prefers-color-scheme: light) {
    :root:where(:not([data-theme="dark"])) {
      color-scheme: light;
      --canvas:#F4F5F8; --surface-1:#FFFFFF; --surface-2:#EDEFF4;
      --surface-3:#E2E6EE; --surface-4:#D3D9E5;
      --ink-1:#0C0F16; --ink-2:#4A5365; --ink-3:#78829A;
      --hair:rgba(12,15,22,.10); --hair-firm:rgba(12,15,22,.18);
      --grid:rgba(12,15,22,.07); --axis:rgba(12,15,22,.24);
      --edge-hint: rgba(17,17,18,.30);
      --accent:#A16207; --accent-deep:#7C4A05; --accent-ink:#FFFFFF;
      --accent-wash:rgba(161,98,7,.10);
      --pulse:#0E7C99; --pulse-wash:rgba(14,124,153,.12);
      --s1:#2a78d6; --s2:#eb6834; --s3:#1baf7a; --s4:#eda100;
      --s5:#e87ba4; --s6:#008300; --s7:#4a3aa7; --s8:#e34948;
      --up:#0F9D58; --down:#D22D4B;
      --shadow-2: 0 12px 40px -14px rgba(0,0,0,.22);
    }
  }
  :root[data-theme="light"] {
    color-scheme: light;
    --edge-hint: rgba(17,17,18,.30);
    --canvas:#F4F5F8; --surface-1:#FFFFFF; --surface-2:#EDEFF4;
    --surface-3:#E2E6EE; --surface-4:#D3D9E5;
    --ink-1:#0C0F16; --ink-2:#4A5365; --ink-3:#78829A;
    --hair:rgba(12,15,22,.10); --hair-firm:rgba(12,15,22,.18);
    --grid:rgba(12,15,22,.07); --axis:rgba(12,15,22,.24);
    --accent:#A16207; --accent-deep:#7C4A05; --accent-ink:#FFFFFF;
    --accent-wash:rgba(161,98,7,.10);
    --pulse:#0E7C99; --pulse-wash:rgba(14,124,153,.12);
    --s1:#2a78d6; --s2:#eb6834; --s3:#1baf7a; --s4:#eda100;
    --s5:#e87ba4; --s6:#008300; --s7:#4a3aa7; --s8:#e34948;
    --up:#0F9D58; --down:#D22D4B;
    --shadow-2: 0 12px 40px -14px rgba(0,0,0,.22);
  }

  * { box-sizing: border-box; }
  html { -webkit-text-size-adjust: 100%; }

  body {
    margin: 0;
    background: var(--canvas);
    color: var(--ink-1);
    font-family: var(--font);
    font-size: 14px;
    line-height: 1.5;
    letter-spacing: -0.006em;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
  }

  a { color: inherit; text-decoration: none; }
  ::selection { background: var(--accent); color: var(--accent-ink); }

  :focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: var(--r-xs);
  }

  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      animation-duration: .001ms !important;
      transition-duration: .001ms !important;
    }
  }
}

/* ------------------------------------------------------------------ brand */

@layer components {
  .lockup { display: inline-flex; align-items: center; gap: 9px; flex: none; }
  .mark { display: block; flex: none; }
  .wordmark {
    font-size: 15px; letter-spacing: -0.03em; white-space: nowrap;
    display: inline-flex; gap: 3px;
  }
  .wordmark b { font-weight: 640; color: var(--ink-1); }
  .wordmark i { font-style: normal; font-weight: 400; color: var(--ink-3); }

  /* Source marks: real logo when the provider publishes one, else monogram. */
  .srcmark {
    width: var(--sz, 20px); height: var(--sz, 20px);
    border-radius: var(--r-xs);
    display: inline-grid; place-items: center; flex: none;
    font-size: calc(var(--sz, 20px) * .38);
    font-weight: 680; letter-spacing: -0.02em;
    background: color-mix(in srgb, var(--mc, var(--ink-3)) 20%, transparent);
    color: var(--mc, var(--ink-2));
    border: 1px solid color-mix(in srgb, var(--mc, var(--ink-3)) 35%, transparent);
  }
  .srcmark.img { background: var(--surface-3); border-color: var(--hair); padding: 2px; }
  .srcmark.img img { width: 100%; height: 100%; object-fit: contain; display: block; }

  /* Self-hosted brand art. */
  .srcmark.art {
    background: var(--surface-3);
    border: 1px solid var(--hair);
    padding: var(--pad, 2px);
    overflow: hidden;
  }
  .srcmark.art img { width: 100%; height: 100%; object-fit: contain; display: block; }
  /* Marks that ship their own rounded tile must not sit on a second one. */
  .srcmark.art.bleed { background: none; border: 0; padding: 0; }
  /* Polymarket's mark is solid black artwork, which is invisible on a dark
     canvas. Inverting is the only way to show the real logo rather than
     substituting something that is not theirs. */
  .srcmark.art.invert img { filter: invert(1); }
  :root[data-theme="light"] .srcmark.art.invert img { filter: none; }
  @media (prefers-color-scheme: light) {
    :root:where(:not([data-theme="dark"])) .srcmark.art.invert img { filter: none; }
  }

  /* Team crests: real ESPN artwork, abbreviation if it fails to load. */
  .crest {
    width: var(--sz, 22px); height: var(--sz, 22px);
    display: inline-grid; place-items: center; flex: none; position: relative;
  }
  .crest img { width: 100%; height: 100%; object-fit: contain; display: block; }
  .crest em { display: none; }
  .crest.bare {
    background: color-mix(in srgb, var(--tc, var(--ink-3)) 22%, var(--surface-3));
    border: 1px solid var(--hair); border-radius: var(--r-xs);
  }
  .crest.bare em {
    display: block; font-style: normal; font-weight: 660;
    font-size: calc(var(--sz, 22px) * .34); letter-spacing: -0.02em; color: var(--ink-1);
  }
  .matchup { display: inline-flex; align-items: center; gap: 6px; }
  .matchup .at { color: var(--ink-3); font-size: 11px; }
}

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

@layer layout {
  .topbar {
    position: sticky; top: 0; z-index: 60;
    display: flex; align-items: center; gap: 22px;
    height: 58px; padding: 0 22px;
    background: color-mix(in srgb, var(--canvas) 82%, transparent);
    backdrop-filter: blur(16px) saturate(1.6);
    border-bottom: 1px solid var(--hair);
  }

  nav.tabs {
    display: flex; gap: 1px; overflow-x: auto; scrollbar-width: none;
    /* min-width:0 is load-bearing. A flex item defaults to min-width:auto, so
       without this the tab strip refuses to shrink below its content width and
       stretches the topbar — and the whole page — past the viewport instead of
       scrolling inside itself. */
    flex: 1 1 auto; min-width: 0;
  }
  nav.tabs::-webkit-scrollbar { display: none; }
  nav.tabs a {
    position: relative; padding: 8px 13px; border-radius: var(--r-sm);
    color: var(--ink-3); font-size: 13px; font-weight: 480;
    white-space: nowrap; transition: color .18s var(--ease), background .18s var(--ease);
  }
  nav.tabs a:hover { color: var(--ink-1); background: var(--surface-2); }
  nav.tabs a[aria-current="page"] { color: var(--ink-1); font-weight: 560; }
  nav.tabs a[aria-current="page"]::after {
    content: ""; position: absolute; left: 13px; right: 13px; bottom: -1px;
    height: 2px; background: var(--accent); border-radius: 2px 2px 0 0;
  }

  .topbar-right { margin-left: auto; display: flex; align-items: center; gap: 12px; }

  main { padding: 30px 22px 96px; max-width: 1600px; margin: 0 auto; }

  /* Editorial page head: oversized title, rule, standfirst. */
  .page-head { margin-bottom: 14px; max-width: 1600px; }
  .page-head .eyebrow {
    font-size: 10.5px; font-weight: 620; letter-spacing: .13em;
    text-transform: uppercase; color: var(--accent); margin-bottom: 5px;
    display: flex; align-items: center; gap: 8px;
  }
  .page-head h1 {
    margin: 0; font-size: clamp(23px, 2.1vw, 30px); font-weight: 620;
    letter-spacing: -0.035em; line-height: 1.02;
  }
  .page-head .standfirst {
    margin: 14px 0 0; color: var(--ink-2); font-size: 12.5px;
    line-height: 1.62; max-width: 78ch;
  }
  .page-head .standfirst b { color: var(--ink-1); font-weight: 560; }
  .page-head .standfirst em { color: var(--ink-1); font-style: italic; }

  .rule { height: 1px; background: var(--hair); margin: 26px 0; border: 0; }

  .grid { display: grid; gap: 16px; }
  .cols-2 { grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); }
  .cols-3 { grid-template-columns: repeat(auto-fit, minmax(272px, 1fr)); }
  .cols-4 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
  .split-wide {
    display: grid; grid-template-columns: minmax(0,1.6fr) minmax(0,1fr); gap: 16px;
    /* Panels size to their content. Stretching a short chart to match a tall
       neighbour leaves a dead field of empty surface under it. */
    align-items: start;
  }
  @media (max-width: 1080px) { .split-wide { grid-template-columns: 1fr; } }
}

@layer components {
  .panel {
    background: var(--surface-1);
    border: 1px solid var(--hair);
    border-radius: var(--r-lg);
    padding: 20px;
    min-width: 0;
    position: relative;
  }
  .panel.flush { padding: 0; overflow: hidden; }
  .panel-head { margin-bottom: 16px; }
  .panel-head.row { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
  .panel h2 {
    margin: 0; font-size: 13.5px; font-weight: 600;
    letter-spacing: -0.012em; color: var(--ink-1);
  }
  .panel .sub {
    margin: 5px 0 0; color: var(--ink-3); font-size: 12.5px;
    line-height: 1.55; max-width: 68ch;
  }
  .panel .sub b { color: var(--ink-2); font-weight: 560; }
  .panel .sub em { font-style: italic; color: var(--ink-2); }

  /* ------------------------------------------------------------- figures */

  .figure { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
  .figure .label {
    font-size: 10.5px; font-weight: 560; letter-spacing: .1em;
    text-transform: uppercase; color: var(--ink-3);
  }
  .figure .value {
    font-size: 25px; font-weight: 600; letter-spacing: -0.035em;
    line-height: 1; color: var(--ink-1);
    font-variant-numeric: lining-nums;
  }
  .figure .value.md { font-size: 20px; }
  .figure .value.sm { font-size: 16px; letter-spacing: -0.02em; }
  .figure .value .unit { font-size: .48em; font-weight: 500; color: var(--ink-3); margin-left: 2px; }
  .figure .note { font-size: 10.5px; color: var(--ink-3); line-height: 1.35; }

  /* A row of figures beside a title: right-aligned and rigid on a wide screen,
     wrapping and left-aligned once there isn't room for four across. */
  .figrow { display: flex; gap: 26px; flex-wrap: wrap; }
  .figrow .figure { flex: none; text-align: right; }
  @media (max-width: 640px) {
    .figrow { gap: 14px 20px; width: 100%; }
    .figrow .figure { flex: 1 1 calc(50% - 10px); text-align: left; }
  }

  /* Hero tiles carry a hairline top-rule in the accent for rhythm. */
  .tile {
    background: var(--surface-1); border: 1px solid var(--hair);
    border-radius: var(--r); padding: 10px 12px 9px;
    position: relative; overflow: hidden;
    transition: border-color .2s var(--ease), transform .2s var(--ease);
  }
  .tile::before {
    content: ""; position: absolute; inset: 0 auto auto 0;
    width: 100%; height: 1px;
    background: linear-gradient(90deg, var(--accent), transparent 62%);
    opacity: .55;
  }
  .tile:hover { border-color: var(--hair-firm); }

  /* --------------------------------------------------------------- chips */

  .toolbar {
    display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
    margin-bottom: 18px; padding: 9px 11px;
    background: var(--surface-1); border: 1px solid var(--hair);
    border-radius: var(--r);
  }
  .toolbar .spacer { flex: 1; }

  .chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 5px 11px; border-radius: 999px;
    background: transparent; border: 1px solid var(--hair-firm);
    color: var(--ink-2); font-size: 12.5px; font-weight: 480;
    cursor: pointer; user-select: none; white-space: nowrap;
    transition: all .16s var(--ease);
  }
  .chip:hover { color: var(--ink-1); border-color: var(--ink-3); }
  .chip[aria-pressed="true"] {
    background: var(--accent); border-color: var(--accent);
    color: var(--accent-ink); font-weight: 560;
  }
  .chip.static { cursor: default; border-style: dashed; }
  .chip.static:hover { color: var(--ink-2); border-color: var(--hair-firm); }
  .chip .dotmark { width: 7px; height: 7px; border-radius: 2px; flex: none; }

  .field {
    display: inline-flex; align-items: center; gap: 7px;
    font-size: 11px; font-weight: 560; letter-spacing: .07em;
    text-transform: uppercase; color: var(--ink-3);
  }
  select, input[type="search"], input[type="text"] {
    background: var(--surface-3); border: 1px solid var(--hair);
    color: var(--ink-1); padding: 6px 10px; border-radius: var(--r-sm);
    font: inherit; font-size: 12.5px; letter-spacing: 0; text-transform: none;
    transition: border-color .16s var(--ease);
  }
  select:hover, input:hover { border-color: var(--hair-firm); }
  input[type="search"] { min-width: 230px; }
  input[type="search"]::placeholder { color: var(--ink-3); }

  button.ghost {
    background: var(--surface-3); border: 1px solid var(--hair);
    color: var(--ink-2); padding: 6px 12px; border-radius: var(--r-sm);
    font: inherit; font-size: 12.5px; cursor: pointer;
    transition: all .16s var(--ease);
  }
  button.ghost:hover { background: var(--surface-4); color: var(--ink-1); }

  .iconbtn {
    width: 32px; height: 32px; display: grid; place-items: center;
    background: transparent; border: 1px solid var(--hair);
    border-radius: var(--r-sm); color: var(--ink-3);
    cursor: pointer; transition: all .16s var(--ease);
  }
  .iconbtn:hover { color: var(--ink-1); border-color: var(--hair-firm); background: var(--surface-2); }

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

  .tablewrap { overflow-x: auto; min-width: 0; max-width: 100%; }
  table { width: 100%; border-collapse: collapse; font-size: 13px; }
  thead th {
    position: sticky; top: 0; z-index: 2;
    background: var(--surface-1); color: var(--ink-3);
    text-align: left; font-weight: 560; font-size: 10px;
    letter-spacing: .11em; text-transform: uppercase;
    padding: 10px 12px; white-space: nowrap;
    border-bottom: 1px solid var(--hair-firm);
  }
  tbody td {
    padding: 11px 12px; border-bottom: 1px solid var(--grid);
    vertical-align: middle;
  }
  tbody tr { transition: background .14s var(--ease); }
  tbody tr:hover td { background: var(--surface-2); }
  tbody tr:last-child td { border-bottom: 0; }
  td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--mono); font-size: 12px; }
  .t-primary { font-weight: 540; letter-spacing: -0.01em; }
  .t-sub { font-size: 11px; color: var(--ink-3); margin-top: 2px; }

  /* --------------------------------------------------------------- badge */

  .badge {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 2.5px 8px; border-radius: 999px;
    font-size: 10.5px; font-weight: 560; letter-spacing: .02em;
    background: var(--surface-3); color: var(--ink-2);
    border: 1px solid transparent; white-space: nowrap;
  }
  .badge.accent { background: var(--accent-wash); color: var(--accent); border-color: color-mix(in srgb, var(--accent) 28%, transparent); }
  .badge.live { background: color-mix(in srgb, var(--critical) 16%, transparent); color: #ff8b8b; }
  .badge.good { background: color-mix(in srgb, var(--up) 15%, transparent); color: var(--up); }
  .badge.warn { background: color-mix(in srgb, var(--warning) 16%, transparent); color: var(--warning); }
  .badge.ghost { background: transparent; border: 1px dashed var(--hair-firm); color: var(--ink-3); }

  .livedot {
    width: 6px; height: 6px; border-radius: 50%; background: var(--critical);
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--critical) 60%, transparent);
    animation: ping 2s var(--ease) infinite;
  }
  @keyframes ping {
    0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--critical) 55%, transparent); }
    70%  { box-shadow: 0 0 0 7px transparent; }
    100% { box-shadow: 0 0 0 0 transparent; }
  }

  /* nowrap and flex:none are both load-bearing. As a shrinkable flex item at
     the end of the topbar this wrapped to "live ·" / "71 msgs" on two lines and
     pushed the bar taller than its siblings. */
  .ws-state {
    display: flex; align-items: center; gap: 6px; flex: none;
    font-size: 11px; color: var(--ink-3);
    font-variant-numeric: tabular-nums; white-space: nowrap;
  }
  .ws-state .pip {
    width: 6px; height: 6px; border-radius: 50%; background: var(--up); flex: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--up) 22%, transparent);
  }
  .ws-state .pip.stale { background: var(--warning); }
  .ws-state .pip.down  { background: var(--critical); }

  /* ------------------------------------------------------------ meter bar */

  .meter { position: relative; height: 5px; border-radius: 3px; background: var(--surface-4); overflow: hidden; }
  .meter > span { position: absolute; inset: 0 auto 0 0; border-radius: 3px; background: var(--accent); transition: width .5s var(--ease); }

  .stack { display: flex; height: 7px; gap: 2px; }
  .stack > span { display: block; border-radius: 2px; transition: flex .5s var(--ease); }
  .stack > span:first-child { border-radius: 4px 2px 2px 4px; }
  .stack > span:last-child  { border-radius: 2px 4px 4px 2px; }

  .legend { display: flex; flex-wrap: wrap; gap: 14px; font-size: 11.5px; color: var(--ink-2); margin-top: 14px; }
  .legend .item { display: inline-flex; align-items: center; gap: 6px; }
  .legend .sw { width: 9px; height: 9px; border-radius: 2px; flex: none; }

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

  .tooltip {
    position: fixed; z-index: 999; pointer-events: none;
    background: color-mix(in srgb, var(--surface-2) 96%, transparent);
    backdrop-filter: blur(10px);
    border: 1px solid var(--hair-firm); border-radius: var(--r);
    padding: 10px 12px; font-size: 12px; box-shadow: var(--shadow-2);
    max-width: 320px; opacity: 0; transform: translateY(3px);
    transition: opacity .13s var(--ease), transform .13s var(--ease);
  }
  .tooltip.on { opacity: 1; transform: none; }
  .tooltip .t-title { font-weight: 600; margin-bottom: 6px; letter-spacing: -0.01em; display: flex; align-items: center; gap: 6px; }
  .tooltip .t-row { display: flex; justify-content: space-between; gap: 18px; color: var(--ink-3); line-height: 1.65; }
  .tooltip .t-row b { color: var(--ink-1); font-variant-numeric: tabular-nums; font-weight: 540; font-family: var(--mono); font-size: 11.5px; }

  .empty { padding: 42px 22px; text-align: center; }
  .empty h3 { margin: 0 0 7px; color: var(--ink-2); font-size: 13.5px; font-weight: 560; }
  .empty p { margin: 0 auto; max-width: 58ch; font-size: 12.5px; color: var(--ink-3); line-height: 1.6; }

  .note-box {
    background: var(--surface-1);
    border: 1px solid var(--hair);
    border-left: 2px solid var(--accent);
    border-radius: var(--r-sm);
    padding: 13px 16px; font-size: 12.5px; color: var(--ink-2);
    line-height: 1.62; margin-bottom: 18px;
  }
  .note-box b { color: var(--ink-1); font-weight: 560; }
  .note-box code { font-family: var(--mono); font-size: 11.5px; background: var(--surface-3); padding: 1px 5px; border-radius: 4px; color: var(--ink-1); }
  .note-box a { color: var(--accent); border-bottom: 1px solid color-mix(in srgb, var(--accent) 40%, transparent); }
  .note-box.warn { border-left-color: var(--warning); }

  .scroll-y { overflow-y: auto; }
  .scroll-y::-webkit-scrollbar { width: 9px; }
  .scroll-y::-webkit-scrollbar-track { background: transparent; }
  .scroll-y::-webkit-scrollbar-thumb { background: var(--surface-4); border-radius: 5px; border: 2px solid var(--surface-1); }
  .scroll-y::-webkit-scrollbar-thumb:hover { background: var(--ink-3); }
}

/* -------------------------------------------------------------------- viz */

@layer viz {
  svg.chart { display: block; width: 100%; height: auto; overflow: visible; }
  svg.chart text { font-family: var(--font); }
  .axis-label { font-size: 10px; fill: var(--ink-3); letter-spacing: .04em; }
  .axis-line { stroke: var(--axis); stroke-width: 1; }
  .grid-line { stroke: var(--grid); stroke-width: 1; }
  .tick-text { font-size: 10px; fill: var(--ink-3); font-variant-numeric: tabular-nums; }
  .mark-ring { stroke: var(--surface-1); stroke-width: 2; }

  /* Cards reveal in a short stagger — motion that reads as the data landing,
     not as decoration. Disabled wholesale under reduced-motion.

     Every entrance below animates FROM a hidden state TO the element's natural
     one, with no fill-mode holding the start frame. If the animation is
     interrupted, never scheduled, or the class is dropped, the mark is still
     drawn at full opacity — visibility never depends on motion completing. */
  .reveal { animation: reveal .5s var(--ease); }
  @keyframes reveal { from { opacity: 0; transform: translateY(7px); } }

  .bee.pop { animation: pop .42s var(--ease); transform-box: fill-box; transform-origin: center; }
  @keyframes pop { from { opacity: 0; } }

  .row.slidein { animation: slidein .4s var(--ease); }
  @keyframes slidein { from { opacity: 0; transform: translateX(-8px); } }

  .growx { animation: growx .6s var(--ease); transform-box: fill-box; transform-origin: left center; }
  @keyframes growx { from { transform: scaleX(0); } }

  .drawin { animation: drawin .8s var(--ease); stroke-dasharray: var(--len) var(--len); }
  @keyframes drawin { from { stroke-dashoffset: var(--len); } to { stroke-dashoffset: 0; } }

  .flash-up   { animation: fu .9s var(--ease); }
  .flash-down { animation: fd .9s var(--ease); }
  @keyframes fu { from { background: color-mix(in srgb, var(--up) 26%, transparent); } }
  @keyframes fd { from { background: color-mix(in srgb, var(--down) 26%, transparent); } }
}

/* ---------------------------------------------------------------- utility */

@layer utility {
  .mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
  .dim  { color: var(--ink-2); }
  .muted{ color: var(--ink-3); }
  .up   { color: var(--up); }
  .down { color: var(--down); }
  .nowrap { white-space: nowrap; }
  .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
}

/* ------------------------------------------------------------ page pieces */

@layer components {
  /* Market card, prediction-markets page. */
  .mkt:hover { border-color: var(--hair-firm); background: var(--surface-2); }
  .mkt .mkt-head { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
  .mkt .mkt-title { font-weight: 540; font-size: 13.5px; line-height: 1.4; letter-spacing: -0.012em; }
  .mkt .oc { display: flex; align-items: center; gap: 9px; font-size: 12.5px; }
  .mkt .oc .nm { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink-2); }
  .mkt .oc .pv { font-weight: 600; min-width: 48px; text-align: right; font-variant-numeric: tabular-nums; font-family: var(--mono); font-size: 12px; }
  .mkt .mkt-foot {
    display: flex; align-items: center; gap: 14px; margin-top: auto;
    font-size: 11px; color: var(--ink-3); font-variant-numeric: tabular-nums;
    padding-top: 10px; border-top: 1px solid var(--grid);
  }
  .mkt .mkt-foot a { color: var(--accent); }

  /* Tree rows. */
  .tree { font-size: 13px; }
  .tree-row {
    display: flex; align-items: center; gap: 9px;
    padding: 4px 9px 4px 0; border-radius: var(--r-sm);
    transition: background .14s var(--ease);
  }
  .tree-row:hover { background: var(--surface-2); }
  .tree-caret { width: 12px; color: var(--ink-3); flex: none; font-size: 9px; }
  .tree-swatch { width: 8px; height: 8px; border-radius: 2px; flex: none; }
  .tree-name { flex: none; max-width: 330px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .tree-prob { color: var(--ink-1); font-weight: 560; font-size: 12px; flex: none; min-width: 54px; text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }
  .tree-meta { color: var(--ink-3); font-size: 11px; flex: none; font-family: var(--mono); }
  .tree-count { color: var(--ink-3); font-size: 10px; background: var(--surface-3); padding: 1px 7px; border-radius: 999px; flex: none; }
  .tree-bar { margin-left: auto; position: relative; width: 130px; height: 4px; border-radius: 2px; background: var(--surface-4); overflow: hidden; flex: none; }
  .tree-bar > span { position: absolute; inset: 0 auto 0 0; border-radius: 2px; }
  .tree-row.type-sport   > .tree-name { font-weight: 620; font-size: 14px; letter-spacing: -0.02em; }
  .tree-row.type-league  > .tree-name { font-weight: 540; color: var(--ink-2); }
  .tree-row.type-market  > .tree-name { color: var(--ink-2); text-transform: capitalize; }
  .tree-row.type-outcome > .tree-name { color: var(--ink-1); font-weight: 540; }
  .tree-row.type-source  > .tree-name { color: var(--ink-2); font-size: 12px; }
  .tree-row.type-sport { border-top: 1px solid var(--grid); margin-top: 8px; padding-top: 8px; }

  /* Source cards. */
  .srccard { display: flex; flex-direction: column; gap: 10px; }
  .srccard .top { display: flex; align-items: center; gap: 9px; }
  .srccard .nm { font-weight: 600; font-size: 14px; flex: 1; letter-spacing: -0.015em; }
  .srccard .note { font-size: 12.5px; color: var(--ink-2); line-height: 1.55; }
  .srccard .meta { display: flex; gap: 13px; font-size: 11px; color: var(--ink-3); flex-wrap: wrap; font-variant-numeric: tabular-nums; }
  .srccard.dormant { border-style: dashed; background: transparent; }
  .srccard.dormant .nm { color: var(--ink-2); }
  .srccard a { color: var(--accent); font-size: 12px; }
}


/* --------------------------------------------------- alerts: bell & toasts */

@layer components {
  .bellwrap { position: relative; }
  .bell { position: relative; }
  .bell-count {
    position: absolute; top: -4px; right: -4px;
    min-width: 16px; height: 16px; padding: 0 4px;
    border-radius: 999px; background: var(--accent); color: var(--accent-ink);
    font-size: 9.5px; font-weight: 680; line-height: 16px; text-align: center;
    border: 2px solid var(--canvas);
  }

  .bellmenu {
    position: absolute; top: calc(100% + 9px); right: 0; z-index: 80;
    width: min(390px, calc(100vw - 24px));
    background: var(--surface-1); border: 1px solid var(--hair-firm);
    border-radius: var(--r); box-shadow: var(--shadow-2); overflow: hidden;
  }
  .bellmenu-head {
    display: flex; align-items: center; gap: 8px;
    padding: 11px 13px; border-bottom: 1px solid var(--hair); font-size: 13px;
  }
  .bellmenu-head .spacer { flex: 1; }
  .bellmenu-head .ghost { font-size: 11px; padding: 5px 9px; }
  .bellmenu-body { max-height: min(60vh, 460px); overflow-y: auto; }

  .bellrow {
    display: flex; gap: 10px; padding: 11px 13px;
    border-bottom: 1px solid var(--grid); transition: background .14s var(--ease);
  }
  .bellrow:hover { background: var(--surface-2); }
  .bellrow:last-child { border-bottom: 0; }
  .bellrow-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; margin-top: 5px; }
  .bellrow-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  .bellrow-title { font-size: 12.5px; font-weight: 550; letter-spacing: -0.01em; }
  .bellrow-detail {
    font-size: 11.5px; color: var(--ink-3); line-height: 1.4;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  .bellrow-meta { font-size: 10.5px; color: var(--ink-3); margin-top: 2px; }

  .toasts {
    position: fixed; z-index: 200;
    right: max(16px, env(safe-area-inset-right));
    bottom: max(16px, env(safe-area-inset-bottom));
    display: flex; flex-direction: column; gap: 9px;
    width: min(370px, calc(100vw - 32px)); pointer-events: none;
  }
  .toast {
    pointer-events: auto;
    display: flex; gap: 10px; align-items: flex-start;
    padding: 12px 13px;
    background: color-mix(in srgb, var(--surface-2) 97%, transparent);
    backdrop-filter: blur(10px);
    border: 1px solid var(--hair-firm); border-radius: var(--r);
    box-shadow: var(--shadow-2);
    animation: toastin .32s var(--ease);
  }
  .toast.out { animation: toastout .2s var(--ease) forwards; }
  @keyframes toastin { from { opacity: 0; transform: translateY(10px) scale(.98); } }
  @keyframes toastout { to { opacity: 0; transform: translateX(14px); } }
  .toast-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; margin-top: 5px; }
  .toast-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
  .toast-title { font-size: 12.5px; font-weight: 560; letter-spacing: -0.01em; }
  .toast-detail {
    font-size: 11.5px; color: var(--ink-3); line-height: 1.4;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  .toast-x {
    background: none; border: 0; color: var(--ink-3); cursor: pointer;
    font-size: 16px; line-height: 1; padding: 0 2px; flex: none;
  }
  .toast-x:hover { color: var(--ink-1); }

  /* ------------------------------------------------------ command palette */

  .searchbtn {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 6px 9px 6px 10px; border-radius: var(--r-sm);
    background: var(--surface-2); border: 1px solid var(--hair);
    color: var(--ink-3); font: inherit; font-size: 12.5px; cursor: pointer;
    transition: all .16s var(--ease);
  }
  .searchbtn:hover { color: var(--ink-1); border-color: var(--hair-firm); }
  .searchbtn kbd {
    font-family: var(--font); font-size: 10.5px;
    background: var(--surface-4); color: var(--ink-3);
    padding: 1px 5px; border-radius: 4px;
  }

  .palette-backdrop {
    position: fixed; inset: 0; z-index: 300;
    background: color-mix(in srgb, var(--canvas) 72%, transparent);
    backdrop-filter: blur(5px);
    display: flex; justify-content: center; align-items: flex-start;
    padding: max(9vh, 40px) 16px 16px;
    animation: reveal .18s var(--ease);
  }
  .palette {
    width: min(640px, 100%);
    background: var(--surface-1); border: 1px solid var(--hair-firm);
    border-radius: var(--r-lg); box-shadow: var(--shadow-2); overflow: hidden;
  }
  .palette-input {
    display: flex; align-items: center; gap: 10px;
    padding: 14px 16px; border-bottom: 1px solid var(--hair); color: var(--ink-3);
  }
  .palette-input input {
    flex: 1; min-width: 0; background: none; border: 0; outline: none;
    color: var(--ink-1); font: inherit; font-size: 16px; letter-spacing: -0.01em;
  }
  .palette-input kbd {
    font-family: var(--font); font-size: 10.5px;
    background: var(--surface-3); padding: 2px 6px; border-radius: 4px;
  }
  .palette-body { max-height: min(58vh, 460px); overflow-y: auto; padding: 6px; }

  .pal-row {
    display: flex; align-items: center; gap: 11px;
    padding: 9px 11px; border-radius: var(--r-sm);
  }
  .pal-row.on { background: var(--surface-3); }
  .pal-kind {
    font-size: 9.5px; font-weight: 620; letter-spacing: .06em; text-transform: uppercase;
    border: 1px solid; border-radius: 999px; padding: 2px 7px; flex: none;
  }
  .pal-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
  .pal-title { font-size: 13px; font-weight: 520; letter-spacing: -0.01em;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .pal-sub { font-size: 11px; color: var(--ink-3);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

@media (max-width: 640px) {
  /* The search button collapses to its icon; the shortcut hint is meaningless
     without a keyboard anyway. */
  .searchbtn span, .searchbtn kbd { display: none; }
  .searchbtn { padding: 8px 9px; }
  .bellmenu { position: fixed; top: 58px; left: 8px; right: 8px; width: auto; }
  .toasts { left: max(12px, env(safe-area-inset-left)); right: max(12px, env(safe-area-inset-right)); width: auto; }
  .palette-backdrop { padding: 12px; align-items: flex-start; }
}


/* ------------------------------------------------------ alerts page rows */

@layer components {
  .rulerow {
    display: flex; align-items: center; gap: 12px;
    padding: 12px 0; border-bottom: 1px solid var(--grid);
  }
  .rulerow:last-child { border-bottom: 0; }
  .rulerow.off { opacity: .48; }
  .rulerow .ghost { padding: 4px 10px; font-size: 15px; line-height: 1; }

  /* A switch, not a checkbox — the state has to read at a glance in a list. */
  .toggle {
    width: 34px; height: 20px; border-radius: 999px; flex: none;
    background: var(--surface-4); border: 1px solid var(--hair);
    position: relative; cursor: pointer; padding: 0;
    transition: background .18s var(--ease), border-color .18s var(--ease);
  }
  .toggle span {
    position: absolute; top: 2px; left: 2px; width: 14px; height: 14px;
    border-radius: 50%; background: var(--ink-3);
    transition: transform .18s var(--ease), background .18s var(--ease);
  }
  .toggle.on { background: var(--accent); border-color: var(--accent); }
  .toggle.on span { transform: translateX(14px); background: var(--accent-ink); }

  .firerow {
    display: flex; gap: 11px; padding: 13px 20px;
    border-bottom: 1px solid var(--grid); transition: background .14s var(--ease);
  }
  .firerow:hover { background: var(--surface-2); }
  .firerow-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; margin-top: 5px; }
}


/* ------------------------------------------------------ fixture drill-down */

@layer components {
  .scoreline { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
  .scoreline-at { color: var(--ink-3); font-size: 13px; }
  .scoreline-team { display: flex; align-items: center; gap: 12px; }
  .scoreline-name { display: flex; flex-direction: column; gap: 1px; }
  .scoreline-name b { font-size: 22px; font-weight: 620; letter-spacing: -0.03em; }
  .scoreline-name i { font-style: normal; font-size: 12px; color: var(--ink-3); }
  .scoreline-name em { font-style: normal; font-size: 11px; color: var(--ink-3); }
  .scoreline-score { font-size: 32px; font-weight: 560; letter-spacing: -0.04em; }

  .outcome { padding: 16px 0; border-top: 1px solid var(--grid); }
  .outcome:first-of-type { border-top: 0; padding-top: 4px; }
  .outcome-head {
    display: flex; justify-content: space-between; align-items: flex-start;
    gap: 20px; flex-wrap: wrap; margin-bottom: 4px;
  }
  .outcome-title { font-size: 15px; font-weight: 600; letter-spacing: -0.02em; }
}

@media (max-width: 640px) {
  .scoreline { gap: 12px; width: 100%; }
  .scoreline-name b { font-size: 18px; }
  .scoreline-score { font-size: 26px; }
  .outcome-head { gap: 12px; }
}


/* ------------------------------------------------------------------ icons */

@layer components {
  /* One inline-flex box so an icon sits on the text baseline everywhere it
     appears, and inherits colour rather than carrying its own. */
  .ico { display: inline-flex; align-items: center; justify-content: center; vertical-align: -0.14em; }
  .ico svg { width: 100%; height: 100%; display: block; }

  /* Icons inside headings and labels sit slightly recessed so the word leads. */
  .panel h2 { display: inline-flex; align-items: center; gap: 8px; }
  .panel h2 .ico { color: var(--ink-3); }
  .figure .label { display: inline-flex; align-items: center; gap: 6px; }
  .figure .label .ico { color: var(--ink-3); }

  nav.tabs a { display: inline-flex; align-items: center; gap: 7px; }
  nav.tabs a .ico { color: var(--ink-3); transition: color .18s var(--ease); }
  nav.tabs a:hover .ico, nav.tabs a[aria-current="page"] .ico { color: var(--accent); }
}

@media (max-width: 1180px) {
  /* Below this the labelled tabs no longer fit; the icons carry them, with the
     accessible name still on the link. */
  nav.tabs a span:not(.ico) { display: none; }
  nav.tabs a { padding: 8px 11px; }
}





/* ------------------------------------------------------------------ hero

   The dashboard opens on the live market field. The canvas sits behind the
   copy rather than beside it, so the page still leads with a sentence that
   says what this is — the animation is the evidence, not the headline.
   ------------------------------------------------------------------------ */

@layer components {
  .hero {
    position: relative;
    /* An explicit height, not a min-height. A canvas sized from its own
       bounding box inside a content-sized grid row feeds back into itself and
       the hero grew to fill the viewport. */
    height: clamp(300px, 34vw, 400px);
    margin-bottom: 16px;
    border-radius: var(--r-lg);
    overflow: hidden;
    background:
      radial-gradient(120% 90% at 78% 20%, var(--accent-wash), transparent 62%),
      radial-gradient(90% 80% at 12% 90%, var(--pulse-wash), transparent 58%),
      var(--surface-1);
    border: 1px solid var(--hair);
    display: grid;
  }
  /* Absolute, so the canvas can never contribute to the height that is being
     used to size the canvas. */
  .hero-canvas {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    display: block;
  }
  .hero-body {
    grid-area: 1 / 1;
    position: relative;
    align-self: center;
    padding: 30px 32px;
    max-width: 60ch;
    /* The cloud drifts behind the text. A scrim keeps the copy at full
       contrast without dimming the whole canvas. */
    background: linear-gradient(90deg,
      color-mix(in srgb, var(--surface-1) 92%, transparent) 0%,
      color-mix(in srgb, var(--surface-1) 78%, transparent) 62%,
      transparent 100%);
    pointer-events: none;
  }
  .hero-body .eyebrow {
    font-size: 10.5px; font-weight: 620; letter-spacing: .13em;
    text-transform: uppercase; color: var(--accent); margin-bottom: 6px;
    display: flex; align-items: center; gap: 8px;
  }
  .hero-body h1 {
    margin: 0 0 10px; font-size: clamp(26px, 3vw, 40px); font-weight: 620;
    letter-spacing: -0.035em; line-height: 1.04;
  }
  .hero-body .standfirst { font-size: 13px; max-width: 54ch; margin: 0 0 14px; }

  .hero-legend {
    display: flex; flex-wrap: wrap; gap: 6px 16px;
    font-size: 10.5px; color: var(--ink-3);
  }
  .hero-legend span { display: inline-flex; align-items: center; gap: 6px; }
  .hero-legend em { font-style: italic; color: var(--ink-2); }
  .hero-legend i { width: 12px; height: 12px; flex: none; display: inline-block; position: relative; }
  .hero-legend .k-angle::before {
    content: ""; position: absolute; inset: 5px 0 5px 0;
    background: linear-gradient(90deg, var(--s1), var(--accent)); border-radius: 2px;
  }
  .hero-legend .k-height::before {
    content: ""; position: absolute; left: 5px; top: 0; bottom: 0; width: 2px;
    background: linear-gradient(180deg, var(--warning), transparent); border-radius: 2px;
  }
  .hero-legend .k-depth::before {
    content: ""; position: absolute; inset: 2px; border-radius: 50%;
    background: var(--ink-2);
  }
  .hero-legend .k-ring::before {
    content: ""; position: absolute; inset: 0; border-radius: 50%;
    border: 1.5px solid var(--s3);
  }
  .hero-legend .k-ring::after {
    content: ""; position: absolute; inset: 4.5px; border-radius: 50%;
    background: var(--s3);
  }
}

@media (max-width: 860px) {
  .hero { height: clamp(280px, 62vw, 340px); }
  /* On a narrow screen the copy covers most of the canvas, so the scrim goes
     full-width rather than fading out over a cloud nobody can see. */
  .hero-body {
    padding: 22px 18px;
    background: linear-gradient(180deg,
      color-mix(in srgb, var(--surface-1) 90%, transparent) 0%,
      color-mix(in srgb, var(--surface-1) 72%, transparent) 78%,
      transparent 100%);
  }
  .hero-legend { font-size: 11px; gap: 5px 12px; }
}

/* ------------------------------------------------------ market cards (dense)

   Rebuilt for density. The previous card was ~460x370 to carry six numbers,
   which meant four fitted on a 1440 screen and everything below the fold went
   unseen. This version is roughly a third of the height: the source becomes a
   logo instead of a text pill, the leading outcome gets the size, the rest are
   compressed to one line each, and volume/liquidity/expiry share a single
   footer row with the sparkline.
   ------------------------------------------------------------------------- */

@layer components {
  .mkt {
    display: flex; flex-direction: column; gap: 7px;
    padding: 11px 12px;
    background: var(--surface-1);
    border: 1px solid var(--hair);
    border-radius: var(--r);
    transition: border-color .16s var(--ease), background .16s var(--ease), transform .16s var(--ease);
  }
  .mkt:hover {
    border-color: var(--hair-firm);
    background: var(--surface-2);
    transform: translateY(-1px);
  }

  .mkt-head { display: flex; align-items: center; gap: 6px; min-width: 0; }
  .mkt-src {
    font-size: 11px; font-weight: 560; color: var(--ink-2);
    white-space: nowrap; letter-spacing: -0.01em;
  }

  .tag {
    font-size: 9.5px; font-weight: 560; letter-spacing: .05em; text-transform: uppercase;
    padding: 2px 6px; border-radius: var(--r-xs);
    background: var(--surface-3); color: var(--ink-3);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 92px;
  }
  .tag.play { color: var(--warning); background: color-mix(in srgb, var(--warning) 14%, transparent); }
  .tag.live {
    color: var(--pulse); background: var(--pulse-wash);
    display: inline-flex; align-items: center; gap: 4px;
  }
  .tag.live i {
    width: 5px; height: 5px; border-radius: 50%; background: currentColor;
    animation: livepulse 1.6s var(--ease) infinite;
  }
  @keyframes livepulse { 0%,100% { opacity: 1 } 50% { opacity: .25 } }

  /* Movement sits hard right and is the only coloured number in the header, so
     "which way has this gone" is answerable without reading anything else. */
  .mkt-delta {
    margin-left: auto; font-size: 11.5px; font-weight: 620;
    font-variant-numeric: tabular-nums; white-space: nowrap;
    font-family: var(--mono);
  }
  .mkt-delta em { font-style: normal; font-size: 9px; opacity: .6; margin-left: 1px; }
  .mkt-delta.up { color: var(--up); }
  .mkt-delta.down { color: var(--down); }
  .mkt-delta.flat { color: var(--ink-3); }

  .mkt-title {
    font-size: 12.5px; font-weight: 560; line-height: 1.35; color: var(--ink-1);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden; min-height: 2.7em;
  }
  .mkt-title:hover { color: var(--accent); }

  .mkt-lead { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
  .mkt-lead-name {
    font-size: 12px; color: var(--ink-2); min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .mkt-lead-pct {
    font-size: 17px; font-weight: 640; letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums; flex: none;
  }

  .mkt-rest { display: flex; flex-direction: column; gap: 2px; }
  .mkt-rest-row { display: flex; align-items: center; gap: 6px; font-size: 11px; min-width: 0; }
  .mkt-rest-row .sw { width: 7px; height: 7px; border-radius: 2px; flex: none; }
  .mkt-rest-row .nm {
    flex: 1; min-width: 0; color: var(--ink-2);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .mkt-rest-row .pv { color: var(--ink-1); font-variant-numeric: tabular-nums; flex: none; }
  .mkt-rest-more { font-size: 10px; color: var(--ink-3); padding-left: 13px; }

  .mkt-foot {
    display: flex; align-items: center; gap: 10px;
    padding-top: 7px; border-top: 1px solid var(--hair);
    font-size: 10.5px; color: var(--ink-3); min-width: 0;
  }
  .mkt-spark { flex: none; display: flex; align-items: center; opacity: .85; }
  .mkt-stat { display: flex; align-items: baseline; gap: 3px; white-space: nowrap; }
  .mkt-stat b { font-weight: 600; color: var(--ink-2); font-variant-numeric: tabular-nums; }
  .mkt-ends { margin-left: auto; overflow: hidden; text-overflow: ellipsis; }
}

@media (max-width: 640px) {
  /* The title is the card's link to the market, so it needs a real tap target;
     a one-line title measured 19px. */
  .mkt-title {
    -webkit-line-clamp: 3; min-height: 40px;
    display: -webkit-box; align-items: center;
  }
  .mkt-foot { flex-wrap: wrap; gap: 8px; }
  .mkt-ends { margin-left: 0; }
  /* 9.5px and 10px are fine on a desktop card and unreadable on a phone. */
  .tag { font-size: 11px; padding: 3px 7px; max-width: 120px; }
  .mkt-rest-more { font-size: 11px; }
  .mkt-foot { font-size: 11.5px; }
  .mkt-src { font-size: 12px; }
}

/* ------------------------------------------------------- forecast (outlook) */

@layer components {
  .fc-card { display: flex; flex-direction: column; gap: 11px; padding: 15px; }

  .fc-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; min-width: 0; }
  .fc-head > .badge { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* The matchup is the card's main link to the fixture, so it has to be a real
     tap target, not a 22px strip the height of the crests. */
  .fc-matchup { display: flex; align-items: center; gap: 9px; min-width: 0; min-height: 40px; }
  .fc-name { font-size: 13px; font-weight: 560; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  .fc-call { display: flex; flex-direction: column; gap: 5px; }
  .fc-call-label {
    font-size: 10px; font-weight: 560; letter-spacing: .09em;
    text-transform: uppercase; color: var(--ink-3);
  }
  .fc-call-main { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
  .fc-call-team { font-size: 15px; font-weight: 620; letter-spacing: -0.01em; }
  .fc-call-prob { font-size: 26px; font-weight: 640; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
  .fc-call-range { font-size: 10.5px; }

  /* The band is the honest part of the card: a point estimate drawn alone
     implies a precision that two disagreeing books do not have. */
  .fc-band {
    position: relative; height: 7px; border-radius: 999px;
    background: var(--surface-3); overflow: hidden;
  }
  .fc-band-range {
    position: absolute; top: 0; bottom: 0;
    background: color-mix(in srgb, var(--accent) 42%, transparent);
    border-radius: 999px;
  }
  .fc-band-point {
    position: absolute; top: -2px; width: 2px; height: 11px;
    background: var(--accent); border-radius: 1px; transform: translateX(-1px);
  }

  .fc-fields { display: flex; flex-direction: column; gap: 4px; }
  .fc-field { display: flex; align-items: center; gap: 8px; font-size: 11.5px; }
  .fc-field-label {
    flex: 0 0 34%; min-width: 0; color: var(--ink-2);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .fc-field-bar { flex: 1; height: 5px; background: var(--surface-3); border-radius: 999px; overflow: hidden; }
  .fc-field-bar > span { display: block; height: 100%; background: var(--ink-3); border-radius: 999px; }
  .fc-field-num { flex: 0 0 auto; font-variant-numeric: tabular-nums; color: var(--ink-1); }

  .fc-meters { display: flex; gap: 14px; flex-wrap: wrap; }
  .fc-meter { display: flex; flex-direction: column; gap: 3px; flex: 1 1 45%; min-width: 0; }
  .fc-meter-label {
    font-size: 9.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--ink-3);
  }
  .fc-meter-track { height: 4px; background: var(--surface-3); border-radius: 999px; overflow: hidden; }
  .fc-meter-track > span { display: block; height: 100%; background: var(--accent-deep); border-radius: 999px; }
  .fc-meter-word { font-size: 11px; color: var(--ink-2); }

  .fc-drivers { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
  .fc-drivers li {
    font-size: 11.5px; line-height: 1.45; color: var(--ink-2);
    border-left: 2px solid var(--hair-firm); padding-left: 9px;
  }

  /* Collapsed by default: the card should read at a glance, but the full
     working has to be one click away rather than absent. */
  .fc-more { border-top: 1px solid var(--hair); padding-top: 9px; }
  .fc-more summary {
    cursor: pointer; list-style: none; font-size: 10.5px; font-weight: 560;
    letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
    display: flex; align-items: center; gap: 6px; min-height: 30px;
  }
  .fc-more summary::-webkit-details-marker { display: none; }
  .fc-more summary::before {
    content: ""; width: 5px; height: 5px; flex: none;
    border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
    transform: rotate(-45deg); transition: transform .18s var(--ease);
  }
  .fc-more[open] summary::before { transform: rotate(45deg); }
  .fc-more summary:hover { color: var(--ink-1); }

  .fc-grid {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 2px 14px; margin-top: 8px;
  }
  .fc-metric {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 8px; padding: 3px 0; border-bottom: 1px solid var(--hair);
    font-size: 11px; min-width: 0;
  }
  .fc-metric-k {
    color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .fc-metric-v { color: var(--ink-1); font-variant-numeric: tabular-nums; white-space: nowrap; }

  /* NOT .stack — that is the 7px stacked-bar component, and reusing its name
     here laid these rows out sideways inside a 7px-tall flex row. */
  .fc-trend-list { display: flex; flex-direction: column; min-width: 0; }

  .fc-trend-row {
    display: flex; align-items: center; gap: 8px; min-width: 0;
    padding: 6px 0; border-top: 1px solid var(--hair); min-height: 40px;
  }
  .fc-trend-row:hover .fc-trend-label { color: var(--accent); }
  /* min-width:0 here is load-bearing: without it a long fixture name refuses to
     shrink and pushes the whole row past the viewport. */
  .fc-trend-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
  .fc-trend-label {
    font-size: 12px; font-weight: 560;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .fc-trend-event {
    font-size: 11px; color: var(--ink-3);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .fc-trend-num { flex: 0 0 auto; font-size: 12px; white-space: nowrap; }

  .fc-context { display: flex; flex-wrap: wrap; gap: 5px; }
  .fc-chip {
    display: inline-flex; align-items: center; padding: 3px 8px;
    border-radius: 999px; font-size: 10.5px; white-space: nowrap;
    color: var(--tone, var(--ink-3));
    background: color-mix(in srgb, var(--tone, var(--ink-3)) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--tone, var(--ink-3)) 26%, transparent);
  }
}

@media (max-width: 640px) {
  /* A forecast card carries a matchup, a big number, a band, three outcome
     rows and a paragraph of reasoning. Half of 390px is not enough for any of
     that, so these go one-up like the fixture cards do. */
  .fc-card { gap: 10px; }
  .fc-call-prob { font-size: 24px; }
  .fc-meters { gap: 10px; }
  /* 10px and 9.5px labels are below comfortable reading size on a phone. */
  .fc-call-label { font-size: 11.5px; }
  .fc-meter-label { font-size: 11px; }
  .fc-more summary { font-size: 11.5px; }
  .fc-chip { font-size: 11.5px; padding: 4px 9px; }
  /* A 20px switch is half a fingertip. Pad the hit area without resizing the
     control itself, so the row keeps its proportions. */
  /* A 34x20 switch is a desktop control. On touch it becomes the primary way
     to silence a rule, so it gets a real size rather than an invisible padded
     hit area — the visible target should match the tappable one. */
  .toggle { width: 50px; height: 30px; }
  .toggle span { top: 3px; left: 3px; width: 22px; height: 22px; }
  .toggle.on span { transform: translateX(20px); }
  /* Two columns of label + number do not fit in 390px without truncating the
     labels into uselessness. */
  .fc-grid { grid-template-columns: 1fr; gap: 0; }
}

/* ----------------------------------------------------- mobile refinements */

@media (max-width: 640px) {
  /* Standalone action links ("open ↗", "docs ↗") are buttons wearing text
     clothes: they sat at 17px tall, roughly half a fingertip. Inline links
     inside a sentence are deliberately left at text height — padding those
     would wreck the line rhythm of the prose they live in. */
  .mkt-foot a,
  .srccard a,
  .bellmenu-head a {
    display: inline-flex;
    align-items: center;
    min-height: 36px;
    padding-inline: 2px;
  }

  /* A long league name plus a kick-off time overflowed the card header,
     because the badge refuses to wrap and nothing was allowed to shrink. */
  .scorecard-head { gap: 8px; min-width: 0; }
  .scorecard-head > .badge {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 0 1 auto;
  }
  .scorecard-head > :last-child { flex: 0 0 auto; white-space: nowrap; }
}

/* ==========================================================================
   Mobile.

   A dense terminal on a 390px screen is a different product, not a squeezed
   one. Panels lose their inset so content gets the full width, wide tables
   scroll inside their own container (never the page), controls reach the 44px
   touch target, and charts shorten rather than shrink their type.
   ========================================================================== */

@layer layout {
  /* The page itself must never scroll sideways — only designated containers. */
  html, body { max-width: 100%; overflow-x: hidden; }
  .tablewrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;

    /* A dense odds table genuinely needs to scroll sideways on a phone, but
       silently clipping the last column reads as a broken layout rather than
       as "there is more over here". These are the classic four-layer scroll
       shadows: the two `local` gradients scroll with the content and mask the
       shadow off whenever that edge is actually the end of the table, so the
       hint appears only while there is something left to reach. */
    background:
      linear-gradient(to right, var(--surface-1), transparent) 0 0 / 26px 100% no-repeat local,
      linear-gradient(to left,  var(--surface-1), transparent) 100% 0 / 26px 100% no-repeat local,
      radial-gradient(farthest-side at 0 50%,   var(--edge-hint), transparent) 0 0 / 14px 100% no-repeat scroll,
      radial-gradient(farthest-side at 100% 50%, var(--edge-hint), transparent) 100% 0 / 14px 100% no-repeat scroll;
  }
}

@media (max-width: 900px) {
  .split-wide { grid-template-columns: 1fr; }
  .cols-2, .cols-3 { grid-template-columns: 1fr; }
  .cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Two-up suits the stat tiles, but a fixture card carries a crest, a full
     club name and a score — at half of 390px "Paris Saint-Germain" truncates
     to "Paris Saint-Ger…". Fixtures get the full width. */
  .fixtures.cols-4 { grid-template-columns: 1fr; }
}

@media (max-width: 640px) {
  :root { --r-lg: 13px; --r: 10px; }

  main {
    padding: 18px max(13px, env(safe-area-inset-left)) 64px;
  }

  .topbar {
    height: 54px;
    gap: 10px;
    padding: 0 max(13px, env(safe-area-inset-left)) 0 max(13px, env(safe-area-inset-right));
  }
  .topbar-right { gap: 8px; }
  /* The message counter is noise on a phone; the pip already says "live". */
  .ws-state { font-size: 0; gap: 0; }
  .ws-state .pip { width: 7px; height: 7px; }

  nav.tabs {
    /* Snap so tabs land cleanly rather than half-scrolled. */
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    margin: 0 -4px;
  }
  nav.tabs a { scroll-snap-align: start; padding: 8px 11px; font-size: 13px; }
  nav.tabs {
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 22px), transparent 100%);
            mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 22px), transparent 100%);
  }

  .page-head { margin-bottom: 20px; }
  .page-head h1 { font-size: 27px; letter-spacing: -0.03em; }
  .page-head .standfirst { font-size: 14px; line-height: 1.55; }
  /* Was 10px. Below comfortable reading size on a phone, and the eyebrow is
     tracked out which makes it read smaller still. */
  .page-head .eyebrow { font-size: 11.5px; letter-spacing: .1em; }

  /* Full-bleed panels: on a narrow screen the 13px gutter plus 20px padding
     wastes a sixth of the width before any content appears. */
  .panel {
    padding: 15px;
    margin-inline: -13px;
    border-radius: 0;
    border-inline: 0;
  }
  .panel.flush { margin-inline: -13px; border-radius: 0; border-inline: 0; }
  .grid { gap: 12px; }

  .tile { padding: 11px 12px 10px; }
  .figure .value { font-size: 22px; }
  .figure .value.md { font-size: 18px; }
  .figure .value.sm { font-size: 15px; }

  /* Controls: 44px targets, and inputs that don't trigger iOS zoom (<16px does). */
  .toolbar {
    gap: 7px; padding: 10px;
    margin-inline: -13px; border-radius: 0; border-inline: 0;
  }
  .toolbar .spacer { display: none; }
  select, input[type="search"], input[type="text"] {
    font-size: 16px; padding: 9px 11px; min-height: 40px;
  }
  input[type="search"] { min-width: 0; flex: 1 1 100%; }
  /* Was label-beside-control, which left the select roughly 100px wide and
     clipped "multiplicative" to "multiplicativ". Stacking hands the control
     the whole column. */
  .field {
    flex: 1 1 calc(50% - 4px);
    flex-direction: column; align-items: stretch; gap: 4px;
  }
  .field select { width: 100%; min-width: 0; }
  .chip { padding: 8px 13px; font-size: 13px; min-height: 38px; }
  button.ghost { padding: 9px 13px; min-height: 38px; font-size: 13px; }
  .iconbtn { width: 38px; height: 38px; }

  /* Tables stay tables — they carry too many dimensions to flatten into cards —
     but the row gets air and the horizontal scroll is contained. */
  table { font-size: 12.5px; }
  thead th { padding: 9px 10px; font-size: 9.5px; }
  tbody td { padding: 12px 10px; }
  td.num, th.num { font-size: 11.5px; }

  .note-box { padding: 12px 14px; font-size: 12.5px; }
  .legend { gap: 10px 14px; font-size: 11px; }
  .scroll-y { max-height: 60vh !important; }
  .tooltip { max-width: min(300px, calc(100vw - 24px)); }

  /* Market cards read better as a single column than as two cramped ones. */
  .mkt { padding: 14px; }
  .tree-name { max-width: 190px; }
  .tree-bar { width: 64px; }
}

@media (max-width: 359px) {
  .cols-4 { grid-template-columns: 1fr; }
}

@media (max-width: 400px) {
  .figure .value { font-size: 25px; }
  .page-head h1 { font-size: 24px; }
}

/* Coarse pointers get no hover-only affordances and bigger hit areas. */
@media (hover: none) {
  .tree-row { padding-block: 8px; }
  nav.tabs a { padding-block: 10px; }
  .panel:hover, .mkt:hover, .tile:hover { border-color: var(--hair); }
}

@media (max-width: 860px) {
  .wordmark { display: none; }
}
