/* Generated by build.sh — do not edit. Edit the source files in src/assets/css/ instead. */

/* ===== fonts.css ===== */
/* OpenThinkr webfonts — Space Grotesk 500/700 (display), Inter 400/500/600 (body).
   The Google Fonts stylesheet is linked from the document head with preconnect,
   not @imported here, so it does not chain behind this file. */

/* ===== colors.css ===== */
:root{
  /* ---------- Neutrals: 11-step ramp, slightly blue-tinted ---------- */
  --n-0:#FFFFFF;
  --n-50:#F7F8FB;
  --n-100:#EFF1F6;
  --n-200:#E2E6EF;
  --n-300:#CBD1DE;
  --n-400:#A3ABBD;
  --n-500:#78819A;
  --n-600:#565F78;
  --n-700:#3B4358;
  --n-800:#212734;
  --n-900:#0B0D12;

  /* ---------- Brand accents (base = the published brand hue) ---------- */
  /* Blue — primary action, links, focus */
  --blue-50:#EAF1FE; --blue-100:#D3E1FC; --blue-300:#7CA9F4;
  --blue-500:#1F6FEB; --blue-600:#1A5CC4; --blue-700:#154A9E; --blue-900:#0D2C5E;
  /* Coral — Brain Games, alerts, destructive */
  --red-50:#FEECEB; --red-100:#FCD8D5; --red-300:#F79891;
  --red-500:#F0483E; --red-600:#D93529; --red-700:#C22B22; --red-900:#5E1611;
  /* Amber — Languages, highlights, score bars */
  --amber-50:#FFF6E3; --amber-100:#FFEBC2; --amber-300:#FFD37A;
  --amber-500:#FFBF3C; --amber-600:#C98B00; --amber-800:#8A5B00; --amber-900:#4A3000;
  /* Emerald — Career & Jobs, success, correct */
  --emerald-50:#E7F6EE; --emerald-100:#C9EBD9; --emerald-300:#6CC79A;
  --emerald-500:#1FA463; --emerald-600:#188A53; --emerald-700:#157A48; --emerald-900:#0A3B23;
  /* Violet — Personality */
  --violet-50:#F1EDFE; --violet-100:#E2DAFD; --violet-300:#AE99F6;
  --violet-500:#7B5CF0; --violet-600:#6C4BE6; --violet-700:#6642DC; --violet-900:#2E1D70;
  /* Teal — Knowledge & Trivia */
  --teal-50:#E4F6F8; --teal-100:#C2EAEE; --teal-300:#5FC6CE;
  --teal-500:#12A5B0; --teal-600:#0C8A94; --teal-700:#0A6E76; --teal-900:#053B40;

  /* ---------- Semantic surfaces & text (light) ---------- */
  --surface-page:#F7F8FB;         /* near-white, never pure white */
  --surface-card:var(--n-0);
  --surface-raised:var(--n-0);
  --surface-sunken:var(--n-100);
  --surface-inverse:var(--n-900);
  --surface-overlay:rgba(11,13,18,.55);

  --text-primary:var(--n-900);
  --text-secondary:var(--n-600);
  --text-tertiary:var(--n-500);
  --text-inverse:var(--n-0);
  --text-link:var(--blue-500);
  --text-link-hover:var(--blue-700);
  --text-on-accent:var(--n-0);

  --border-subtle:var(--n-200);
  --border-default:var(--n-300);
  --border-strong:var(--n-400);

  /* Interactive — primary */
  --action-primary-bg:var(--blue-500);
  --action-primary-bg-hover:var(--blue-600);
  --action-primary-bg-active:var(--blue-700);
  --action-primary-fg:var(--n-0);
  /* Interactive — secondary (outlined) */
  --action-secondary-bg:var(--n-0);
  --action-secondary-bg-hover:var(--blue-50);
  --action-secondary-bg-active:var(--blue-100);
  --action-secondary-fg:var(--blue-700);
  --action-secondary-border:var(--n-300);
  /* Interactive — ghost */
  --action-ghost-bg:transparent;
  --action-ghost-bg-hover:var(--n-100);
  --action-ghost-bg-active:var(--n-200);
  --action-ghost-fg:var(--n-700);
  /* Disabled + focus */
  --action-disabled-bg:var(--n-200);
  --action-disabled-fg:var(--n-400);
  --focus-ring:var(--blue-500);
  --focus-ring-offset:var(--surface-page);

  /* Feedback */
  --success-fg:var(--emerald-700); --success-bg:var(--emerald-50); --success-border:var(--emerald-300); --success-solid:var(--emerald-500);
  --danger-fg:var(--red-700);      --danger-bg:var(--red-50);      --danger-border:var(--red-300);      --danger-solid:var(--red-500);
  --warning-fg:var(--amber-800);   --warning-bg:var(--amber-50);   --warning-border:var(--amber-300);   --warning-solid:var(--amber-500);
  --info-fg:var(--blue-700);       --info-bg:var(--blue-50);       --info-border:var(--blue-300);       --info-solid:var(--blue-500);

  /* ---------- Category accents: one hue per category, held everywhere ---------- */
  --cat-iq:var(--blue-500);          --cat-iq-fg:var(--blue-700);          --cat-iq-tint:var(--blue-50);
  --cat-personality:var(--violet-500); --cat-personality-fg:var(--violet-700); --cat-personality-tint:var(--violet-50);
  --cat-career:var(--emerald-500);   --cat-career-fg:var(--emerald-700);   --cat-career-tint:var(--emerald-50);
  --cat-language:var(--amber-500);   --cat-language-fg:var(--amber-800);    --cat-language-tint:var(--amber-50);
  --cat-games:var(--red-500);        --cat-games-fg:var(--red-700);        --cat-games-tint:var(--red-50);
  --cat-trivia:var(--teal-500);      --cat-trivia-fg:var(--teal-700);      --cat-trivia-tint:var(--teal-50);

  /* Generic accent channel — set by a category scope, read by components */
  --accent:var(--blue-500);
  --accent-fg:var(--blue-700);
  --accent-tint:var(--blue-50);
  /* Deepened accent for solid fills that carry white text (AA at every size) */
  --accent-deep:var(--blue-600);
  /* Text/glyph colour that sits on --accent-deep */
  --accent-on:#FFFFFF;

  /* Ad slots */
  --ad-bg:var(--n-100);
  --ad-border:var(--n-200);
  --ad-label:var(--n-400);
}

/* Category scopes — put data-category on any container (card, page header, result) */
[data-category="iq"]{--accent:var(--cat-iq);--accent-fg:var(--cat-iq-fg);--accent-tint:var(--cat-iq-tint);--accent-deep:var(--blue-600)}
[data-category="personality"]{--accent:var(--cat-personality);--accent-fg:var(--cat-personality-fg);--accent-tint:var(--cat-personality-tint);--accent-deep:var(--violet-600)}
[data-category="career"]{--accent:var(--cat-career);--accent-fg:var(--cat-career-fg);--accent-tint:var(--cat-career-tint);--accent-deep:var(--emerald-700)}
[data-category="language"]{--accent:var(--cat-language);--accent-fg:var(--cat-language-fg);--accent-tint:var(--cat-language-tint);--accent-deep:var(--amber-500);--accent-on:var(--n-900)}
[data-category="games"]{--accent:var(--cat-games);--accent-fg:var(--cat-games-fg);--accent-tint:var(--cat-games-tint);--accent-deep:var(--red-700)}
[data-category="trivia"]{--accent:var(--cat-trivia);--accent-fg:var(--cat-trivia-fg);--accent-tint:var(--cat-trivia-tint);--accent-deep:var(--teal-700)}

/* ---------- Dark mode ---------- */
[data-theme="dark"]{
  --surface-page:var(--n-900);
  --surface-card:#12161F;
  --surface-raised:#1A1F2B;
  --surface-sunken:#080A0E;
  --surface-inverse:var(--n-0);
  --surface-overlay:rgba(4,6,10,.7);

  --text-primary:#EDF0F6;
  --text-secondary:#A9B2C4;
  --text-tertiary:#7F8899;
  --text-inverse:var(--n-900);
  --text-link:#7CA9F4;
  --text-link-hover:#A9C7F8;
  --text-on-accent:var(--n-900);

  --border-subtle:#232935;
  --border-default:#303845;
  --border-strong:#454E5F;

  --action-primary-bg:#3B82F6;
  --action-primary-bg-hover:#5A99F8;
  --action-primary-bg-active:#1F6FEB;
  --action-primary-fg:#06101F;
  --action-secondary-bg:#161B25;
  --action-secondary-bg-hover:#1D2534;
  --action-secondary-bg-active:#243046;
  --action-secondary-fg:#A9C7F8;
  --action-secondary-border:#303845;
  --action-ghost-bg:transparent;
  --action-ghost-bg-hover:#1A1F2B;
  --action-ghost-bg-active:#232935;
  --action-ghost-fg:#C4CBD8;
  --action-disabled-bg:#1D222D;
  --action-disabled-fg:#5A6376;
  --focus-ring:#7CA9F4;
  --focus-ring-offset:var(--n-900);

  --success-fg:#5FD69B; --success-bg:#0C2A1C; --success-border:#1F6B48;
  --danger-fg:#FF8C84;  --danger-bg:#33110E;  --danger-border:#7A2A22;
  --warning-fg:#FFD37A; --warning-bg:#332508; --warning-border:#7A5A12;
  --info-fg:#8CB8F7;    --info-bg:#0E1F3A;    --info-border:#245094;
  --success-solid:#26C079; --danger-solid:#FF6257; --warning-solid:#FFC94F; --info-solid:#3B82F6;

  /* Category accents lift for dark surfaces */
  --cat-iq:#5A99F8;          --cat-iq-fg:#A9C7F8;          --cat-iq-tint:#101B2E;
  --cat-personality:#9C82F6; --cat-personality-fg:#C2B2FA; --cat-personality-tint:#1A1435;
  --cat-career:#35C280;      --cat-career-fg:#7FDCAE;      --cat-career-tint:#0C2A1C;
  --cat-language:#FFCC63;    --cat-language-fg:#FFDC96;    --cat-language-tint:#2E2208;
  --cat-games:#FF6E64;       --cat-games-fg:#FFA39C;       --cat-games-tint:#2E1210;
  --cat-trivia:#2FC3CE;      --cat-trivia-fg:#7BDCE4;      --cat-trivia-tint:#0A2A2E;
  --accent:var(--cat-iq); --accent-fg:var(--cat-iq-fg); --accent-tint:var(--cat-iq-tint);

  --ad-bg:#12161F; --ad-border:#232935; --ad-label:#5A6376;
}

/* ===== typography.css ===== */
:root{
  /* Families — two only */
  --font-display:"Space Grotesk","Helvetica Neue",Arial,sans-serif;
  --font-body:"Inter","Helvetica Neue",Arial,sans-serif;
  --font-numeric:"Inter","Helvetica Neue",Arial,sans-serif;

  --fw-body:400;/* @kind font */ --fw-medium:500;/* @kind font */ --fw-semibold:600;/* @kind font */
  --fw-display-medium:500;/* @kind font */ --fw-display-bold:700;/* @kind font */

  /* Type scale — size / line-height / tracking.
     Display steps use --font-display; text steps use --font-body. */
  --fs-display-1:64px;/* @kind font */  --lh-display-1:1.04;/* @kind font */ --ls-display-1:-.02em;/* @kind font */
  --fs-display-2:52px;/* @kind font */  --lh-display-2:1.07;/* @kind font */ --ls-display-2:-.02em;/* @kind font */
  --fs-h1:40px;/* @kind font */         --lh-h1:1.12;/* @kind font */        --ls-h1:-.018em;/* @kind font */
  --fs-h2:32px;/* @kind font */         --lh-h2:1.18;/* @kind font */        --ls-h2:-.015em;/* @kind font */
  --fs-h3:24px;/* @kind font */         --lh-h3:1.25;/* @kind font */        --ls-h3:-.01em;/* @kind font */
  --fs-h4:20px;/* @kind font */         --lh-h4:1.32;/* @kind font */        --ls-h4:-.005em;/* @kind font */
  --fs-body-lg:18px;/* @kind font */    --lh-body-lg:1.6;/* @kind font */    --ls-body-lg:0;/* @kind font */
  --fs-body:16px;/* @kind font */       --lh-body:1.6;/* @kind font */       --ls-body:0;/* @kind font */
  --fs-body-sm:14px;/* @kind font */    --lh-body-sm:1.55;/* @kind font */   --ls-body-sm:0;/* @kind font */
  --fs-caption:12px;/* @kind font */    --lh-caption:1.45;/* @kind font */   --ls-caption:.005em;/* @kind font */
  --fs-overline:12px;/* @kind font */   --lh-overline:1.1;/* @kind font */   --ls-overline:.08em;/* @kind font */

  /* Question text — the most-read type on the site */
  --fs-question:32px;/* @kind font */   --lh-question:1.3;/* @kind font */   --ls-question:-.01em;/* @kind font */
  /* Numerals: scores, timers, counters */
  --fs-score:72px;/* @kind font */      --lh-score:1;/* @kind font */        --ls-score:-.02em;/* @kind font */
}
@media (max-width:768px){
  :root{
    --fs-display-1:40px;/* @kind font */ --lh-display-1:1.08;/* @kind font */
    --fs-display-2:34px;/* @kind font */
    --fs-h1:30px;/* @kind font */ --fs-h2:26px;/* @kind font */ --fs-h3:21px;/* @kind font */ --fs-h4:18px;/* @kind font */
    --fs-body-lg:17px;/* @kind font */
    --fs-question:24px;/* @kind font */ --lh-question:1.35;/* @kind font */
    --fs-score:56px;/* @kind font */
  }
}

/* Reusable type classes — components may use these or the raw tokens */
.ot-display-1{font:var(--fw-display-bold) var(--fs-display-1)/var(--lh-display-1) var(--font-display);letter-spacing:var(--ls-display-1)}
.ot-display-2{font:var(--fw-display-bold) var(--fs-display-2)/var(--lh-display-2) var(--font-display);letter-spacing:var(--ls-display-2)}
.ot-h1{font:var(--fw-display-bold) var(--fs-h1)/var(--lh-h1) var(--font-display);letter-spacing:var(--ls-h1)}
.ot-h2{font:var(--fw-display-bold) var(--fs-h2)/var(--lh-h2) var(--font-display);letter-spacing:var(--ls-h2)}
.ot-h3{font:var(--fw-display-medium) var(--fs-h3)/var(--lh-h3) var(--font-display);letter-spacing:var(--ls-h3)}
.ot-h4{font:var(--fw-display-medium) var(--fs-h4)/var(--lh-h4) var(--font-display);letter-spacing:var(--ls-h4)}
.ot-question{font:var(--fw-display-medium) var(--fs-question)/var(--lh-question) var(--font-display);letter-spacing:var(--ls-question)}
.ot-body-lg{font:var(--fw-body) var(--fs-body-lg)/var(--lh-body-lg) var(--font-body)}
.ot-body{font:var(--fw-body) var(--fs-body)/var(--lh-body) var(--font-body)}
.ot-body-sm{font:var(--fw-body) var(--fs-body-sm)/var(--lh-body-sm) var(--font-body)}
.ot-caption{font:var(--fw-body) var(--fs-caption)/var(--lh-caption) var(--font-body);letter-spacing:var(--ls-caption)}
.ot-overline{font:var(--fw-semibold) var(--fs-overline)/var(--lh-overline) var(--font-body);letter-spacing:var(--ls-overline);text-transform:uppercase}
.ot-num{font-family:var(--font-numeric);font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
.ot-score{font:var(--fw-semibold) var(--fs-score)/var(--lh-score) var(--font-numeric);letter-spacing:var(--ls-score);font-variant-numeric:tabular-nums}

/* ===== spacing.css ===== */
:root{
  /* 8px base scale (2px and 4px available for optical fixes) */
  --space-0:0;
  --space-025:2px;
  --space-05:4px;
  --space-1:8px;
  --space-2:16px;
  --space-3:24px;
  --space-4:32px;
  --space-5:40px;
  --space-6:48px;
  --space-8:64px;
  --space-10:80px;
  --space-12:96px;
  --space-16:128px;

  /* Layout */
  --container-max:1200px;
  --container-narrow:720px;   /* question + result reading column */
  --gutter:24px;
  --gutter-mobile:16px;
  --nav-height:64px;
  --grid-gap:20px;

  /* Reserved ad slot dimensions (IAB) — containers exist now, ads land later */
  --ad-leaderboard-w:728px;  --ad-leaderboard-h:90px;
  --ad-leaderboard-mobile-w:320px; --ad-leaderboard-mobile-h:100px;
  --ad-incontent-w:336px;    --ad-incontent-h:280px;
  --ad-sidebar-w:300px;      --ad-sidebar-h:600px;

  /* Minimum tap target */
  --tap-min:48px;/* @kind spacing */
}
@media (max-width:768px){:root{--gutter:16px;--grid-gap:12px}}

/* ===== radius.css ===== */
:root{
  --radius-xs:4px;
  --radius-sm:8px;
  --radius-md:12px;   /* buttons, inputs, chips */
  --radius-lg:16px;   /* cards, answer options */
  --radius-xl:24px;   /* panels, hero blocks, modals */
  --radius-pill:999px;
  --border-width:1px;/* @kind radius */
  --border-width-strong:2px;/* @kind radius */
  --focus-width:3px;/* @kind radius */
  --focus-offset:2px;/* @kind radius */
}

/* ===== elevation.css ===== */
:root{
  /* Elevation is deliberately restrained: borders do the work, shadows only lift.
     e0 flat · e1 card hover · e2 sticky nav / dropdown · e3 modal */
  --elev-0:none;
  --elev-1:0 1px 2px rgba(11,13,18,.04), 0 2px 8px rgba(11,13,18,.06);
  --elev-2:0 2px 4px rgba(11,13,18,.05), 0 8px 24px rgba(11,13,18,.08);
  --elev-3:0 8px 16px rgba(11,13,18,.08), 0 24px 48px rgba(11,13,18,.14);
  --elev-focus:0 0 0 var(--focus-width) color-mix(in srgb, var(--focus-ring) 45%, transparent);
  --elev-inset:inset 0 1px 0 rgba(255,255,255,.6);
}
[data-theme="dark"]{
  --elev-1:0 1px 2px rgba(0,0,0,.4), 0 2px 8px rgba(0,0,0,.3);
  --elev-2:0 2px 4px rgba(0,0,0,.45), 0 8px 24px rgba(0,0,0,.4);
  --elev-3:0 8px 16px rgba(0,0,0,.5), 0 24px 48px rgba(0,0,0,.55);
  --elev-inset:inset 0 1px 0 rgba(255,255,255,.05);
}

/* ===== motion.css ===== */
:root{
  --dur-instant:80ms;/* @kind other */
  --dur-fast:140ms;/* @kind other */
  --dur-base:200ms;/* @kind other */
  --dur-slow:320ms;/* @kind other */
  --dur-reveal:600ms;/* @kind other */      /* score dial / result reveal */
  --ease-out:cubic-bezier(.22,.7,.3,1);/* @kind other */
  --ease-in-out:cubic-bezier(.5,0,.3,1);/* @kind other */
  --ease-spring:cubic-bezier(.34,1.3,.5,1);/* @kind other */
  --transition-ui:background-color var(--dur-fast) var(--ease-out),border-color var(--dur-fast) var(--ease-out),color var(--dur-fast) var(--ease-out),box-shadow var(--dur-fast) var(--ease-out),transform var(--dur-fast) var(--ease-out);/* @kind other */
  --press-scale:.985;/* @kind other */
}
@media (prefers-reduced-motion:reduce){
  :root{--dur-instant:0ms;/* @kind other */--dur-fast:0ms;/* @kind other */--dur-base:0ms;/* @kind other */--dur-slow:0ms;/* @kind other */--dur-reveal:0ms;/* @kind other */--press-scale:1;/* @kind other */}
}

/* ===== base.css ===== */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--surface-page);color:var(--text-primary);font:var(--fw-body) var(--fs-body)/var(--lh-body) var(--font-body);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
h1,h2,h3,h4{margin:0;font-family:var(--font-display);color:var(--text-primary);text-wrap:balance}
p{margin:0;text-wrap:pretty}
a{color:var(--text-link);text-decoration:none}
a:hover{color:var(--text-link-hover);text-decoration:underline;text-underline-offset:2px}
button,input,select,textarea{font:inherit;color:inherit}
img,svg{display:block;max-width:100%}
:focus-visible{outline:var(--focus-width) solid var(--focus-ring);outline-offset:var(--focus-offset);border-radius:var(--radius-xs)}
[hidden]{display:none!important}

/* Layout helpers */
.ot-container{width:100%;max-width:var(--container-max);margin-inline:auto;padding-inline:var(--gutter)}
.ot-narrow{width:100%;max-width:var(--container-narrow);margin-inline:auto;padding-inline:var(--gutter)}

/* Icon glyphs — Lucide (outline, 24px grid) tinted with currentColor via CSS mask.
   No inline SVG, no icon font: one CDN request per glyph, colourable, crisp. */
:root{--icon-src:"../icons/";/* @kind other */}
.ot-icon{display:inline-block;width:24px;height:24px;flex:none;background-color:currentColor;-webkit-mask:var(--i) no-repeat center/contain;mask:var(--i) no-repeat center/contain}

/* On-accent type safety net — a solid accent fill must always pair with --accent-on
   (white on the five dark hues, near-black on amber). Higher specificity than the
   components' own injected rules so a light fill can never render white type. */
[data-category].otcard--solid .otcard__title,[data-category].otcard--solid .otcard__cat{color:var(--accent-on)}
[data-category].otcard--solid .otcard__desc,[data-category].otcard--solid .otcard__meta{color:color-mix(in srgb,var(--accent-on) 85%,transparent)}
[data-category].otcard--solid .otcard__meta{border-top-color:color-mix(in srgb,var(--accent-on) 28%,transparent)}
[data-category].otcard--solid .otcard__glyph{background:color-mix(in srgb,var(--accent-on) 18%,transparent);color:var(--accent-on)}
[data-category].otcard--solid .otbadge{background:color-mix(in srgb,var(--accent-on) 20%,transparent);border-color:color-mix(in srgb,var(--accent-on) 40%,transparent);color:var(--accent-on)}
.otdial--inv .otdial__fill{stroke:var(--accent-on)!important}
.otdial--inv .otdial__track{stroke:color-mix(in srgb,var(--accent-on) 28%,transparent)!important}
.otdial--inv .otdial__value{color:var(--accent-on)!important}
.otdial--inv .otdial__label{color:color-mix(in srgb,var(--accent-on) 80%,transparent)!important}

/* Reserved ad containers — fixed dimensions, zero layout shift when filled */
.ot-ad{display:grid;place-items:center;background:var(--ad-bg);border:1px dashed var(--ad-border);border-radius:var(--radius-md);color:var(--ad-label);font:var(--fw-semibold) var(--fs-overline)/1 var(--font-body);letter-spacing:var(--ls-overline);text-transform:uppercase}

/* ===== site.css ===== */
/* ==========================================================================
   OpenThinkr — site layer
   Homepage composition built on the design system tokens. No hardcoded
   palette, type or spacing values: everything reads from tokens/*.css.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Icons — Lucide glyphs served locally, tinted with currentColor via CSS mask.
   One class per glyph so no URL ever appears inline in the markup.
   -------------------------------------------------------------------------- */
.i-layout-grid  { --i: url("../icons/layout-grid.svg") }
.i-chevron-down { --i: url("../icons/chevron-down.svg") }
.i-languages    { --i: url("../icons/languages.svg") }
.i-moon         { --i: url("../icons/moon.svg") }
.i-sun          { --i: url("../icons/sun.svg") }
.i-arrow-right  { --i: url("../icons/arrow-right.svg") }
.i-brain        { --i: url("../icons/brain.svg") }
.i-user-round   { --i: url("../icons/user-round.svg") }
.i-briefcase    { --i: url("../icons/briefcase.svg") }
.i-gamepad-2    { --i: url("../icons/gamepad-2.svg") }
.i-lightbulb    { --i: url("../icons/lightbulb.svg") }
.i-zap          { --i: url("../icons/zap.svg") }
.i-ruler        { --i: url("../icons/ruler.svg") }
.i-share-2      { --i: url("../icons/share-2.svg") }
.i-clock        { --i: url("../icons/clock.svg") }
.i-list         { --i: url("../icons/list.svg") }
.i-timer        { --i: url("../icons/timer.svg") }
.i-plus         { --i: url("../icons/plus.svg") }
.i-minus        { --i: url("../icons/minus.svg") }

.ot-icon--14 { width: 14px; height: 14px }
.ot-icon--16 { width: 16px; height: 16px }
.ot-icon--20 { width: 20px; height: 20px }

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */
.otb {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  font-family: var(--font-body);
  font-weight: var(--fw-semibold);
  border: var(--border-width) solid transparent;
  border-radius: var(--radius-md);
  cursor: pointer;
  text-decoration: none;
  transition: var(--transition-ui);
  padding-block: 10px;
}
.otb:hover { text-decoration: none }
.otb:active:not(:disabled) { transform: scale(var(--press-scale)) }
.otb:disabled {
  background: var(--action-disabled-bg);
  border-color: transparent;
  color: var(--action-disabled-fg);
  cursor: not-allowed;
}

.otb--md { min-height: 44px; padding-inline: var(--space-3); font-size: var(--fs-body) }
.otb--lg { min-height: 56px; padding-inline: var(--space-4); font-size: var(--fs-body-lg) }

.otb--primary { background: var(--action-primary-bg); color: var(--action-primary-fg) }
.otb--primary:hover { background: var(--action-primary-bg-hover); color: var(--action-primary-fg) }
.otb--primary:active { background: var(--action-primary-bg-active) }

.otb--secondary {
  background: var(--action-secondary-bg);
  color: var(--action-secondary-fg);
  border-color: var(--action-secondary-border);
}
.otb--secondary:hover { background: var(--action-secondary-bg-hover); border-color: var(--blue-300); color: var(--action-secondary-fg) }

.otb--accent { background: var(--accent-deep); color: var(--accent-on) }
.otb--accent:hover { filter: brightness(.93); color: var(--accent-on) }

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--surface-card) 90%, transparent);
  backdrop-filter: saturate(1.4) blur(10px);
  border-bottom: 1px solid var(--border-subtle);
}
.site-header__inner {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--nav-height);
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.logo {
  display: inline-flex;
  align-items: center;
  gap: .42em;
  color: var(--text-primary);
  text-decoration: none;
  line-height: 1;
}
.logo:hover { color: var(--text-primary); text-decoration: none }
.logo__mark { width: 30px; height: 30px; flex: none }
.logo__type {
  font-family: var(--font-display);
  font-weight: var(--fw-display-bold);
  font-size: var(--fs-h4);
  letter-spacing: -.03em;
  white-space: nowrap;
}
.logo__accent { color: var(--blue-500) }

.site-nav {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: auto;
}
.site-nav__link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 12px;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--text-secondary);
  font-family: var(--font-body);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
  white-space: nowrap;
  text-decoration: none;
  transition: var(--transition-ui);
}
.site-nav__link:hover { background: var(--action-ghost-bg-hover); color: var(--text-primary); text-decoration: none }
.site-nav__trigger { color: var(--text-primary); cursor: pointer }
.site-nav__count { color: var(--text-tertiary); font-variant-numeric: tabular-nums }
.site-nav__chevron { transition: transform var(--dur-fast) var(--ease-out) }
.site-nav__trigger[aria-expanded="true"] { background: var(--action-ghost-bg-hover) }
.site-nav__trigger[aria-expanded="true"] .site-nav__chevron { transform: rotate(180deg) }

/* --------------------------------------------------------------------------
   Mega menu — the "browse all tests" dropdown, ported from the homepage
   template. Anchored to the header so it spans the container, not the trigger.
   -------------------------------------------------------------------------- */
.site-nav__group { padding-bottom: 12px; margin-bottom: -12px }

.mega {
  position: absolute;
  top: 100%;
  right: var(--gutter);
  z-index: 50;
  width: min(calc(100vw - 2 * var(--gutter)), 780px);
  max-height: calc(100vh - var(--nav-height) - var(--space-4));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-3);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xl);
  box-shadow: var(--elev-2);
}
.mega[hidden] { display: none }

.mega__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  align-items: start;          /* columns size to their own content, not the row */
  gap: var(--space-3);
}
.mega__col { display: flex; flex-direction: column }

.mega__head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 8px 8px;
  border-bottom: 2px solid var(--accent);
  color: var(--text-primary);
  text-decoration: none;
}
.mega__head:hover { color: var(--text-primary); text-decoration: none }
.mega__col--soon .mega__head { border-bottom-color: var(--border-default) }

.mega__glyph {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  flex: none;
  border-radius: var(--radius-sm);
  background: var(--accent-tint);
  color: var(--accent-fg);
}
.mega__col--soon .mega__glyph { background: var(--surface-sunken); color: var(--text-tertiary) }

.mega__cat {
  font-family: var(--font-display);
  font-weight: var(--fw-display-medium);
  font-size: var(--fs-body);
}
.mega__count {
  margin-left: auto;
  font-size: var(--fs-caption);
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}

.mega__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 34px;
  margin-top: 2px;
  padding: 0 8px;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: var(--fs-body-sm);
  text-decoration: none;
  transition: var(--transition-ui);
}
a.mega__item:hover { background: var(--accent-tint); color: var(--accent-fg); text-decoration: none }
.mega__item--soon { color: var(--text-tertiary); font-style: normal }
.mega__meta {
  flex: none;
  white-space: nowrap;
  color: var(--text-tertiary);
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
}

.mega__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border-subtle);
}
.mega__note { font-size: var(--fs-body-sm); color: var(--text-secondary) }
.mega__foot-links { display: flex; align-items: center; gap: var(--space-3) }
.mega__foot-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
}
/* About us and Blog only surface here once they leave the top bar */
.mega__foot-link--small { display: none }

.icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 36px;
  height: 36px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--surface-card);
  color: var(--text-secondary);
  cursor: pointer;
  transition: var(--transition-ui);
}
.icon-button:hover { border-color: var(--blue-500); color: var(--text-primary) }

/* The six-hue palette spine under the header */
.palette-spine {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  height: 8px;
}
.palette-spine span { background: var(--accent) }

/* --------------------------------------------------------------------------
   Reserved ad slots — containers only, no scripts. Present from day one so
   switching ads on later cannot cause a layout shift or a redesign.
   -------------------------------------------------------------------------- */
.ad-rail { display: grid; place-items: center; padding: var(--space-3) var(--gutter) 0 }
.ad-rail--footer { padding: var(--space-4) var(--gutter) 0 }
.ot-ad--leaderboard {
  width: min(100%, var(--ad-leaderboard-w));
  height: var(--ad-leaderboard-h);
}
@media (max-width: 768px) {
  .ot-ad--leaderboard {
    width: min(100%, var(--ad-leaderboard-mobile-w));
    height: var(--ad-leaderboard-mobile-h);
  }
}

/* --------------------------------------------------------------------------
   Shared section furniture
   -------------------------------------------------------------------------- */
.section {
  max-width: var(--container-max);
  margin-inline: auto;
  padding: 0 var(--gutter) var(--space-8);
  /* anchor jumps must clear the sticky header */
  scroll-margin-top: calc(var(--nav-height) + var(--space-3));
}
.section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  flex-wrap: wrap;
}
.section__title {
  font-family: var(--font-display);
  font-weight: var(--fw-display-bold);
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: var(--ls-h2);
}
.section__aside { font-size: var(--fs-body-sm); color: var(--text-tertiary) }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 12px;
  border-radius: var(--radius-pill);
  background: var(--accent-tint);
  color: var(--accent-fg);
  font-size: var(--fs-caption);
  font-weight: var(--fw-medium);
  letter-spacing: .04em;
  text-transform: uppercase;
}

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */
.hero {
  max-width: var(--container-max);
  margin-inline: auto;
  padding: var(--space-6) var(--gutter) var(--space-8);
}
.hero__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--space-6);
  align-items: center;
}
.hero__copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
}
.hero__title {
  max-width: 16ch;
  font-family: var(--font-display);
  font-weight: var(--fw-display-bold);
  font-size: var(--fs-display-1);
  line-height: var(--lh-display-1);
  letter-spacing: var(--ls-display-1);
}
.hero__support {
  max-width: 46ch;
  font-size: var(--fs-body-lg);
  line-height: var(--lh-body-lg);
  color: var(--text-secondary);
}
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--space-2) }
.hero__note { font-size: var(--fs-body-sm); color: var(--text-tertiary) }

/* Featured card — the one live test, standing in for the sample-question panel */
.feature-card {
  position: relative;
  width: 100%;
  max-width: 520px;
  justify-self: end;
  padding: var(--space-4);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xl);
  box-shadow: var(--elev-2);
}
.feature-card__meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  font-size: var(--fs-caption);
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}
.feature-card__title {
  margin-top: var(--space-2);
  font-family: var(--font-display);
  font-weight: var(--fw-display-medium);
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
}
.feature-card__desc {
  margin-top: 8px;
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--text-secondary);
}
.feature-card__games {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
  margin-top: var(--space-3);
}
.game-chip {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: var(--space-2);
  background: var(--accent-tint);
  border-radius: var(--radius-md);
  color: var(--accent-fg);
  text-decoration: none;
  transition: var(--transition-ui);
}
.game-chip:hover { color: var(--accent-fg); text-decoration: none; transform: translateY(-2px) }
.game-chip__name { font-weight: var(--fw-semibold); font-size: var(--fs-body-sm) }
.game-chip__meta { font-size: var(--fs-caption); opacity: .8; font-variant-numeric: tabular-nums }

.feature-card__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border-subtle);
  font-size: var(--fs-body-sm);
  color: var(--text-tertiary);
}

.live-dot {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--accent-fg);
  font-weight: var(--fw-medium);
}
.live-dot::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
}

/* --------------------------------------------------------------------------
   Promise strip — what the site guarantees. Facts only, no vanity metrics.
   -------------------------------------------------------------------------- */
.promise {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1px;
  background: var(--border-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xl);
  overflow: hidden;
}
.promise__item { background: var(--surface-card); padding: var(--space-4) var(--space-3) }
.promise__value {
  font-family: var(--font-body);
  font-size: var(--fs-h2);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}
.promise__label { margin-top: 4px; font-size: var(--fs-body-sm); color: var(--text-secondary) }

/* --------------------------------------------------------------------------
   Badge — ported from the design system's Badge component
   -------------------------------------------------------------------------- */
.otbadge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 8px;
  font-family: var(--font-body);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  border: var(--border-width) solid transparent;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
.otbadge--square { border-radius: var(--radius-xs) }
.otbadge.is-neutral {
  background: var(--surface-sunken);
  color: var(--text-secondary);
  border-color: var(--border-subtle);
}
.otbadge.is-accent {
  background: var(--accent-tint);
  color: var(--accent-fg);
  border-color: color-mix(in srgb, var(--accent) 30%, transparent);
}

/* --------------------------------------------------------------------------
   Test card — ported from the design system's TestCard component.
   `--solid` is the full-bleed accent treatment used on the homepage grid.
   -------------------------------------------------------------------------- */
.otcard {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  height: 100%;
  padding: var(--space-3);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-lg);
  overflow: hidden;
  color: inherit;
  text-decoration: none;
  transition: var(--transition-ui);
}
.otcard::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: var(--accent);
}
.otcard:hover {
  color: inherit;
  text-decoration: none;
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  box-shadow: var(--elev-1);
  transform: translateY(-2px);
}
.otcard:active { transform: translateY(0) scale(var(--press-scale)) }

.otcard__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-top: var(--space-05);
}
.otcard__cat {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--accent-fg);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caption);
}
.otcard__glyph {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-md);
  background: var(--accent-tint);
  color: var(--accent-fg);
}
.otcard__title {
  font: var(--fw-display-bold) var(--fs-h4)/var(--lh-h4) var(--font-display);
  letter-spacing: var(--ls-h4);
  color: var(--text-primary);
}
.otcard__desc {
  margin-top: var(--space-05);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--text-secondary);
}
.otcard__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: auto;
  padding-top: var(--space-1);
  border-top: var(--border-width) solid var(--border-subtle);
  color: var(--text-tertiary);
  font-size: var(--fs-caption);
}
.otcard__meta span { display: inline-flex; align-items: center; gap: 4px }
.otcard__meta b { font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums }
.otcard__meta .otcard__end { margin-left: auto }

/* Solid variant */
.otcard--solid { background: var(--accent-deep); border-color: var(--accent-deep) }
.otcard--solid::before { background: color-mix(in srgb, var(--accent-on) 35%, transparent) }
.otcard--solid:hover { border-color: var(--accent-deep); filter: brightness(1.08); box-shadow: var(--elev-1) }
.otcard--solid .otcard__cat,
.otcard--solid .otcard__title { color: var(--accent-on) }
.otcard--solid .otcard__desc { color: color-mix(in srgb, var(--accent-on) 85%, transparent) }
.otcard--solid .otcard__glyph {
  background: color-mix(in srgb, var(--accent-on) 18%, transparent);
  color: var(--accent-on);
}
.otcard--solid .otcard__meta {
  color: color-mix(in srgb, var(--accent-on) 85%, transparent);
  border-top-color: color-mix(in srgb, var(--accent-on) 28%, transparent);
}
.otcard--solid .otbadge {
  background: color-mix(in srgb, var(--accent-on) 20%, transparent);
  border-color: color-mix(in srgb, var(--accent-on) 40%, transparent);
  color: var(--accent-on);
}

/* Not-yet-built cards: full accent fill so the palette stays intact, but no
   link affordance. The "Coming soon" badge carries the meaning, not a dim. */
.otcard--soon { cursor: default }
.otcard--soon:hover { transform: none; filter: none; box-shadow: none }

.test-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--grid-gap);
}
@media (max-width: 1000px) { .test-grid { grid-template-columns: repeat(2, 1fr) } }
@media (max-width: 640px)  { .test-grid { grid-template-columns: 1fr } }

/* --------------------------------------------------------------------------
   Category grid
   -------------------------------------------------------------------------- */
/* Explicit column counts, not auto-fill: six categories must land on even rows
   (6 / 3 / 2), never five-plus-one orphan. */
.category-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: var(--grid-gap);
}
@media (max-width: 1100px) { .category-grid { grid-template-columns: repeat(3, 1fr) } }
@media (max-width: 620px)  { .category-grid { grid-template-columns: repeat(2, 1fr) } }
.category-tile {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-top: 3px solid var(--accent);
  border-radius: var(--radius-lg);
  color: var(--text-primary);
  text-decoration: none;
  transition: var(--transition-ui);
}
.category-tile:hover {
  color: var(--text-primary);
  text-decoration: none;
  border-color: var(--accent);
  box-shadow: var(--elev-1);
  transform: translateY(-2px);
}
.category-tile__glyph {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-md);
  background: var(--accent-tint);
  color: var(--accent-fg);
}
.category-tile__name {
  font-family: var(--font-display);
  font-weight: var(--fw-display-medium);
  font-size: var(--fs-h4);
}
.category-tile__meta {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: auto;          /* pins the meta line to the bottom of every tile */
  padding-top: var(--space-1);
  font-size: var(--fs-body-sm);
  color: var(--text-secondary);
}

/* Coming-soon tiles keep full accent saturation — the palette is how the site
   says which category you are in, so dimming five of six breaks the spine.
   The "0 tests" count carries the meaning. They are simply not links. */
.category-tile--soon { cursor: default }
.category-tile--soon:hover {
  border-color: var(--border-subtle);
  border-top-color: var(--accent);
  box-shadow: none;
  transform: none;
}

/* --------------------------------------------------------------------------
   Why blocks
   -------------------------------------------------------------------------- */
.why-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--grid-gap);
}
.why-card {
  padding: var(--space-3);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}
.why-card__glyph {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-md);
  background: var(--accent-tint);
  color: var(--accent-fg);
}
.why-card__title {
  margin-top: var(--space-2);
  font-family: var(--font-display);
  font-weight: var(--fw-display-medium);
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
}
.why-card__body {
  margin-top: 6px;
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--text-secondary);
}

/* --------------------------------------------------------------------------
   FAQ
   -------------------------------------------------------------------------- */
.faq {
  display: grid;
  grid-template-columns: minmax(240px, 300px) 1fr;
  gap: var(--space-5);
  align-items: start;
}
.faq__intro { margin-top: var(--space-2); font-size: var(--fs-body); line-height: var(--lh-body); color: var(--text-secondary) }
.faq__list {
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.faq__item + .faq__item { border-top: 1px solid var(--border-subtle) }
.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  width: 100%;
  min-height: var(--tap-min);
  padding: var(--space-2) var(--space-3);
  border: 0;
  background: transparent;
  color: var(--text-primary);
  font-family: var(--font-display);
  font-weight: var(--fw-display-medium);
  font-size: var(--fs-body-lg);
  text-align: left;
  cursor: pointer;
  transition: var(--transition-ui);
}
.faq__q:hover { background: var(--surface-sunken) }
.faq__q .ot-icon { color: var(--text-tertiary) }
.faq__a {
  padding: 0 var(--space-3) var(--space-3);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
  max-width: 68ch;
}
.faq__item[data-open="false"] .faq__a { display: none }
.faq__item[data-open="false"] .i-minus,
.faq__item[data-open="true"] .i-plus { display: none }

@media (max-width: 860px) {
  .faq { grid-template-columns: 1fr; gap: var(--space-3) }
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */
.site-footer {
  background: var(--surface-card);
  border-top: 1px solid var(--border-subtle);
  padding-block: var(--space-6) var(--space-4);
}
.site-footer__inner {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
/* Three columns: brand, the live test's games, site links. The brand column is
   twice the width of a link column so the blurb keeps a readable measure. */
.site-footer__top {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  gap: var(--space-6);
  align-items: start;
}
.site-footer__brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.site-footer__blurb {
  margin-top: var(--space-2);
  max-width: 38ch;
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--text-secondary);
}
.site-footer__heading {
  display: block;
  color: var(--text-tertiary);
}
.site-footer__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-top: var(--space-2);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
}
.site-footer__list a {
  color: var(--text-secondary);
}
.site-footer__list a:hover {
  color: var(--text-link-hover);
}
.site-footer__bar {
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border-subtle);
}
.site-footer__note {
  max-width: 80ch;
  font-size: var(--fs-caption);
  line-height: var(--lh-body-sm);
  color: var(--text-tertiary);
}
.site-footer__legal {
  margin-top: var(--space-2);
  font-size: var(--fs-caption);
  color: var(--text-tertiary);
}

@media (max-width: 900px) {
  .site-footer__top {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-5);
  }
  .site-footer__brand { grid-column: 1 / -1 }
}
@media (max-width: 480px) {
  .site-footer__top { grid-template-columns: 1fr }
}

/* --------------------------------------------------------------------------
   Small screens
   -------------------------------------------------------------------------- */
/* Below 900px the top-bar links move into the dropdown's footer so the header
   stays on one line. Nothing becomes unreachable. */
@media (max-width: 900px) {
  .site-nav__link--secondary { display: none }
  .mega__foot-link--small { display: inline-flex }
  .mega__note { display: none }
  .mega__foot { justify-content: flex-end }
}
@media (max-width: 860px) { .mega__grid { grid-template-columns: repeat(2, 1fr) } }
@media (max-width: 560px) {
  .mega__grid { grid-template-columns: 1fr }
  .mega { width: calc(100vw - 2 * var(--gutter)) }
  .site-nav__trigger .site-nav__count { display: none }
}
@media (max-width: 620px) {
  .feature-card { justify-self: stretch; padding: var(--space-3) }
  .feature-card__games { grid-template-columns: 1fr }
  .hero__actions .otb { width: 100% }
}

/* Skip link */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: var(--space-2) var(--space-3);
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
}
.skip-link:focus { left: var(--gutter); top: var(--space-1) }

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

/* ---------------------------------------------------------------------------
   Content pages
   The title block and body copy for text pages: about, disclaimer, privacy,
   terms. Narrow measure, because these are read rather than scanned.
   --------------------------------------------------------------------------- */

.page-head {
  max-width: var(--container-max);
  margin-inline: auto;
  padding: var(--space-8) var(--gutter) var(--space-5);
}
.page-head__inner {
  max-width: var(--container-narrow);
}
.page-head__title {
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  line-height: var(--lh-h1);
  letter-spacing: var(--ls-h1);
  font-weight: var(--fw-display-bold);
  color: var(--text-primary);
  margin: var(--space-2) 0 0;
}
.page-head__lede {
  font-size: var(--fs-body-lg);
  line-height: var(--lh-body-lg);
  color: var(--text-secondary);
  margin: var(--space-3) 0 0;
}

.prose {
  max-width: var(--container-max);
  margin-inline: auto;
  padding: 0 var(--gutter) var(--space-10);
  color: var(--text-secondary);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}
/* Constrain the measure on each block rather than on the container, so the
   copy stays left-aligned with the page title instead of centring under it. */
.prose > * {
  max-width: var(--container-narrow);
}
.prose > * + * {
  margin-top: var(--space-3);
}
.prose h2 {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  letter-spacing: var(--ls-h3);
  font-weight: var(--fw-display-medium);
  color: var(--text-primary);
  margin-top: var(--space-6);
}
.prose h2:first-child {
  margin-top: 0;
}
.prose strong {
  color: var(--text-primary);
  font-weight: var(--fw-semibold);
}
.prose a {
  color: var(--text-link);
  text-underline-offset: 0.2em;
}
.prose a:hover {
  color: var(--text-link-hover);
}
.prose ul {
  margin-left: var(--space-4);
  list-style: disc;
}
.prose li + li {
  margin-top: var(--space-1);
}
/* Inline literals in the legal pages: storage keys, hostnames, values. */
.prose code {
  padding: 0.1em 0.35em;
  border-radius: var(--radius-sm);
  background: var(--surface-card);
  font-family: var(--font-numeric);
  font-size: 0.9em;
  color: var(--text-primary);
}
/* "Last updated" line that closes each legal page. */
.prose__meta {
  margin-top: var(--space-6);
  padding-top: var(--space-3);
  border-top: var(--border-width) solid var(--border-default);
  font-size: var(--fs-body-sm);
  color: var(--text-tertiary);
}

/* ===== games.css ===== */
/* --------------------------------------------------------------------------
   Games layer — the test hub, the game pages, and the play surface itself.
   Every value here comes from the token files. No new colours, type sizes or
   spacing steps are invented in this file.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   Page frame — main column plus the reserved sidebar ad rail
   -------------------------------------------------------------------------- */
.test-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: var(--space-6);
  align-items: start;
  max-width: var(--container-max);
  margin-inline: auto;
  padding: var(--space-4) var(--gutter) var(--space-8);
}
.test-main {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}
/* Reserved ad rail. Empty by design until roughly 10k monthly pageviews. */
.test-rail {
  position: sticky;
  top: calc(var(--nav-height) + var(--space-3));
}
.ot-ad--rail { min-height: 600px }
@media (max-width: 1080px) {
  .test-layout { grid-template-columns: minmax(0, 1fr) }
  .test-rail { display: none }
}

/* --------------------------------------------------------------------------
   Hub hero band. Ported from the design system's pymetrics-practice-test
   template, "heroLight" variant. Full width above the two-column layout, so
   the ad rail starts at the games section the way the template has it.
   -------------------------------------------------------------------------- */
.test-hero {
  border-bottom: var(--border-width) solid var(--border-subtle);
}
.test-hero__inner {
  max-width: var(--container-max);
  margin-inline: auto;
  padding: var(--space-4) var(--gutter) var(--space-8);
}
.test-hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 420px);
  align-items: center;
  gap: var(--space-5);
  margin-top: var(--space-6);
}
.test-hero__copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
}
/* Plain overline, not the pill `.eyebrow` used on the home page. The design
   system's hero uses quiet tertiary text here so the headline carries the page. */
.test-hero__eyebrow { color: var(--text-tertiary) }
.test-hero__title {
  margin: 0;
  max-width: 24ch;
  font-family: var(--font-display);
  font-weight: var(--fw-display-bold);
  font-size: var(--fs-display-1);
  line-height: var(--lh-display-1);
  letter-spacing: var(--ls-display-1);
  text-wrap: balance;
}
/* The highlight is amber in both themes, so it always needs the dark ink. */
.test-hero__mark {
  padding: 0 var(--space-1);
  background: var(--amber-500);
  color: var(--n-900);
}
.test-hero__lede {
  margin: 0;
  max-width: 52ch;
  font-size: var(--fs-body-lg);
  line-height: var(--lh-body-lg);
  color: var(--text-secondary);
  text-wrap: pretty;
}
.test-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
}
.test-hero__note {
  margin: var(--space-3) 0 0;
  max-width: 70ch;
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--text-secondary);
}

/* Decorative only, and hidden from assistive tech in the markup. */
.test-hero__shapes {
  position: relative;
  align-self: stretch;
  min-height: 280px;
  overflow: hidden;
}
.test-hero__ring,
.test-hero__triangle,
.test-hero__dot { position: absolute }
.test-hero__ring {
  top: var(--space-1);
  right: -72px;
  width: 236px;
  height: 236px;
  border: 12px solid var(--violet-500);
  border-radius: 50%;
}
.test-hero__triangle {
  bottom: 0;
  left: var(--space-1);
  width: 0;
  height: 0;
  border-left: 56px solid transparent;
  border-right: 56px solid transparent;
  border-bottom: 96px solid var(--amber-500);
}
.test-hero__dot {
  top: 96px;
  left: 104px;
  width: 76px;
  height: 76px;
  border-radius: 50%;
  background: var(--teal-500);
}

/* Stat strip. Every number in it is generated from the test data, never typed,
   so it cannot drift from what is actually built. */
.stat-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  gap: var(--border-width);
  max-width: 820px;
  margin-top: var(--space-5);
  background: var(--border-subtle);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-025);
  padding: var(--space-2);
  background: var(--surface-card);
}
.stat__value {
  font-family: var(--font-display);
  font-weight: var(--fw-display-bold);
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  letter-spacing: var(--ls-h3);
  font-variant-numeric: tabular-nums;
}
.stat__label {
  font-size: var(--fs-body-sm);
  color: var(--text-secondary);
}

@media (max-width: 900px) {
  .test-hero__grid { grid-template-columns: minmax(0, 1fr) }
  .test-hero__shapes { display: none }
}

/* --------------------------------------------------------------------------
   Breadcrumb
   -------------------------------------------------------------------------- */
.crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--fs-body-sm);
  color: var(--text-tertiary);
}
.crumbs a { color: inherit }
.crumbs a:hover { color: var(--text-link-hover) }
.crumbs [aria-current] { color: var(--text-secondary) }

/* --------------------------------------------------------------------------
   Page header for a test or a game
   -------------------------------------------------------------------------- */
.test-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.test-head__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.test-head__num {
  display: grid;
  place-items: center;
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  background: var(--accent-tint);
  color: var(--accent-fg);
  font-size: var(--fs-body);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
}
.test-head__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--fw-display-bold);
  font-size: var(--fs-h1);
  line-height: var(--lh-h1);
  letter-spacing: var(--ls-h1);
}
.test-head__meta {
  margin-left: auto;
  font-size: var(--fs-body-sm);
  color: var(--text-tertiary);
  white-space: nowrap;
}
.test-head__lede {
  margin: 0;
  max-width: 64ch;
  font-size: var(--fs-body-lg);
  line-height: var(--lh-body-lg);
  color: var(--text-secondary);
  text-wrap: pretty;
}
.traits {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
}
.trait {
  padding: 5px 12px;
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-pill);
  font-size: var(--fs-caption);
  color: var(--text-secondary);
}
@media (max-width: 560px) {
  .test-head__meta { margin-left: 0; width: 100% }
}

/* --------------------------------------------------------------------------
   Unofficial-practice notice. Appears on the hub and on every game page,
   not only on /disclaimer.
   -------------------------------------------------------------------------- */
.notice {
  padding: var(--space-3) var(--space-4);
  background: var(--warning-bg);
  border: var(--border-width) solid var(--warning-border);
  border-radius: var(--radius-lg);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--warning-fg);
}
.notice strong { font-weight: var(--fw-semibold) }

/* --------------------------------------------------------------------------
   Instructions card
   -------------------------------------------------------------------------- */
.instructions {
  padding: var(--space-4);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-subtle);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-lg);
}
.instructions__title {
  margin: 0 0 var(--space-2);
  font-family: var(--font-display);
  font-weight: var(--fw-display-medium);
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
}
.instructions ol {
  margin: 0;
  padding-left: 20px;
  display: flex;
  flex-direction: column;
  gap: var(--space-05);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
}

/* --------------------------------------------------------------------------
   Play surface
   -------------------------------------------------------------------------- */
.gm {
  padding: var(--space-4);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-xl);
}
.gm-idle {
  display: grid;
  place-items: center;
  min-height: 340px;
  border: var(--border-width) dashed var(--border-default);
  border-radius: var(--radius-lg);
  background: var(--surface-page);
}
.gm-panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.gm-scoreboard {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  padding-bottom: var(--space-3);
  border-bottom: var(--border-width) solid var(--border-subtle);
}
.gm-stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-025);
}
.gm-stat--divider {
  padding-left: var(--space-3);
  border-left: var(--border-width) solid var(--border-subtle);
}
.gm-stat__label { color: var(--text-tertiary) }
.gm-stat__value {
  font-family: var(--font-display);
  font-weight: var(--fw-display-bold);
  font-size: var(--fs-h4);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.gm-stage {
  display: grid;
  place-items: center;
  min-height: 340px;
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--surface-page);
  overflow: hidden;
}

.gm-controls {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.gm-action { flex: 1 1 200px }
.gm-controls--input { align-items: stretch }
.gm-input {
  flex: 1 1 200px;
  min-height: 56px;
  padding-inline: var(--space-3);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
  background: var(--surface-card);
  color: var(--text-primary);
  font-family: var(--font-numeric);
  font-size: var(--fs-h4);
  letter-spacing: var(--ls-h4);
}
.gm-input:focus-visible {
  outline: var(--focus-width) solid var(--focus-ring);
  outline-offset: var(--focus-offset);
}
.gm-input:disabled {
  background: var(--surface-sunken);
  color: var(--text-tertiary);
}

.gm-hint {
  margin: 0;
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  color: var(--text-tertiary);
}
.gm-announce {
  margin: 0;
  min-height: var(--space-3);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--text-secondary);
}

/* --------------------------------------------------------------------------
   Balloon
   -------------------------------------------------------------------------- */
.gm-balloon {
  --gm-inflate: 0;
  width: 96px;
  aspect-ratio: 5 / 6;
  border-radius: 50% 50% 46% 46%;
  background: var(--balloon-fill, var(--blue-500));
  transform: scale(calc(1 + var(--gm-inflate) * 1.6));
  transform-origin: bottom center;
  transition: transform var(--dur-fast) var(--ease-spring), opacity var(--dur-fast) var(--ease-out);
}
.gm-balloon[data-colour="blue"] { --balloon-fill: var(--blue-500) }
.gm-balloon[data-colour="amber"] { --balloon-fill: var(--amber-500) }
.gm-balloon[data-colour="coral"] { --balloon-fill: var(--red-500) }
.gm-balloon.is-burst {
  opacity: 0;
  transform: scale(1.9);
}

/* --------------------------------------------------------------------------
   Digits
   -------------------------------------------------------------------------- */
.gm-digit {
  min-height: 1.2em;
  font-family: var(--font-numeric);
  font-weight: var(--fw-display-bold);
  font-size: var(--fs-display-2);
  line-height: var(--lh-display-2);
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
  opacity: 0;
  transition: opacity var(--dur-instant) var(--ease-out);
}
.gm-digit.is-on { opacity: 1 }

/* --------------------------------------------------------------------------
   Arrows
   -------------------------------------------------------------------------- */
.gm-arrows {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-4);
  border-radius: var(--radius-lg);
  transition: background-color var(--dur-fast) var(--ease-out);
}
.gm-arrows.is-right { background: var(--success-bg) }
.gm-arrows.is-wrong { background: var(--danger-bg) }

.gm-arrow {
  width: 40px;
  height: 40px;
  background: var(--arrow-fill, var(--text-primary));
  clip-path: polygon(0 35%, 55% 35%, 55% 12%, 100% 50%, 55% 88%, 55% 65%, 0 65%);
}
.gm-arrow[data-dir="left"] { transform: scaleX(-1) }
.gm-arrows[data-colour="blue"] .gm-arrow { --arrow-fill: var(--blue-500) }
.gm-arrows[data-colour="grey"] .gm-arrow { --arrow-fill: var(--text-secondary) }
.gm-arrows[data-colour="red"] .gm-arrow { --arrow-fill: var(--red-500) }

@media (max-width: 560px) {
  .gm-arrow { width: 28px; height: 28px }
  .gm-arrows { gap: var(--space-1) }
}

/* --------------------------------------------------------------------------
   Result panel. No comparison-to-average bars — we have no such data and this
   site does not print numbers it cannot stand behind.
   -------------------------------------------------------------------------- */
.gm-result {
  margin-top: var(--space-4);
  padding: var(--space-5);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-subtle);
  border-top: 3px solid var(--accent);
  border-radius: var(--radius-xl);
}
.gm-result:focus-visible {
  outline: var(--focus-width) solid var(--focus-ring);
  outline-offset: var(--focus-offset);
}
.gm-result__title {
  margin: 0 0 var(--space-2);
  font-family: var(--font-display);
  font-weight: var(--fw-display-bold);
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: var(--ls-h2);
}
.gm-result__lede {
  margin: 0 0 var(--space-4);
  max-width: 62ch;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
}
.gm-result__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-2);
}
.gm-result__stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-05);
  padding: var(--space-3);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-md);
}
.gm-result__value {
  font-family: var(--font-display);
  font-weight: var(--fw-display-bold);
  font-size: var(--fs-h3);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.gm-result__reading {
  margin: var(--space-3) 0 0;
  max-width: 62ch;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
}
.gm-result__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

/* --------------------------------------------------------------------------
   Game rail — every game, linked from the hub and from each game page
   -------------------------------------------------------------------------- */
.game-rail {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: var(--space-2);
}
.game-rail__item {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 48px;
  padding-inline: var(--space-2);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-subtle);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
  transition: var(--transition-ui);
}
.game-rail__item:hover {
  background: var(--accent-tint);
  color: var(--text-primary);
  text-decoration: none;
}
.game-rail__item[aria-current] {
  background: var(--accent-tint);
  color: var(--accent-fg);
}
.game-rail__num {
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}
/* Games that do not have a page yet are listed, not linked. Being honest about
   what exists costs nothing and stops us shipping links to 404s. */
.game-rail__item--soon {
  border-left-color: var(--border-default);
  background: var(--surface-page);
  color: var(--text-tertiary);
  font-weight: var(--fw-body);
}
.game-rail__soon {
  margin-left: auto;
  font-size: var(--fs-caption);
  color: var(--text-tertiary);
}
.game-rail__item--all {
  border: var(--border-width) dashed var(--border-default);
  background: var(--surface-page);
  color: var(--text-secondary);
}

/* --------------------------------------------------------------------------
   Hub-only: the game explainer list. Ported from the design system's
   pymetrics-practice-test template — accent bar on top, number badge beside
   the heading, trait chips and a play link at the foot.
   -------------------------------------------------------------------------- */
.game-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.game-entry {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-subtle);
  border-top: 3px solid var(--accent);
  border-radius: var(--radius-lg);
  scroll-margin-top: calc(var(--nav-height) + var(--space-3));
}
.game-entry__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.game-entry__num {
  display: grid;
  place-items: center;
  flex: none;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  background: var(--accent-tint);
  color: var(--accent-fg);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
}
.game-entry__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--fw-display-medium);
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  letter-spacing: var(--ls-h3);
}
.game-entry__desc {
  margin: 0;
  max-width: 64ch;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
}
/* Preview-clip slot. The striped fill is the design system's "asset goes here"
   treatment, not a finished state. Replace with real recordings before launch. */
/* Frame for the game's animated preview. Was a dashed striped placeholder box
   until the previews landed; the aspect-ratio is unchanged so nothing below it
   moved. See previews.css for the loops themselves. */
.game-entry__media {
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 9;
  /* At full column width 16:9 makes a 415px-tall box, which scales the artwork
     2.3x and turns 2.5px strokes into 6px ones. The cap keeps the drawing at a
     sane size; the SVG's `meet` letterboxes it in the middle. */
  max-height: 240px;
  overflow: hidden;
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
  background: var(--surface-page);
}
/* Caption under the frame. Carries the same description the placeholder label
   used to, so nothing that was readable became decorative. */
.game-entry__media-label {
  display: block;
  margin-top: var(--space-1);
  font-family: var(--font-numeric);
  font-size: var(--fs-caption);
  color: var(--text-tertiary);
}
.game-entry__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.game-entry__play {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: var(--space-05);
  color: var(--accent-fg);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-semibold);
}
/* Games without a page yet say so rather than offering a dead link. */
.game-entry__soon {
  align-self: flex-start;
  font-size: var(--fs-body-sm);
  color: var(--text-tertiary);
}

/* ===== previews.css ===== */
/* ==========================================================================
   Game previews — the animated SVG loops on the test hub.

   Replaces the striped `gif · …` placeholder boxes from session 5.

   Rules this file follows, all of them deliberate:

   1. transform and opacity only. Never width, height, x, y, r, top or left.
      Twelve simultaneous loops on the site's most important page is exactly
      where a layout-animating property would show up as jank.
   2. Base CSS is the resting frame. Every loop is written so that switching
      the animation off leaves a still image that still reads. That is what
      makes the prefers-reduced-motion block small.
   3. Colour comes from --accent-fg, which the entry's data-category already
      sets. No preview hardcodes a hue.
   4. Loops are paused while off screen by main.js adding .gp-paused. They run
      by default, so if that script never executes the page is merely less
      efficient rather than visibly broken.
   ========================================================================== */

.gp {
  display: block;
  width: 100%;
  height: 100%;
}

/* SVG defaults: strokes are strokes, fills are explicit. Without this the
   browser fills every path solid black.

   ⚠️ Both selectors are wrapped in :where() on purpose. Written the obvious way,
   `.gp rect` scores 0,1,1 and silently outranks every single-class component
   rule below it (`.gp-pill`, `.gp-node`, `.gp-coin`, `.gp-disc`, …), which
   repainted the balloon, the pills and the discs in pale accent-tint and made
   several of them nearly invisible. :where() contributes zero specificity, so
   these behave as real defaults that any class can override. */
:where(.gp) :where(line, path) {
  fill: none;
  stroke: var(--accent-fg);
  stroke-width: 2.5;
  stroke-linecap: round;
}
:where(.gp) :where(rect, circle) {
  fill: var(--accent-tint);
  stroke: var(--accent-fg);
  stroke-width: 2;
}

.gp-fill-accent {
  fill: var(--accent-fg);
  stroke: none;
}
/* --text-tertiary, not --border-default. Against the frame's own background a
   border token lands around 1.4:1 and the line effectively disappears. */
.gp-stroke-muted {
  stroke: var(--text-tertiary);
  stroke-dasharray: 4 5;
}
.gp-pill {
  fill: var(--surface-card);
  stroke: var(--border-default);
}
.gp-label,
.gp-num {
  fill: var(--text-secondary);
  stroke: none;
  font-family: var(--font-numeric);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
}
.gp-num {
  font-size: 22px;
  fill: var(--accent-fg);
}
.gp-node,
.gp-head {
  fill: var(--surface-card);
}
/* Declared AFTER .gp-head deliberately. Both are single classes, so source
   order is what decides, and the eyes must win over the face they sit on.
   Styling the head as `.gp-face circle` instead scores 0,1,1, beats this rule,
   and paints the eyes the same colour as the face — which is exactly what
   happened, leaving two blank circles. */
.gp-eye {
  fill: var(--accent-fg);
  stroke: none;
}
.gp-panel {
  fill: var(--surface-card);
  stroke: var(--border-default);
}
.gp-missing {
  font-family: var(--font-numeric);
  font-size: var(--fs-caption);
  color: var(--text-tertiary);
}

/* Off-screen loops idle instead of burning CPU. Applied by main.js. */
.gp-paused .gp,
.gp-paused .gp * {
  animation-play-state: paused !important;
}

/* --- 01 balloon — pumping and banking ---------------------------------- */
.gp-balloon {
  transform-box: fill-box;
  transform-origin: center bottom;
  animation: gp-pump 3.4s var(--ease-out, ease-out) infinite;
}
.gp-bank {
  animation: gp-bank-flash 3.4s ease-in-out infinite;
}
/* Starts at 0.58 rather than 0.45: below that the balloon reads as a dot for
   the first fifth of every loop. */
@keyframes gp-pump {
  0%   { transform: scale(0.58); }
  20%  { transform: scale(0.72); }
  40%  { transform: scale(0.85); }
  60%  { transform: scale(0.97); }
  72%  { transform: scale(1); }
  80%  { transform: scale(0.58); }
  100% { transform: scale(0.58); }
}
@keyframes gp-bank-flash {
  0%, 68%   { fill: var(--surface-card); }
  76%, 84%  { fill: var(--accent-tint); }
  100%      { fill: var(--surface-card); }
}

/* --- 02 digits — sequence flashes, then recall -------------------------- */
.gp-digit {
  animation: gp-digit-flash 4s ease-in-out infinite;
  animation-delay: calc(var(--i) * 0.4s);
}
.gp-digit rect {
  fill: var(--surface-card);
}
.gp-recall line {
  stroke: var(--border-default);
  animation: gp-recall-in 4s ease-in-out infinite;
}
/* The dim state is 0.4, not 0.18. Lower than this and the four boxes read as a
   broken graphic for most of the loop rather than as unlit ones. */
@keyframes gp-digit-flash {
  0%, 4%    { opacity: 0.4; }
  10%, 18%  { opacity: 1; }
  26%, 100% { opacity: 0.4; }
}
@keyframes gp-recall-in {
  0%, 45%   { opacity: 0.45; }
  60%, 88%  { opacity: 1; }
  100%      { opacity: 0.45; }
}

/* --- 03 arrows — rows switching colour ---------------------------------- */
.gp-arrow {
  animation: gp-arrow-swap 2.8s steps(1, end) infinite;
  animation-delay: calc(var(--i) * 0.09s);
}
.gp-swap {
  fill: none;
  stroke: var(--accent-fg);
  animation: gp-swap-frame 2.8s steps(1, end) infinite;
}
@keyframes gp-arrow-swap {
  0%, 49%   { stroke: var(--accent-fg); opacity: 1; }
  50%, 100% { stroke: var(--border-default); opacity: 0.55; }
}
@keyframes gp-swap-frame {
  0%, 49%   { opacity: 0.35; }
  50%, 100% { opacity: 0; }
}

/* --- 04 keypress — GO cue, then rapid tapping --------------------------- */
.gp-go,
.gp-go-text {
  animation: gp-go-cue 2.6s ease-in-out infinite;
}
.gp-key {
  fill: var(--surface-card);
  animation: gp-key-press 2.6s ease-in-out infinite;
  transform-box: fill-box;
  transform-origin: center;
}
.gp-tap {
  fill: none;
  stroke: var(--accent-fg);
  transform-box: fill-box;
  transform-origin: center;
  opacity: 0;
  animation: gp-ripple 2.6s ease-out infinite;
  animation-delay: calc(0.9s + var(--i) * 0.22s);
}
@keyframes gp-go-cue {
  0%, 24%   { opacity: 0.2; }
  32%, 62%  { opacity: 1; }
  74%, 100% { opacity: 0.2; }
}
@keyframes gp-key-press {
  0%, 34%       { transform: scale(1); }
  40%, 50%, 60% { transform: scale(0.94); }
  45%, 55%, 70% { transform: scale(1); }
  100%          { transform: scale(1); }
}
@keyframes gp-ripple {
  0%   { opacity: 0.7; transform: scale(0.6); }
  40%  { opacity: 0;   transform: scale(1.5); }
  100% { opacity: 0;   transform: scale(1.5); }
}

/* --- 05 cards — drawing from four decks --------------------------------- */
.gp-deck rect {
  fill: var(--surface-card);
  animation: gp-deck-cycle 4.8s ease-in-out infinite;
  animation-delay: calc(var(--i) * 1.2s);
}
.gp-draw rect {
  transform-box: fill-box;
  transform-origin: center bottom;
  animation: gp-card-draw 4.8s ease-in-out infinite;
}
@keyframes gp-deck-cycle {
  0%, 6%    { fill: var(--accent-tint); }
  22%, 100% { fill: var(--surface-card); }
}
@keyframes gp-card-draw {
  0%       { opacity: 0; transform: translateY(0) rotate(0deg); }
  8%       { opacity: 1; transform: translateY(0) rotate(0deg); }
  26%      { opacity: 1; transform: translateY(-26px) rotate(-7deg); }
  42%      { opacity: 0; transform: translateY(-26px) rotate(-7deg); }
  100%     { opacity: 0; transform: translateY(0) rotate(0deg); }
}

/* --- 06 money exchange 1 — send, then receive back --------------------- */
.gp-coin {
  fill: var(--accent-fg);
  stroke: none;
  transform-box: fill-box;
}
.gp-coin--out {
  animation: gp-send 4s ease-in-out infinite;
}
.gp-coin--back {
  animation: gp-return 4s ease-in-out infinite;
}
.gp-dash {
  animation: gp-dash-pulse 4s ease-in-out infinite;
}
@keyframes gp-send {
  0%, 6%    { opacity: 0; transform: translateX(0); }
  14%       { opacity: 1; transform: translateX(0); }
  40%       { opacity: 1; transform: translateX(124px); }
  46%, 100% { opacity: 0; transform: translateX(124px); }
}
@keyframes gp-return {
  0%, 50%   { opacity: 0; transform: translateX(0); }
  58%       { opacity: 1; transform: translateX(0); }
  84%       { opacity: 1; transform: translateX(-124px); }
  90%, 100% { opacity: 0; transform: translateX(-124px); }
}
@keyframes gp-dash-pulse {
  0%, 100% { opacity: 0.4; }
  45%      { opacity: 1; }
}

/* --- 07 money exchange 2 — splitting a bonus ---------------------------- */
/* No `opacity: 0` here, deliberately. animation-fill-mode is `none`, so the base
   style IS the resting frame — setting the base to 0 made all six bars vanish
   whenever the animation was off, which is the whole preview gone under
   prefers-reduced-motion. The fade-in belongs in the keyframes, not the base. */
.gp-split rect {
  fill: var(--accent-tint);
  transform-box: fill-box;
  transform-origin: center;
  animation: gp-stack 4.2s ease-out infinite;
  animation-delay: calc(var(--i) * 0.28s);
}
.gp-split--right rect {
  animation-name: gp-stack-late;
  animation-delay: calc(0.5s + var(--i) * 0.28s);
}
@keyframes gp-stack {
  0%, 4%    { opacity: 0; transform: translateY(-14px); }
  16%, 84%  { opacity: 1; transform: translateY(0); }
  96%, 100% { opacity: 0; transform: translateY(0); }
}
@keyframes gp-stack-late {
  0%, 4%    { opacity: 0; transform: translateY(-14px); }
  20%, 84%  { opacity: 1; transform: translateY(0); }
  96%, 100% { opacity: 0; transform: translateY(0); }
}

/* --- 08 easy or hard — a selector moving between two panels ------------- */
.gp-pick {
  fill: none;
  stroke: var(--accent-fg);
  stroke-width: 3;
  transform-box: fill-box;
  animation: gp-pick-move 3.6s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
@keyframes gp-pick-move {
  0%, 34%   { transform: translateX(0); }
  50%, 84%  { transform: translateX(128px); }
  100%      { transform: translateX(0); }
}

/* --- 09 lengths — short mouth versus long mouth ------------------------- */
.gp-face {
  animation: gp-face-focus 3.2s ease-in-out infinite;
  animation-delay: calc(var(--i) * 1.6s);
}
.gp-mouth {
  stroke: var(--accent-fg);
  stroke-width: 3;
}
@keyframes gp-face-focus {
  0%, 6%    { opacity: 1; }
  46%, 96%  { opacity: 0.32; }
  100%      { opacity: 1; }
}

/* --- 10 faces — a face and three emotion words -------------------------- */
.gp-mouth--curve {
  stroke: var(--accent-fg);
  stroke-width: 3;
}
.gp-option {
  animation: gp-option-scan 4.2s ease-in-out infinite;
  animation-delay: calc(var(--i) * 0.5s);
}
.gp-option .gp-pill {
  transform-box: fill-box;
  transform-origin: center;
}
@keyframes gp-option-scan {
  0%, 8%    { opacity: 0.4; }
  18%, 30%  { opacity: 1; }
  42%, 100% { opacity: 0.4; }
}

/* --- 11 stop — go and stop signals alternating --------------------------
   The only preview that does not use the entry's accent hue. This game really
   is red and green circles, and depicting it in career-green would describe a
   different game. The square inside the stop signal is a deliberate second
   cue, so the two states are still distinguishable without colour vision.
   Raw --red-500/--emerald-500 are used rather than --cat-* tokens because the
   --cat-* set is remapped in dark mode and these two must not shift. */
.gp-signal--go {
  fill: var(--emerald-500);
  stroke: var(--emerald-600);
  animation: gp-signal-a 2.2s steps(1, end) infinite;
}
.gp-signal--stop {
  animation: gp-signal-b 2.2s steps(1, end) infinite;
}
.gp-signal--stop circle {
  fill: var(--red-500);
  stroke: var(--red-600);
}
.gp-signal--stop rect {
  fill: var(--surface-page);
  stroke: none;
}
@keyframes gp-signal-a {
  0%, 54%   { opacity: 1; }
  55%, 100% { opacity: 0; }
}
@keyframes gp-signal-b {
  0%, 54%   { opacity: 0; }
  55%, 100% { opacity: 1; }
}

/* --- 12 towers — a disc hopping between pegs ---------------------------- */
.gp-peg {
  stroke: var(--text-tertiary);
  stroke-width: 4;
}
/* Solid, unlike .gp-stroke-muted. A dashed floor under the pegs read as an
   unfinished graphic rather than as ground. */
.gp-floor {
  stroke: var(--text-tertiary);
  stroke-width: 2;
}
.gp-disc {
  fill: var(--accent-tint);
  stroke: var(--accent-fg);
  transform-box: fill-box;
}
.gp-disc--mover {
  animation: gp-hop 4s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
@keyframes gp-hop {
  0%   { transform: translate(0, 0); }
  18%  { transform: translate(28px, -56px); }
  34%  { transform: translate(70px, -14px); }
  50%  { transform: translate(70px, -14px); }
  66%  { transform: translate(112px, -56px); }
  82%  { transform: translate(140px, -14px); }
  100% { transform: translate(140px, -14px); }
}

/* --------------------------------------------------------------------------
   Reduced motion. Every loop above rests on a readable frame, so switching
   the animations off is nearly enough on its own. These four rules cover the
   cases whose resting state is deliberately invisible.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .gp,
  .gp * {
    animation: none !important;
  }
  /* Only three overrides are needed, because every base state above is already
     a readable frame. Anything more than this is a sign a loop is hiding its
     resting state in the base rule instead of in its keyframes. */
  .gp-balloon {
    transform: scale(0.85);
  }
  /* One coin in flight reads as a transfer; two reads as a bug. */
  .gp-coin--back {
    opacity: 0;
  }
  /* The two signals sit on the same centre, so showing both at once blends red
     over green into a muddy olive that reads as neither. Rest on the stop state
     alone: a red circle with a cut-out square is unambiguous, and the caption
     already says the two alternate. */
  .gp-signal--go {
    opacity: 0;
  }
  .gp-signal--stop {
    opacity: 1;
  }
  /* Rest the drawn card lifted clear of the deck it came from. */
  .gp-draw rect {
    transform: translateY(-26px) rotate(-7deg);
  }
}
