/* =============================================================
   unHero Game Studios
   Riso-print / arcade-flyer aesthetic:
   warm paper, heavy ink rules, hard offset shadows, spot colours.
   No framework, no build step.
   ============================================================= */

/* ---------- 1. Tokens ---------- */

:root {
  /* Ink & paper */
  --paper:      #F2EEE4;
  --paper-2:    #E7E1D3;   /* recessed panels */
  --ink:        #16150F;
  --ink-soft:   #55514A;
  --ink-faint:  rgba(22, 21, 15, .14);
  --on-ink:     #F7F4EC;

  /* Default spot colour (each game overrides --accent locally) */
  --accent:      #0E8FA8;
  --accent-deep: #0A5E6E;

  /* Shape */
  --rule: 2px;
  --pop: 7px;              /* hard offset shadow distance */
  --radius: 3px;

  /* Rhythm */
  --maxw: 1320px;
  --gutter: clamp(1.25rem, 5vw, 5rem);
  --pad-x: max(var(--gutter), calc((100% - var(--maxw)) / 2));
  --stack:  clamp(3.5rem, 9vw, 8rem);

  /* Type */
  --display: "Bricolage Grotesque", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: "Space Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --dot-ink: 22, 21, 15;   /* rgb triplet for the halftone canvas */
}

/* The accent used for *type*. Deepened on paper so it passes contrast,
   lifted on black stock for the same reason. Declared on .game as well so
   each panel resolves it from its own --accent. */
:root, .game { --accent-text: var(--accent-deep); }
:root[data-theme="dark"], :root[data-theme="dark"] .game {
  --accent-text: color-mix(in oklab, var(--accent) 78%, #FFF);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]), :root:not([data-theme="light"]) .game {
    --accent-text: color-mix(in oklab, var(--accent) 78%, #FFF);
  }
}

/* Night press: cream ink on black stock. */
:root[data-theme="dark"] {
  --paper:     #14130E;
  --paper-2:   #1E1C15;
  --ink:       #F0ECE0;
  --ink-soft:  #A19B8D;
  --ink-faint: rgba(240, 236, 224, .16);
  --on-ink:    #14130E;
  --dot-ink:   240, 236, 224;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:     #14130E;
    --paper-2:   #1E1C15;
    --ink:       #F0ECE0;
    --ink-soft:  #A19B8D;
    --ink-faint: rgba(240, 236, 224, .16);
    --on-ink:    #14130E;
    --dot-ink:   240, 236, 224;
  }
}

/* ---------- 2. Base ---------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--display);
  font-size: clamp(1rem, .95rem + .25vw, 1.125rem);
  line-height: 1.55;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Paper grain. Sits above the page, ignores pointer events. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: .35;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}
:root[data-theme="dark"] body::after { mix-blend-mode: screen; opacity: .18; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) body::after { mix-blend-mode: screen; opacity: .18; }
}

img, svg, canvas { display: block; max-width: 100%; }
h1, h2, h3 { margin: 0; line-height: .95; letter-spacing: -.035em; font-weight: 800; }
p { margin: 0 0 1em; }
ul, ol, dl { margin: 0; padding: 0; list-style: none; }

a { color: inherit; text-underline-offset: .18em; text-decoration-thickness: 2px; }

:focus-visible {
  outline: 3px solid var(--accent-text);
  outline-offset: 3px;
  border-radius: 1px;
}

::selection { background: var(--ink); color: var(--paper); }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 10000;
  background: var(--ink); color: var(--paper);
  padding: .75rem 1.25rem; font-family: var(--mono); font-size: .8rem;
}
.skip:focus { left: 0; }

/* Shared bits */
.sep { color: var(--accent-text); font-size: .7em; vertical-align: .12em; padding: 0 .55em; }

.eyebrow {
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 1.6rem;
}

/* ---------- 3. Buttons ---------- */

.btn {
  --btn-bg: var(--ink);
  --btn-fg: var(--paper);
  display: inline-flex;
  align-items: center;
  gap: .5em;
  padding: .78em 1.35em;
  border: var(--rule) solid var(--ink);
  border-radius: var(--radius);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: var(--mono);
  font-size: .82rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-decoration: none;
  box-shadow: var(--pop) var(--pop) 0 var(--ink);
  transition: transform .14s cubic-bezier(.2,.9,.3,1), box-shadow .14s cubic-bezier(.2,.9,.3,1), background-color .14s;
}
.btn--ghost { --btn-bg: transparent; --btn-fg: var(--ink); box-shadow: var(--pop) var(--pop) 0 var(--ink-faint); }
.btn--lg { font-size: .95rem; padding: 1em 1.7em; }
/* Not a link yet — the App Store listing it points at doesn't exist. Kept in
   the button row so the row still says where the game is going. */
.btn--soon { cursor: default; opacity: .55; }

.btn:hover, .btn:focus-visible {
  transform: translate(-3px, -3px);
  box-shadow: calc(var(--pop) + 3px) calc(var(--pop) + 3px) 0 var(--accent-text);
}
.btn:active { transform: translate(var(--pop), var(--pop)); box-shadow: 0 0 0 var(--accent-text); }
.btn__arrow { font-size: 1.05em; line-height: 0; }

@media (prefers-reduced-motion: reduce) { .btn { transition: none; } }

/* ---------- 4. Header ---------- */

.site-head {
  position: sticky;
  top: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  gap: clamp(1rem, 4vw, 3rem);
  padding: .85rem var(--pad-x);
  background: var(--paper);
  border-bottom: var(--rule) solid var(--ink);
}

.wordmark { display: inline-flex; align-items: center; gap: .55rem; text-decoration: none; }
.wordmark__mark { width: 1.15rem; height: 1.15rem; fill: var(--ink); flex: none; }
.wordmark__text { font-size: 1.18rem; font-weight: 400; letter-spacing: -.04em; }
.wordmark__text b { font-weight: 800; }

.site-nav { margin-left: auto; display: flex; gap: clamp(.9rem, 3vw, 2.25rem); }
.site-nav a {
  font-family: var(--mono);
  font-size: .78rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 2px solid transparent;
}
.site-nav a:hover { border-bottom-color: var(--accent-text); }

.theme-toggle {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: .4rem .7rem;
  color: var(--ink);
  background: transparent;
  border: var(--rule) solid var(--ink);
  border-radius: var(--radius);
  cursor: pointer;
}
.theme-toggle:hover { background: var(--ink); color: var(--paper); }

@media (max-width: 560px) {
  .site-nav a:nth-child(2) { display: none; }
}

/* ---------- 5. Hero ---------- */

.hero {
  position: relative;
  padding: clamp(4rem, 13vh, 9rem) var(--pad-x) clamp(3.5rem, 9vh, 6rem);
  border-bottom: var(--rule) solid var(--ink);
  overflow: hidden;
}
.hero__dots {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
}
.hero__inner { position: relative; z-index: 1; max-width: 68rem; }

.hero__title {
  font-size: clamp(2.9rem, 10.5vw, 8.5rem);
  font-weight: 800;
  font-stretch: 92%;
  line-height: .88;
  letter-spacing: -.045em;
  margin-bottom: clamp(1.5rem, 3vw, 2.25rem);
}
.hero__title em {
  font-style: normal;
  color: var(--accent-text);
  position: relative;
  white-space: nowrap;
}
/* Strike the word out. That is the whole joke, so it should read as ink. */
.hero__title em::after {
  content: "";
  position: absolute;
  left: -.045em; right: -.03em; top: 50%;
  height: .07em;
  background: var(--ink);
  transform: translateY(-50%) rotate(-1.3deg);
}

.hero__lede {
  max-width: 34ch;
  font-size: clamp(1.05rem, .95rem + .55vw, 1.4rem);
  line-height: 1.45;
  color: var(--ink-soft);
  margin-bottom: clamp(2rem, 4vw, 2.75rem);
}

.hero__actions { display: flex; flex-wrap: wrap; gap: 1rem clamp(1rem, 3vw, 1.75rem); }

/* ---------- 6. Ticker ---------- */

.ticker {
  background: var(--ink);
  color: var(--paper);
  border-bottom: var(--rule) solid var(--ink);
  overflow: hidden;
  padding: .6rem 0;
}
.ticker__track { display: flex; width: max-content; animation: marquee 34s linear infinite; }
.ticker__group {
  display: flex;
  align-items: center;
  font-family: var(--mono);
  font-size: .78rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  white-space: nowrap;
  padding-right: 0;
}
.ticker__group > span:not(.sep) { padding: 0 .1rem; }
.ticker .sep { color: var(--paper); opacity: .5; }

@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .ticker__track { animation: none; } }

/* ---------- 7. Sections ---------- */

.section { padding: var(--stack) var(--pad-x); }
.section--studio { background: var(--paper-2); border-top: var(--rule) solid var(--ink); }

.section__head {
  display: flex;
  align-items: baseline;
  gap: 1.25rem;
  padding-bottom: 1rem;
  margin-bottom: clamp(2.5rem, 6vw, 4.5rem);
  border-bottom: var(--rule) solid var(--ink);
}
.section__title { font-size: clamp(1.9rem, 5vw, 3.4rem); font-stretch: 90%; }
.section__meta {
  margin: 0 0 0 auto;
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: right;
}

/* ---------- 8. Game panels ---------- */

.games { display: grid; gap: clamp(3rem, 7vw, 6rem); }

.game {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: clamp(1.75rem, 5vw, 4rem);
  align-items: center;
}
.game:nth-child(even) .game__art { order: 2; }

/* Reveal on scroll (JS adds .is-in). Without JS the content is visible anyway. */
.game { opacity: 1; }
.js .game { opacity: 0; transform: translateY(22px); transition: opacity .7s ease, transform .7s cubic-bezier(.2,.8,.3,1); }
.js .game.is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js .game { opacity: 1; transform: none; transition: none; }
}

/* --- art frame --- */
.game__art {
  position: relative;
  aspect-ratio: 1 / 1;
  border: var(--rule) solid var(--ink);
  border-radius: var(--radius);
  background: var(--accent);
  box-shadow: var(--pop) var(--pop) 0 var(--ink);
  overflow: hidden;
  transition: transform .2s cubic-bezier(.2,.9,.3,1), box-shadow .2s cubic-bezier(.2,.9,.3,1);
}
.game:hover .game__art { transform: translate(-4px, -4px); box-shadow: calc(var(--pop) + 4px) calc(var(--pop) + 4px) 0 var(--ink); }
@media (prefers-reduced-motion: reduce) { .game__art { transition: none; } }

.game__art > img { width: 100%; height: 100%; object-fit: cover; }

/* A real capture is a photograph of a screen, not a printed object, so it sits
   ON the spot colour rather than replacing it: a device-shaped panel with the
   same ink rule and offset shadow as everything else. z-index lifts it over
   .art::before so the halftone screens the field but never the image. */
.shot {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 2;
  transform: translate(-50%, -50%);
  border: var(--rule) solid #1A0E06;
  background: #1A0E06;
  box-shadow: 6px 6px 0 rgba(26, 14, 6, .32);
  overflow: hidden;
  line-height: 0;
}
.shot img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* Height-led so a tall phone capture always fits the 1:1 frame. */
.shot--phone { height: 84%; aspect-ratio: 9 / 19.5; border-radius: 10px; }
/* Width-led for the browser builds, which are landscape. */
.shot--web { width: 88%; aspect-ratio: 16 / 10; border-radius: 5px; }

/* --- app icons ---
   The official App Store artwork where a game has a listing. assets/icon-<game>.svg
   is a provisional stand-in drawn from that game's own art block, and is the
   permanent mark for the browser-only games, which have no listing to take one
   from. The artwork is a printed object and does not follow the theme; the rule
   around it is ink, so it does. */
.game__icon, .ghero__icon {
  display: block;
  flex: none;
  border: var(--rule) solid var(--ink);
  border-radius: 22.5%;
}
.game__id { display: flex; align-items: center; gap: .8rem; margin-bottom: .4rem; }
.game__id .game__index { margin: 0; }
.ghero__icon { margin: 0 0 clamp(.9rem, 2vw, 1.35rem); }

/* The art blocks are printed objects: their ink does not follow the theme. */
.art { width: 100%; height: 100%; color: #F7F4EC; }
.art svg { width: 100%; height: 100%; }
/* Halftone dot pattern printed over the spot colour — the riso tell. */
.art::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: .16;
  background-image: radial-gradient(currentColor 1.2px, transparent 1.3px);
  background-size: 9px 9px;
  color: #000;
}

.art--spirit { background: #241A3D; }

/* --- art motion --- */

/* Droptide: the next piece falls in, the pile takes the hit. */
.art__drop { animation: tide-drop 2.6s cubic-bezier(.5,0,.85,.35) infinite; }
@keyframes tide-drop {
  0%        { transform: translateY(-72px); opacity: 0; }
  12%       { transform: translateY(-52px); opacity: 1; }
  56%       { transform: translateY(76px);  opacity: 1; }
  64%, 100% { transform: translateY(82px);  opacity: 0; }
}
.art__pop { transform-origin: 140px 268px; animation: tide-pop 2.6s ease-out infinite; }
@keyframes tide-pop {
  0%, 60%   { transform: scale(1); }
  68%       { transform: scale(1.055); }
  82%, 100% { transform: scale(1); }
}
.art__guide { animation: tide-guide 1.1s linear infinite; }
@keyframes tide-guide { to { stroke-dashoffset: -20; } }
.art__guide { stroke-dasharray: 6 14; }

/* Dashing Ralph: dog flaps to stay up, world rushes past. */
.art__ralph { transform-origin: 128px 254px; animation: ralph-fly 1.7s ease-in-out infinite; }
@keyframes ralph-fly {
  0%, 100% { transform: translateY(-7px) rotate(-1.6deg); }
  50%      { transform: translateY(7px) rotate(1.6deg); }
}
.art__eye { fill: var(--accent); }
.art__wing {
  transform-origin: 129px 250px;
  animation: ralph-flap .85s ease-in-out infinite alternate;
}
@keyframes ralph-flap { from { transform: rotate(18deg); } to { transform: rotate(-10deg); } }
.art__coins circle {
  animation: ralph-coin 1.5s ease-in-out infinite;
  animation-delay: calc(var(--i) * .11s);
}
@keyframes ralph-coin {
  0%, 100% { transform: translateY(0);    opacity: .85; }
  50%      { transform: translateY(-8px); opacity: 1; }
}
.art__shots > g {
  animation: ralph-shot 2.1s cubic-bezier(.3,0,.7,1) infinite;
  animation-delay: calc(var(--i) * -1.05s);
}
@keyframes ralph-shot {
  0%   { transform: translateX(110px); opacity: 0; }
  18%  { opacity: 1; }
  78%  { opacity: 1; }
  100% { transform: translateX(-150px); opacity: 0; }
}
.art__streaks line { animation: streak 1.2s linear infinite; animation-delay: calc(var(--i) * .19s); }
@keyframes streak {
  0%   { transform: translateX(-90px); opacity: 0; }
  30%  { opacity: .75; }
  100% { transform: translateX(170px); opacity: 0; }
}

/* Tiny Spirit: the character is a ball of light, so let it give off some. */
.art__orb { transform-origin: 198px 183px; animation: spirit-hover 3.4s ease-in-out infinite; }
@keyframes spirit-hover {
  0%, 100% { transform: translateY(-8px); }
  50%      { transform: translateY(8px); }
}
.art__aura circle {
  transform-origin: 198px 183px;
  opacity: 0;
  animation: spirit-aura 3.15s ease-out infinite;
  animation-delay: calc(var(--i) * 1.05s);
}
@keyframes spirit-aura {
  0%   { transform: scale(.55); opacity: 0; }
  18%  { opacity: .65; }
  100% { transform: scale(2.2); opacity: 0; }
}
.art__arc { animation: spirit-arc 1.4s linear infinite; }
@keyframes spirit-arc { to { stroke-dashoffset: -40; } }
.art__motes circle {
  opacity: .7;
  animation: drift 9s linear infinite;
  animation-delay: calc(var(--i) * -1.7s);
}
@keyframes drift {
  0%        { transform: translateY(60px);   opacity: 0; }
  20%, 80%  { opacity: .8; }
  100%      { transform: translateY(-160px); opacity: 0; }
}

/* Pencil Fleet: one flick, away off the right-hand edge of the paper and into
   one of theirs, with the pencil going blunt behind it. */
.art__line {
  stroke-dasharray: 490;
  stroke-dashoffset: 490;
  animation: fleet-flick 3.4s cubic-bezier(.16,.72,.35,1) infinite;
}
@keyframes fleet-flick {
  0%       { stroke-dashoffset: 490; opacity: 1; }
  34%      { stroke-dashoffset: 0;   opacity: 1; }
  88%      { stroke-dashoffset: 0;   opacity: 1; }
  100%     { stroke-dashoffset: 0;   opacity: 0; }
}
.art__cross { opacity: 0; animation: fleet-cross 3.4s linear infinite; }
@keyframes fleet-cross {
  0%, 32%  { opacity: 0; }
  40%, 88% { opacity: 1; }
  100%     { opacity: 0; }
}
/* The lead is spent on the flick and comes back over the rest of the loop. */
.art__lead { transform-origin: 30px 368px; animation: fleet-sharpen 3.4s linear infinite; }
@keyframes fleet-sharpen {
  0%       { transform: scaleX(1); }
  5%, 8%   { transform: scaleX(0); }
  92%,100% { transform: scaleX(1); }
}
/* Wrapped in a <g> of its own: a CSS transform would otherwise replace the
   translate that puts the ship on the page. */
.art__drift { animation: fleet-drift 5.4s ease-in-out infinite; }
@keyframes fleet-drift {
  0%, 100% { transform: translateX(-9px); }
  50%      { transform: translateX(9px); }
}

/* Euchre: the card leaves your hand, the trick takes the hit, and the up-card
   sits at the corner of the table waiting to be ordered up. */
.art__play { animation: euchre-play 3.8s cubic-bezier(.2,.8,.3,1) infinite; }
@keyframes euchre-play {
  0%        { transform: translate(-6px, 146px) rotate(-13deg); opacity: 0; }
  8%        { opacity: 1; }
  34%, 90%  { transform: translate(0, 0) rotate(7deg); opacity: 1; }
  100%      { transform: translate(0, 0) rotate(7deg); opacity: 0; }
}
.art__take { animation: euchre-take 3.8s ease-out infinite; }
@keyframes euchre-take {
  0%, 30%   { transform: scale(1); }
  38%       { transform: scale(1.05); }
  52%, 100% { transform: scale(1); }
}
/* The gap the played card left. It slides back as the next one is dealt. */
.art__lift { animation: euchre-lift 3.8s ease-in-out infinite; }
@keyframes euchre-lift {
  0%, 2%    { transform: translateY(0);     opacity: 1; }
  14%, 88%  { transform: translateY(-16px); opacity: 0; }
  99%, 100% { transform: translateY(0);     opacity: 1; }
}
.art__upcard { animation: euchre-upcard 3.8s ease-in-out infinite; }
@keyframes euchre-upcard {
  0%, 100% { opacity: .5; }
  50%      { opacity: 1; }
}

/* Stills. Every piece is composed to read with nothing moving. */
@media (prefers-reduced-motion: reduce) {
  .art__drop, .art__pop, .art__guide, .art__ralph, .art__wing,
  .art__coins circle, .art__shots > g, .art__streaks line, .art__orb,
  .art__aura circle, .art__arc, .art__motes circle,
  .art__line, .art__cross, .art__lead, .art__drift,
  .art__play, .art__take, .art__lift, .art__upcard { animation: none; }
  .art__aura circle { opacity: 0; }
  /* the flick has landed, rather than never having been made */
  .art__line { stroke-dashoffset: 0; }
  .art__cross { opacity: 1; }
}

/* --- game copy --- */
.game__index {
  font-family: var(--mono);
  font-size: clamp(2.4rem, 6vw, 4rem);
  font-weight: 700;
  line-height: 1;
  margin: 0 0 .4rem;
  color: transparent;
  -webkit-text-stroke: 2px var(--accent-text);
  letter-spacing: -.02em;
}
.game__title {
  font-size: clamp(2.1rem, 6vw, 3.9rem);
  font-stretch: 88%;
  margin-bottom: .5rem;
}
.game__hook {
  max-width: 40ch;
  font-size: clamp(1.02rem, .95rem + .35vw, 1.22rem);
  line-height: 1.5;
  color: var(--ink-soft);
  margin-bottom: 1.4rem;
}
.game__tags { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1.9rem; }
.game__tags li {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: .3rem .6rem;
  border: 1.5px solid var(--accent-text);
  border-radius: 100px;
  color: var(--accent-text);
}
.game__actions { display: flex; flex-wrap: wrap; gap: 1rem 1.5rem; }

@media (max-width: 800px) {
  .game { grid-template-columns: 1fr; }
  .game:nth-child(even) .game__art { order: 0; }
  /* The art is drawn square; a 4:3 frame would letterbox it. */
  .game__art { aspect-ratio: 1 / 1; }
  :root { --pop: 5px; }
}

/* ---------- 9. Studio ---------- */

.studio { max-width: 60ch; }
.studio__lead {
  font-size: clamp(1.3rem, 1.1rem + 1.1vw, 2.05rem);
  line-height: 1.22;
  letter-spacing: -.025em;
  font-weight: 600;
  margin-bottom: 1.5rem;
}
.studio p:not(.studio__lead) { color: var(--ink-soft); max-width: 52ch; }

.facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 1px;
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  background: var(--ink);
  border: var(--rule) solid var(--ink);
  border-radius: var(--radius);
  overflow: hidden;
}
.facts > div { background: var(--paper-2); padding: 1.15rem 1.25rem; }
/* The ink shows through the 1px gaps to draw the rules, so a half-filled row
   would leave a black hole. Stretch the last cell to the end of its row. */
.facts > div:last-child { grid-column: auto / -1; }
.facts dt {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: .35rem;
}
.facts dd { margin: 0; font-size: 1.06rem; font-weight: 600; letter-spacing: -.02em; }

/* ---------- 10. Footer ---------- */

.site-foot {
  background: var(--ink);
  color: var(--paper);
  padding: var(--stack) var(--pad-x) 2.5rem;
  border-top: var(--rule) solid var(--ink);
}
.site-foot .btn {
  --btn-bg: var(--paper);
  --btn-fg: var(--ink);
  border-color: var(--paper);
  box-shadow: var(--pop) var(--pop) 0 var(--accent);
}
.site-foot .btn:hover, .site-foot .btn:focus-visible {
  box-shadow: calc(var(--pop) + 3px) calc(var(--pop) + 3px) 0 var(--accent);
}
.site-foot :focus-visible { outline-color: var(--paper); }

.foot__cta { max-width: 40rem; margin-bottom: clamp(3.5rem, 8vw, 6rem); }
.foot__cta h2 { font-size: clamp(2.4rem, 8vw, 5rem); font-stretch: 90%; margin-bottom: .6rem; }
.foot__cta p { color: color-mix(in srgb, var(--paper) 62%, var(--ink)); max-width: 34ch; margin-bottom: 2rem; }

.foot__cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  max-width: 44rem;
  gap: 2rem;
  padding-bottom: 2.5rem;
  border-bottom: 1px solid color-mix(in srgb, var(--paper) 26%, var(--ink));
}
.foot__cols h3 {
  font-family: var(--mono);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--paper) 55%, var(--ink));
  margin-bottom: .9rem;
}
.foot__cols li { margin-bottom: .45rem; }
.foot__cols a { text-decoration: none; border-bottom: 1px solid transparent; }
.foot__cols a:hover { border-bottom-color: var(--paper); }

.foot__legal {
  margin: 1.75rem 0 0;
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .08em;
  color: color-mix(in srgb, var(--paper) 50%, var(--ink));
}
.foot__legal .wordmark__text { font-family: var(--display); font-size: .95rem; letter-spacing: -.03em; color: var(--paper); }
.foot__legal .sep { color: var(--accent); }

/* ---------- 11. Game pages ---------- */
/* One page per game (/dashingralph/, and the rest to follow). The page sets
   its own --accent / --accent-deep inline on <html>, so every accent below
   resolves from the game's colour rather than the site default. */

.crumb {
  display: inline-flex;
  align-items: center;
  gap: .55em;
  margin: 0 0 1.4rem;
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-decoration: none;
}
.crumb:hover { color: var(--accent-text); }

/* --- hero --- */
.ghero__grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
  gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
}
.ghero__title {
  font-size: clamp(2.7rem, 8vw, 6.2rem);
  font-stretch: 92%;
  line-height: .88;
  margin-bottom: clamp(1.25rem, 3vw, 1.9rem);
}
.ghero__lede {
  max-width: 38ch;
  font-size: clamp(1.05rem, .95rem + .5vw, 1.35rem);
  line-height: 1.45;
  color: var(--ink-soft);
  margin-bottom: 1.5rem;
}
.ghero__art { position: relative; }

@media (max-width: 860px) {
  .ghero__grid { grid-template-columns: 1fr; }
  /* Art first on a phone — it says what the game is faster than the copy. */
  .ghero__art { order: -1; max-width: 22rem; }
}

/* --- how it works --- */
.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: clamp(1.75rem, 4vw, 3rem);
}
.step__n {
  display: block;
  margin-bottom: .5rem;
  font-family: var(--mono);
  font-size: 2.3rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -.02em;
  color: transparent;
  -webkit-text-stroke: 2px var(--accent-text);
}
.step h3 { font-size: clamp(1.2rem, 1.05rem + .5vw, 1.5rem); margin-bottom: .5rem; }
.step p { margin: 0; color: var(--ink-soft); }

/* --- captioned cards, two or three up --- */
.notes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: clamp(1.5rem, 4vw, 2.5rem);
}
.note {
  padding: clamp(1.4rem, 3vw, 2.1rem);
  background: var(--paper-2);
  border: var(--rule) solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--pop) var(--pop) 0 var(--ink-faint);
}
.note__label {
  margin: 0 0 .85rem;
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent-text);
}
.note h3 { font-size: clamp(1.35rem, 1.1rem + .8vw, 1.8rem); margin-bottom: .6rem; }
.note p { margin: 0; color: var(--ink-soft); }

/* --- term/description grid (power-ups, and whatever else a game lists) --- */
/* Same 1px rules as .facts, but the number of things a game has to list is not
   going to divide evenly into however many columns fit — so the rules are drawn
   by a 1px ink ring on each cell rather than by ink showing through the gaps.
   A short row then ends in paper instead of a black hole, at any column count. */
.specs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1px;
  background: var(--paper);
  border: var(--rule) solid var(--ink);
  border-radius: var(--radius);
  overflow: hidden;
}
.specs > div {
  background: var(--paper);
  padding: 1.35rem 1.4rem;
  box-shadow: 0 0 0 1px var(--ink);
}
.specs dt {
  margin-bottom: .4rem;
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: -.02em;
  color: var(--accent-text);
}
/* max-width keeps the measure sane when few cells share a wide row. */
.specs dd { margin: 0; max-width: 46ch; font-size: .98rem; color: var(--ink-soft); }

/* The call to action under the facts grid, on a game page. */
.studio__cta {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 1.5rem;
  margin: clamp(2.5rem, 5vw, 3.5rem) 0 0;
}

/* Visually hidden, still read aloud and still indexed. Used to give a game
   page's <h1> the game's name when the display copy doesn't say it. */
.vh {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

/* ---------- 12. Prose pages (privacy, support, 404) ---------- */

.prose { max-width: 64ch; }
.prose > *:first-child { margin-top: 0; }
.prose h2 {
  font-size: clamp(1.25rem, 1.1rem + .7vw, 1.6rem);
  margin: clamp(2.25rem, 5vw, 3rem) 0 .8rem;
}
.prose h3 { font-size: 1.1rem; margin: 1.75rem 0 .5rem; }
.prose p, .prose li { color: var(--ink-soft); }
.prose ul { list-style: disc; padding-left: 1.3em; margin: 0 0 1em; }
.prose li { margin-bottom: .4rem; }
.prose a { color: var(--accent-text); text-decoration-thickness: 1.5px; }
.prose dt { font-weight: 700; margin-top: 1.25rem; }
.prose dd { margin: .25rem 0 0; color: var(--ink-soft); }

.prose__stamp {
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: clamp(2.5rem, 5vw, 3.5rem) 0 0;
  padding-top: 1.25rem;
  border-top: var(--rule) solid var(--ink-faint);
}

/* 404 — the hero title sizing without the hero grid. */
.gone { padding: clamp(4rem, 12vh, 8rem) var(--pad-x) clamp(3.5rem, 9vh, 6rem); }
.gone h1 { font-size: clamp(2.7rem, 9vw, 6rem); font-stretch: 92%; margin-bottom: 1.25rem; }
.gone p { max-width: 42ch; font-size: clamp(1.05rem, .95rem + .45vw, 1.3rem); color: var(--ink-soft); }
.gone__cta { margin: 2rem 0 0; }

/* Inline code in prose — hostnames and storage keys on the privacy page. */
.prose code {
  font-family: var(--mono);
  font-size: .88em;
  padding: .12em .35em;
  background: var(--paper-2);
  border: 1px solid var(--ink-faint);
  border-radius: 2px;
}
