/* ═══════════════════════════════════════════════════════════════════════════
   Clean Arcade — arcade layer (shared by /, /fr/, /de/, /es/, /ar/).

   Substrate: the Nocturne tokens in styles/nocturne.css — tonal ramps, spacing
   scale, radii, shadows, Inter. On top of it, the arcade's own neon: a lit
   violet night ground, one hue per category, and every edge drawn as a glowing
   tube rather than a border.

   Motion budget — every animation moves ONLY transform or opacity, so it runs
   on the compositor and never triggers layout or paint on the main thread:
     · hero aurora   2 gradient layers, transform drift, no filter pass
     · neon ticker   one transform: translateX track
     · card sweep    one conic pseudo-element, rotation, hover only
     · float / bob   transform: translateY on emoji + icons
     · CTA pulse     one pseudo-element opacity
   Hover scale/rotate use the independent `scale` / `rotate` longhands so they
   never collide with a running transform animation. Everything stops under
   prefers-reduced-motion.

   Logical properties throughout, so the Arabic build (dir="rtl") mirrors from
   this one stylesheet.
   ═════════════════════════════════════════════════════════════════════════ */

:root {
  /* brand neons */
  --brand-clean: #baff29;
  --brand-safe: #00f7ff;
  /* category neons — tube colours, read off the arcade-sign reference */
  --n-cyan: #00e9ff;
  --n-lime: #b8ff4a;
  --n-magenta: #ff2bd6;
  --n-violet: #a26bff;
  --n-yellow: #ffe14a;
  --n-green: #3dff90;
  --n-pink: #ff4fd8;
  --neon: var(--n-cyan);

  /* neon-night ground — the deck's section ground moved to page scale */
  --ground-1: #1b1136;
  --ground-2: #150e28;
  --ground-3: #100c1e;
  --card-face: color-mix(in srgb, var(--color-surface) 78%, #2b1a52);

  /* the shiny edge: one lit tube that runs magenta → neon → yellow → green */
  --edge: linear-gradient(135deg,
    color-mix(in srgb, var(--n-magenta) 70%, transparent),
    color-mix(in srgb, var(--neon) 90%, transparent) 34%,
    color-mix(in srgb, var(--n-yellow) 62%, transparent) 62%,
    color-mix(in srgb, var(--n-green) 72%, transparent) 82%,
    color-mix(in srgb, var(--n-magenta) 60%, transparent));
  --edge-lit: linear-gradient(135deg,
    var(--n-magenta), var(--neon) 34%, var(--n-yellow) 62%, var(--n-green) 82%, var(--n-magenta));

  --shell: 1160px;
  --gutter: clamp(14px, 3.2vw, 30px);
  --sec-y: calc(var(--space-8) * 2);
  --nav-h: calc(var(--space-8) * 2.5);
  --head-h: var(--nav-h);
}

html { color-scheme: dark; scroll-behavior: smooth; scroll-padding-top: calc(var(--head-h) + var(--space-4)); }

/* one hard guarantee against sideways scroll: clip on both boxes, and no
   element may widen the document (clip, unlike hidden, creates no scrollport) */
html, body { overflow-x: clip; max-width: 100%; }

body {
  text-wrap: pretty;
  font-size: 16.5px; line-height: 1.6; font-weight: 500;
  -webkit-font-smoothing: antialiased;
  background-color: var(--ground-2);
  background-image:
    radial-gradient(1100px 620px at 8% -10%, color-mix(in srgb, var(--n-violet) 30%, transparent), transparent 68%),
    radial-gradient(900px 520px at 96% 2%, color-mix(in srgb, var(--n-magenta) 17%, transparent), transparent 70%),
    radial-gradient(800px 620px at 50% 108%, color-mix(in srgb, var(--n-cyan) 12%, transparent), transparent 72%),
    linear-gradient(180deg, var(--ground-1) 0%, var(--ground-2) 46%, var(--ground-3) 100%);
  background-repeat: no-repeat;
  background-size: cover;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* the arcade and the game pages hand off as one continuous surface */
@view-transition { navigation: auto; }

[hidden] { display: none !important; }
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.skip {
  position: absolute; inset-inline-start: var(--space-4); inset-block-start: calc(var(--space-2) * -10);
  z-index: 100; background: var(--color-surface); color: var(--color-text);
  padding: var(--space-2) var(--space-4); border-radius: var(--radius-md);
  box-shadow: var(--shadow-md); transition: inset-block-start .15s ease;
}
.skip:focus-visible { inset-block-start: var(--space-4); }

/* equal gutters by construction: one padding value on both inline edges */
.shell { max-width: var(--shell); margin-inline: auto; padding-inline: var(--gutter); }

/* ── shared motion ───────────────────────────────────────────────────────── */
@keyframes ca-float { 50% { transform: translateY(-9px); } }
@keyframes ca-bob { 50% { transform: translateY(-4px); } }
@keyframes ca-spin { to { transform: rotate(1turn); } }
@keyframes ca-breathe { 50% { opacity: .85; } }

/* ── header ──────────────────────────────────────────────────────────────── */
/* A sticky backdrop-filter is the most expensive thing a scrolling page can
   own: the compositor must re-read and re-blur the region behind the bar on
   EVERY scroll frame, and what sits behind it here is body's four-layer
   gradient stack at background-size: cover. The bar is now an opaque surface
   — visually near-identical over this ground, and free to scroll past.
   `contain` stops the bar's own repaints from reaching the document. */
/* The bar carries no ground of its own: whichever theme is on flows straight
   through it, and the page's own gradient is what you see behind the brand.
   No background also means no backdrop-filter — a sticky blur is the most
   expensive thing a scrolling page can own, and there is now nothing to blur. */
.site-head {
  position: sticky; inset-block-start: 0; z-index: 50;
  background: transparent;
  /* `paint` was in this list and it clipped everything the header owns to the
     bar's own box — the timer's panel, the refresh hint. Layout and style
     containment give the same isolation without the clip. */
  contain: layout style;
  box-shadow: 0 1px 0 color-mix(in srgb, var(--n-cyan) 22%, transparent);
}
.site-head .nav {
  max-width: var(--shell); margin-inline: auto;
  min-height: var(--nav-h); padding-inline: var(--gutter);
  gap: var(--space-4);
  /* one row on desktop; the timer's panel and the refresh hint hang below the
     bar, so nothing here may clip */
  flex-wrap: nowrap; overflow: visible;
}
.brand {
  display: inline-flex; align-items: center; gap: var(--space-2);
  color: inherit; text-decoration: none; margin-inline-end: auto;
  flex: 0 1 auto; min-width: 0;
}
.brand-mark {
  font-size: 21px; line-height: 1; color: var(--n-cyan); flex: none;
  text-shadow: 0 0 10px color-mix(in srgb, var(--n-cyan) 75%, transparent),
               0 0 26px color-mix(in srgb, var(--n-cyan) 45%, transparent);
}
.brand-name {
  font-family: var(--font-heading); font-weight: 700; font-size: 19px; letter-spacing: -0.02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
.brand-badge {
  font-size: 10px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--n-lime); border: 1px solid color-mix(in srgb, var(--n-lime) 55%, transparent);
  box-shadow: 0 0 14px -4px var(--n-lime), inset 0 0 12px -8px var(--n-lime);
  padding: 3px var(--space-2); border-radius: 999px; white-space: nowrap; flex: none;
}
/* the official lockup (Brand/Site Logos/) on the game pages: the night file
   by Night and the day file by Day, never one on the other's ground */
.brand-lockup { display: block; flex: none; height: 40px; line-height: 0; }
.brand-lockup img { display: block; height: 100%; width: auto; }
.brand-lockup .brand-lockup-day { display: none; }
:root[data-theme="day"] .brand-lockup .brand-lockup-night { display: none; }
:root[data-theme="day"] .brand-lockup .brand-lockup-day { display: block; }
@media (max-width: 620px) { .brand-lockup { height: 32px; } }
.head-tools { display: flex; align-items: center; gap: var(--space-2); flex: 0 1 auto; min-width: 0; }
/* the break timer's slot — widgets.js drops #sa-break in here rather than
   floating it over the header, which is what used to land the countdown on
   top of the brand and the language row on a phone */
.head-timer { display: flex; align-items: center; flex: none; }

/* language switch — a shrinkable row that scrolls inside itself, never out */
.lang {
  display: flex; gap: var(--space-1); flex: 0 1 auto; min-width: 0;
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  justify-content: flex-end;
}
.lang::-webkit-scrollbar { display: none; }
.lang a {
  font-size: 12px; font-weight: 600; letter-spacing: 0.04em; flex: none;
  color: color-mix(in srgb, var(--color-text) 62%, transparent);
  padding: 5px var(--space-2); border-radius: var(--radius-sm); text-decoration: none;
  min-height: 32px; display: inline-flex; align-items: center; white-space: nowrap;
}
.lang a:hover { color: var(--n-cyan); background: color-mix(in srgb, var(--n-cyan) 12%, transparent); }
.lang a[aria-current="true"] {
  color: var(--n-cyan);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--n-cyan) 60%, transparent), 0 0 14px -6px var(--n-cyan);
}

@media (max-width: 1080px) {
  /* every touch target in the mobile chrome goes to the 44px minimum. --nav-h
     is 56px, so 44px items still fit one row: the header stays a single row
     and the #sa-break offset below stays valid. */
  :root { --head-h: var(--nav-h); }
  .site-head .nav { gap: var(--space-2); }
  .head-tools { gap: 4px; }
  .lang { gap: 0; }
  .lang a { min-height: 44px; min-width: 42px; justify-content: center; padding-inline: 6px; }
}

/* phone chrome: the brand and the five languages always fit one row without
   the page ever widening */
@media (max-width: 760px) {
  .brand-badge { display: none; }
}

/* ── phone header ───────────────────────────────────────────────────────
   Four things have to be visible at once on a 360px screen: the logo, the
   languages, the theme switch and the break timer. As one nowrap flex row
   they could only fit by overlapping. They are now two explicit grid rows —
   logo and timer on top, the whole tool cluster (refresh · theme · languages)
   beneath — so every control keeps its full 44px target and nothing is ever
   drawn over anything else. */
@media (max-width: 860px) {
  :root { --head-h: 110px; }
  .site-head .nav {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "brand timer"
      "tools tools";
    align-items: center;
    column-gap: var(--space-2);
    row-gap: 6px;
    padding-block: 8px;
    min-height: 0;
    /* both rows are reserved at their final 44px from the first paint: the
       timer, theme switch and refresh arrive from scripts a moment later and
       used to grow the header and shove the whole page down (layout shift) */
    grid-template-rows: 44px 44px;
  }
  .brand { grid-area: brand; margin-inline-end: 0; }
  .head-timer { grid-area: timer; justify-self: end; }
  .head-tools {
    grid-area: tools;
    justify-content: flex-end;
    flex-wrap: nowrap;
    gap: var(--space-2);
  }
  .lang { flex: 0 1 auto; }
  /* the timer is a header item now, not a floating pill */
  .head-timer #sa-break .sa-pill { font-size: 11.5px; padding: 6px 11px; gap: 6px; }
}
@media (max-width: 560px) {
  :root { --head-h: 110px; }
  .lang a { min-width: 32px; padding-inline: 4px; font-size: 11.5px; }
  /* the game pages carry "Back to Clean Arcade" twice — here and in the
     control row under the frame. On a phone only the one under the frame is
     worth the width. */
  .head-tools .back-pill { display: none; }
}
@media (max-width: 400px) {
  .head-timer #sa-break .sa-pill { font-size: 11px; padding: 5px 9px; }
}
@media (max-width: 400px) {
  .brand-name { font-size: 16.5px; }
  .lang a { min-width: 38px; font-size: 11.5px; }
}

/* ── hero ────────────────────────────────────────────────────────────────── */
.hero { position: relative; padding-block: calc(var(--sec-y) * 0.85) var(--sec-y); isolation: isolate; }
.aurora { position: absolute; inset: 0; overflow: hidden; z-index: -1; pointer-events: none; }
/* Two drift layers. `will-change` is deliberately NOT set: these animate
   transform, so the compositor promotes them for the duration of the animation
   on its own, and a permanent hint would pin two 46vmax textures in GPU memory
   for the life of the page.

   `filter: blur(60px)` is gone. A 60px Gaussian over a 46vmax layer is a real
   convolution the GPU has to run when the layer is rasterised — the single
   most expensive paint the homepage owned, and phones were the only devices
   excused from it, which left every tablet in landscape paying full price. The
   softness is now carried by the gradient's own stop ramp instead: four stops
   falling off to transparent read as the same diffuse wash, cost one gradient
   fill, and scale with nothing. Phones still drop the layers entirely below —
   two large translucent surfaces over the hero are worth skipping on a phone
   GPU whatever they cost to paint. */
.aurora i {
  position: absolute; display: block; border-radius: 50%;
  opacity: .46;
}
.aurora i:nth-child(1) {
  width: 46vmax; height: 46vmax; inset-block-start: -18vmax; inset-inline-start: -10vmax;
  background: radial-gradient(circle,
    color-mix(in srgb, var(--n-cyan) 48%, transparent) 0%,
    color-mix(in srgb, var(--n-cyan) 33%, transparent) 26%,
    color-mix(in srgb, var(--n-cyan) 16%, transparent) 46%,
    color-mix(in srgb, var(--n-cyan) 5%, transparent) 64%,
    transparent 80%);
  animation: ca-drift-a 26s ease-in-out infinite alternate;
}
.aurora i:nth-child(2) {
  width: 38vmax; height: 38vmax; inset-block-start: -6vmax; inset-inline-end: -12vmax;
  background: radial-gradient(circle,
    color-mix(in srgb, var(--n-magenta) 38%, transparent) 0%,
    color-mix(in srgb, var(--n-magenta) 26%, transparent) 26%,
    color-mix(in srgb, var(--n-magenta) 13%, transparent) 46%,
    color-mix(in srgb, var(--n-magenta) 4%, transparent) 64%,
    transparent 80%);
  animation: ca-drift-b 32s ease-in-out infinite alternate;
}
@keyframes ca-drift-a { to { transform: translate3d(12%, 8%, 0) scale(1.12); } }
@keyframes ca-drift-b { to { transform: translate3d(-10%, 12%, 0) scale(1.08); } }

.hero-in { max-width: none; }
.hero-in > :not(.hero-row) { max-width: 56ch; }
.kicker {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-size: 12px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--n-lime); text-shadow: 0 0 14px color-mix(in srgb, var(--n-lime) 55%, transparent);
  margin-block-end: var(--space-4);
}
.kicker i { font-size: 16px; }
/* the four selling points sit centred across the full hero container, not
   under the left-aligned 56ch text column */
.eyebrow { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2); margin: 0 auto var(--space-4); padding: 0; width: 100%; }
.eyebrow li { list-style: none; }
.eyebrow .tag {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 600; padding: 5px var(--space-3);
  color: var(--pill, var(--n-cyan));
  border: 1px solid color-mix(in srgb, var(--pill, var(--n-cyan)) 55%, transparent);
  box-shadow: 0 0 18px -8px var(--pill, var(--n-cyan)), inset 0 0 16px -12px var(--pill, var(--n-cyan));
  border-radius: 999px;
}
.eyebrow .tag > svg { width: 14px; height: 14px; flex: none; }
/* the four selling points: one even grid at every width — four equal
   pills in a centred row on tablet/laptop, a 2×2 block on phones */
.eyebrow { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-3); max-width: 760px; }
.eyebrow li { display: flex; min-width: 0; }
.eyebrow .tag { flex: 1; justify-content: center; min-height: 42px; padding: 8px var(--space-3); font-size: 13.5px; text-align: center; line-height: 1.2; }
.eyebrow .tag > svg { width: 16px; height: 16px; }
@media (max-width: 620px) {
  .eyebrow { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); }
  .eyebrow .tag { min-height: 40px; padding: 8px var(--space-2); font-size: 13px; }
  .eyebrow .tag > svg { width: 14px; height: 14px; }
}

.hero h1 {
  font-size: clamp(34px, 6.6vw, 60px); font-weight: 700; letter-spacing: -0.03em;
  line-height: 1.04; margin-block-end: var(--space-4);
}
.hero .lede {
  font-size: clamp(16px, 2vw, 19px); line-height: 1.6; font-weight: 400;
  color: color-mix(in srgb, var(--color-text) 84%, transparent);
  margin-block-end: var(--space-6); max-width: 52ch;
}
.cta-row { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }
/* phones: the two calls to action share one row rather than stacking into a
   column of full-width slabs */
@media (max-width: 620px) {
  .cta-row { flex-wrap: nowrap; gap: var(--space-2); }
  .cta-row .btn {
    flex: 1 1 0; min-width: 0; justify-content: center; text-align: center;
    padding-inline: var(--space-3); font-size: 14.5px;
  }
  .cta-row .btn i { flex: none; }
}
.btn-lg { font-size: 16px; font-weight: 600; padding: var(--space-3) var(--space-6); min-height: 48px; }
.btn-neon {
  position: relative; color: #061018;
  background: linear-gradient(100deg, var(--n-cyan), var(--n-green) 55%, var(--n-lime));
  border: 0; border-radius: 999px; overflow: hidden;
  box-shadow: 0 0 30px -10px var(--n-cyan);
}
.btn-neon::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: 0 0 34px 2px var(--n-cyan); opacity: .35;
  animation: ca-breathe 2.4s ease-in-out infinite;
}
.btn-neon:hover { color: #061018; }
.btn-neon:active { transform: translateY(1px); }

/* hero: selling points + the single Play Now call. Laptop/tablet — one line,
   pills then button, centred together. Phones — button centred below. */
.hero-row { display: flex; align-items: center; justify-content: center; gap: var(--space-4); flex-wrap: wrap; margin-block-end: var(--space-4); }
.hero-row .eyebrow { margin: 0; flex: 0 1 700px; }
/* same neon magenta as the About-the-developer heading (--n-magenta) */
.btn-play {
  position: relative; border-radius: 999px; min-height: 48px; white-space: nowrap;
  padding-inline: var(--space-6); color: #1a0616; font-weight: 700;
  background: linear-gradient(100deg, #ff5ce1, var(--n-magenta) 55%, #e619c0);
  border: 1px solid color-mix(in srgb, #ffc2f3 70%, transparent);
  box-shadow: 0 0 28px -6px var(--n-magenta), 0 0 60px -18px var(--n-magenta), inset 0 1px 0 rgba(255,255,255,.4);
  transition: box-shadow .18s ease, transform .18s ease, filter .18s ease;
}
.btn-play::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: 0 0 36px 4px var(--n-magenta); opacity: .4;
  animation: ca-breathe 2.4s ease-in-out infinite;
}
.btn-play:hover { color: #1a0616; filter: brightness(1.1); box-shadow: 0 0 38px -4px var(--n-magenta), 0 0 80px -16px var(--n-magenta), inset 0 1px 0 rgba(255,255,255,.45); }
.btn-play:active { transform: translateY(1px); filter: brightness(.95); }
.btn-play:focus-visible { outline: 2px solid #ffc2f3; outline-offset: 3px; }
.btn-play i { display: inline-flex; }
.btn-play svg { width: 16px; height: 16px; }
@media (max-width: 899px) {
  .hero-row { flex-direction: column; gap: var(--space-3); }
  .hero-row .eyebrow { flex: none; width: 100%; max-width: 760px; }
  .hero-row .btn-play { order: 1; }   /* first in source (start side on wide screens), below the pills here */
}
@media (max-width: 620px) {
  .hero-row .btn-play { width: 100%; max-width: 360px; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) { .btn-play::after { animation: none; } .btn-play { transition: none; } }

.btn-wire {
  border-radius: 999px; min-height: 48px;
  color: var(--n-pink); border-color: color-mix(in srgb, var(--n-pink) 65%, transparent);
  box-shadow: 0 0 22px -10px var(--n-pink), inset 0 0 18px -14px var(--n-pink);
}
.btn-wire:hover { background: color-mix(in srgb, var(--n-pink) 12%, transparent); }

/* The two brand words — lit, and static. These used to run ca-pulse-clean /
   ca-pulse-safe, which animate `text-shadow`: a PAINT property, so the glyphs
   were repainted on the main thread every frame for the life of the page. The
   lit look is carried by the resting shadow; nothing is lost but the cost. */
.neon-clean, .neon-safe { font-weight: 700; }
.neon-clean {
  color: var(--brand-clean);
  text-shadow: 0 0 9px color-mix(in srgb, var(--brand-clean) 92%, transparent),
               0 0 32px color-mix(in srgb, var(--brand-clean) 58%, transparent);
}
.neon-safe {
  color: var(--brand-safe);
  text-shadow: 0 0 9px color-mix(in srgb, var(--brand-safe) 92%, transparent),
               0 0 32px color-mix(in srgb, var(--brand-safe) 58%, transparent);
}

/* ── neon ticker (full-bleed, lit top and bottom edge) ───────────────────── */
.ticker {
  position: relative; overflow: hidden;
  border-block: 1px solid transparent;
  background:
    linear-gradient(90deg,
      color-mix(in srgb, var(--n-cyan) 9%, transparent),
      color-mix(in srgb, var(--n-magenta) 9%, transparent),
      color-mix(in srgb, var(--n-lime) 9%, transparent)) padding-box,
    var(--edge-lit) border-box;
  padding-block: var(--space-3);
  box-shadow: 0 0 34px -20px var(--n-cyan), 0 0 34px -20px var(--n-magenta);
  mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}
/* one composited translateX track; the marquee is the page's only always-on
   animation, and it is paused whenever it is scrolled out of view */
.ticker-track {
  display: flex; align-items: center; gap: calc(var(--space-8) * 1.5);
  width: max-content;
  animation: ca-ticker 34s linear infinite;
}
.ticker:hover .ticker-track { animation-play-state: paused; }
/* RTL is a MIRRORED marquee, not a reversed one. In an RTL flex row the track
   is laid out from the container's right edge and overflows to the LEFT, so
   the LTR keyframe (translateX(-50%)) walks the whole track past the left
   edge of the window: wherever the content is wider than the viewport — every
   phone — the marquee left the screen entirely and never came back. Mirroring
   the travel keeps the duplicated copy sliding in from the left, which is the
   same motion the LTR build has, read the other way. */
@keyframes ca-ticker { to { transform: translateX(-50%); } }
@keyframes ca-ticker-rtl { to { transform: translateX(50%); } }
[dir="rtl"] .ticker-track { animation-name: ca-ticker-rtl; }
.ticker span {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-size: 14px; font-weight: 600; white-space: nowrap;
  color: var(--tint, var(--n-cyan));
  text-shadow: 0 0 16px color-mix(in srgb, var(--tint, var(--n-cyan)) 55%, transparent);
}
.ticker span i { font-size: 17px; }

/* ── sections ────────────────────────────────────────────────────────────── */
/* Off-screen sections are skipped entirely by style, layout and paint until
   they scroll near the viewport. contain-intrinsic-size keeps the scrollbar
   honest so the page never jumps as they are realised. */
.sec { padding-block: var(--sec-y); }
.sec + .sec { padding-block-start: 0; }
/* a page that opens straight on a section (About) — no hero above it, so the
   full section rhythm would leave a hole under the header */
.sec-first { padding-block-start: var(--space-8, 32px); }
/* content-visibility is kept for the two prose sections (#why, #faq), whose
   height is stable and close to the 600px placeholder. It was REMOVED from
   the game-grid sections in the 2026 expansion: those grids grew from three
   cards to eight and nine, so the 600px placeholder was shorter than the
   realised grid and the section box stayed locked at the placeholder height
   while its contents laid out past it — Hero Quests spilled ~465px over
   Creative Play. A placeholder that cannot match the content is worse than
   no placeholder, and the two grids are near enough the top of the page that
   deferring them bought very little to begin with. */
.sec.defer { content-visibility: auto; contain-intrinsic-size: auto 600px; }
.sec-head { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin-block-end: var(--space-6); }
.sec-ico {
  display: grid; place-items: center; width: 38px; height: 38px; flex: none;
  font-size: 21px; color: var(--neon); border-radius: var(--radius-md);
  border: 1.5px solid transparent;
  background:
    linear-gradient(color-mix(in srgb, var(--neon) 10%, var(--ground-2)),
                    color-mix(in srgb, var(--neon) 4%, var(--ground-2))) padding-box,
    var(--edge) border-box;
  box-shadow: 0 0 24px -8px var(--neon), inset 0 0 18px -12px var(--neon);
}
.sec-ico i { line-height: 0; }
.sec-head h1, .sec-head h2 {
  font-size: clamp(23px, 3.2vw, 31px); font-weight: 700; margin: 0; letter-spacing: -0.02em;
  color: var(--neon); text-shadow: 0 0 18px color-mix(in srgb, var(--neon) 50%, transparent);
}
.sec-note {
  font-size: 13.5px; font-weight: 500; margin-inline-start: auto;
  color: color-mix(in srgb, var(--color-text) 62%, transparent);
}
.sec-rule {
  height: 2px; border: 0; margin: 0 0 var(--space-6);
  background: linear-gradient(to right, var(--neon), color-mix(in srgb, var(--n-magenta) 45%, transparent) 45%, transparent);
  box-shadow: 0 0 16px -3px var(--neon);
}

/* ── game grid ───────────────────────────────────────────────────────────── */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 248px), 1fr)); gap: var(--space-4); }
.gcard {
  position: relative; isolation: isolate; display: flex; flex-direction: column; overflow: hidden;
  min-width: 0; max-width: 100%;
  text-decoration: none; color: inherit;
  border: 1.5px solid transparent; border-radius: var(--radius-lg);
  background:
    linear-gradient(165deg, color-mix(in srgb, var(--card-face) 92%, var(--neon)), var(--card-face)) padding-box,
    var(--edge) border-box;
  box-shadow: 0 0 26px -16px var(--neon), 0 14px 30px -18px #000;
  transition: transform .18s ease, box-shadow .18s ease;
}
.gcard:hover, .gcard:focus-visible {
  transform: translateY(-4px);
  background:
    linear-gradient(165deg, color-mix(in srgb, var(--card-face) 88%, var(--neon)), var(--card-face)) padding-box,
    var(--edge-lit) border-box;
  box-shadow: 0 0 34px -10px var(--neon), 0 0 60px -28px var(--n-magenta), 0 18px 34px rgba(0,0,0,.5);
}
.gcard:active { transform: translateY(-1px); }
/* The sweep: one rotating conic highlight, hover only. `will-change` was set
   here permanently, which pinned a GPU texture of ~2.4× the card's area for
   every card in the grid (eight of them) even though the rotation was paused.
   The animation is now declared only in the hover state, so nothing is
   promoted, allocated or ticked until a pointer is actually on the card. */
.gcard::before {
  content: ""; position: absolute; inset: -70%; z-index: -1; pointer-events: none;
  background: conic-gradient(from 0deg,
    transparent 0 60%, color-mix(in srgb, #fff 55%, var(--neon)) 72%, transparent 82%);
  opacity: 0; transition: opacity .3s ease;
}
.gcard:hover::before, .gcard:focus-visible::before {
  opacity: .2;
  animation: ca-spin 5.5s linear infinite;
}
.gcard .thumb {
  position: relative; aspect-ratio: 16 / 10; display: grid; place-items: center;
  font-size: clamp(58px, 10vw, 72px); line-height: 1;
  background:
    radial-gradient(circle at 50% 58%, color-mix(in srgb, var(--neon) 30%, transparent), transparent 68%),
    linear-gradient(180deg, color-mix(in srgb, var(--neon) 6%, transparent), transparent);
  contain: paint;
}
/* the artwork floats on its own clock; hover scales with the independent
   scale/rotate longhands so the float animation keeps running underneath */
.gcard .thumb span {
  display: block;
  animation: ca-float 4.6s ease-in-out infinite;
  transition: scale .3s cubic-bezier(.2,.8,.3,1), rotate .3s cubic-bezier(.2,.8,.3,1);
}
.gcard:hover .thumb span { scale: 1.14; rotate: -5deg; }
.grid .gcard:nth-child(2) .thumb span { animation-delay: -1.5s; }
.grid .gcard:nth-child(3) .thumb span { animation-delay: -3s; }
/* shine sweep — one composited pass across the artwork */
.gcard .thumb::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 34%, rgba(255,255,255,.2) 50%, transparent 66%);
  transform: translateX(-130%); transition: transform .75s ease;
}
.gcard:hover .thumb::after { transform: translateX(130%); }
.gcard .body { padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); flex: 1; }
.gcard h3 { font-size: 17px; font-weight: 700; margin: 0; letter-spacing: -0.015em; }
.gcard p { margin: 0; font-size: 14px; font-weight: 400; line-height: 1.5; color: color-mix(in srgb, var(--color-text) 78%, transparent); flex: 1; }
.gcard .meta { display: flex; align-items: center; gap: var(--space-2); font-size: 12px; font-weight: 500; color: color-mix(in srgb, var(--color-text) 58%, transparent); flex: none; }
.gcard .go {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-height: 44px; margin-block-start: var(--space-1); border-radius: 999px;
  font-size: 14.5px; font-weight: 700; color: var(--neon);
  border: 1px solid color-mix(in srgb, var(--neon) 55%, transparent);
  background: color-mix(in srgb, var(--neon) 9%, transparent);
  box-shadow: 0 0 20px -10px var(--neon), inset 0 0 18px -14px var(--neon);
  transition: background .18s ease, box-shadow .18s ease;
}
.gcard .go i { font-size: 18px; }
.gcard:hover .go { background: color-mix(in srgb, var(--neon) 18%, transparent); box-shadow: 0 0 24px -6px var(--neon); }

/* featured — the banner card */
.gcard.feat { grid-column: 1 / -1; flex-direction: row; align-items: stretch; }
.gcard.feat .thumb { aspect-ratio: auto; flex: 0 0 40%; min-height: calc(var(--space-8) * 11); font-size: clamp(76px, 11vw, 124px); }
.gcard.feat .body { padding: clamp(var(--space-6), 3vw, calc(var(--space-8) * 1.7)); justify-content: center; gap: var(--space-3); }
.gcard.feat h3 { font-size: clamp(24px, 3.4vw, 34px); letter-spacing: -0.025em; }
.gcard.feat p { font-size: clamp(14.5px, 1.8vw, 16.5px); max-width: 46ch; flex: none; }
.gcard.feat .go { align-self: flex-start; padding-inline: var(--space-8); }
/* Two banner cards abreast — the Featured pair. The banner card is a
   full-width row by default; in a duo it stacks (art over copy) and the two
   share the row, collapsing to one column when the track can no longer hold
   two. Nothing here overrides the 760px rules below: both paths land on the
   same stacked geometry, so there is no width at which they disagree. */
.grid.duo { grid-template-columns: repeat(auto-fit, minmax(min(100%, 330px), 1fr)); }
.grid.duo .gcard.feat { grid-column: auto; flex-direction: column; }
.grid.duo .gcard.feat .thumb { flex: none; aspect-ratio: 16 / 9; min-height: 0; font-size: clamp(64px, 8vw, 96px); }
.grid.duo .gcard.feat .body { padding: var(--space-6); justify-content: flex-start; }
.grid.duo .gcard.feat h3 { font-size: clamp(20px, 2.3vw, 26px); }
.grid.duo .gcard.feat p { font-size: 15px; max-width: none; flex: 1; }
.grid.duo .gcard.feat .go { align-self: stretch; padding-inline: var(--space-6); }
.flag-tag {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  font-size: 11px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--neon); padding: 4px var(--space-3); border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--neon) 60%, transparent);
  box-shadow: 0 0 20px -8px var(--neon), inset 0 0 16px -12px var(--neon);
}
.flag-tag i { line-height: 0; }
@media (max-width: 760px) {
  .gcard.feat { flex-direction: column; }
  .gcard.feat .thumb { flex: none; aspect-ratio: 16 / 9; min-height: 0; }
  .gcard.feat .go { align-self: stretch; }
}

/* ── why / features ──────────────────────────────────────────────────────── */
.feats { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr)); gap: var(--space-6); }
.feat-item {
  display: flex; flex-direction: column; gap: var(--space-2);
  padding: var(--space-4); border-radius: var(--radius-md);
  border: 1.5px solid transparent;
  background:
    linear-gradient(160deg, color-mix(in srgb, var(--card-face) 86%, var(--tint, var(--n-cyan))),
                    color-mix(in srgb, var(--card-face) 96%, transparent)) padding-box,
    linear-gradient(140deg,
      color-mix(in srgb, var(--tint, var(--n-cyan)) 75%, transparent),
      color-mix(in srgb, var(--n-yellow) 40%, transparent) 55%,
      color-mix(in srgb, var(--tint, var(--n-cyan)) 55%, transparent)) border-box;
  box-shadow: 0 0 24px -16px var(--tint, var(--n-cyan));
  transition: box-shadow .18s ease, transform .18s ease;
}
.feat-item:hover { transform: translateY(-3px); box-shadow: 0 0 30px -10px var(--tint, var(--n-cyan)); }
.feat-item .ico {
  font-size: 26px; line-height: 1; height: 28px; color: var(--tint, var(--n-cyan));
  text-shadow: 0 0 18px color-mix(in srgb, var(--tint, var(--n-cyan)) 60%, transparent);
  animation: ca-float 5s ease-in-out infinite;
}
.feat-item:nth-child(2) .ico { animation-delay: -1.2s; }
.feat-item:nth-child(3) .ico { animation-delay: -2.4s; }
.feat-item:nth-child(4) .ico { animation-delay: -3.6s; }
.feat-item h3 { font-size: 16.5px; font-weight: 700; margin: 0; }
.feat-item p { margin: 0; font-size: 14px; font-weight: 400; line-height: 1.55; color: color-mix(in srgb, var(--color-text) 76%, transparent); }
/* Why Families Choose — every word capitalised (all five locales), and on
   phones and tablets the icon sits beside its text instead of above it */
#why .sec-head h2, #why .feat-item h3 { text-transform: capitalize; }
@media (max-width: 1024px) {
  #why .feat-item {
    display: grid; grid-template-columns: auto minmax(0, 1fr);
    column-gap: var(--space-3); row-gap: 2px; align-items: start;
  }
  #why .feat-item .ico { grid-row: 1 / span 2; height: auto; margin-block-start: 1px; }
}
/* the live figures in #numbers — the card's tint, at headline scale */
.feat-item p.ca-stat {
  font-size: clamp(30px, 4.4vw, 42px); font-weight: 800; line-height: 1.05;
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
  color: var(--tint, var(--n-cyan));
  text-shadow: 0 0 22px color-mix(in srgb, var(--tint, var(--n-cyan)) 45%, transparent);
  margin-block: 2px;
}
:root[data-theme="day"] .feat-item p.ca-stat { text-shadow: none; }

/* ── faq ─────────────────────────────────────────────────────────────────── */
.faq { max-width: 76ch; }
.faq details {
  border-radius: var(--radius-md); padding-inline: var(--space-3);
  background-image: linear-gradient(to right, transparent, color-mix(in srgb, var(--n-cyan) 28%, transparent) 48px, color-mix(in srgb, var(--n-cyan) 28%, transparent) calc(100% - 48px), transparent);
  background-repeat: no-repeat; background-position: bottom; background-size: 100% 1px;
}
.faq details[open] { background-color: color-mix(in srgb, var(--n-cyan) 6%, transparent); }
.faq summary {
  cursor: pointer; list-style: none; padding-block: var(--space-4); min-height: 48px;
  font-family: var(--font-heading); font-weight: 600; font-size: 16px;
  display: flex; align-items: center; gap: var(--space-3);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+"; margin-inline-start: auto; color: var(--n-cyan); font-size: 20px; line-height: 1;
  text-shadow: 0 0 12px color-mix(in srgb, var(--n-cyan) 70%, transparent);
  transition: transform .18s ease;
}
.faq details[open] summary::after { transform: rotate(45deg); }
.faq summary:hover { color: var(--n-cyan); }
.faq details > div { padding-block-end: var(--space-4); font-size: 14.5px; font-weight: 400; line-height: 1.65; color: color-mix(in srgb, var(--color-text) 80%, transparent); max-width: 66ch; }

/* ── document footer ─────────────────────────────────────────────────────── */
.site-foot { padding-block: var(--sec-y) calc(var(--space-8) * 3); }
.foot-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr)); gap: var(--space-6) var(--space-8); }
.foot-grid h2 {
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--n-cyan); text-shadow: 0 0 14px color-mix(in srgb, var(--n-cyan) 45%, transparent);
  margin-block-end: var(--space-3);
}
.foot-grid ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.foot-grid a {
  font-size: 14px; color: color-mix(in srgb, var(--color-text) 80%, transparent);
  text-decoration: none; display: inline-flex; align-items: center; min-height: 32px;
}
.foot-grid a:hover { color: var(--n-lime); }
.foot-note { margin-block-start: var(--space-8); font-size: 12.5px; font-weight: 400; color: color-mix(in srgb, var(--color-text) 55%, transparent); max-width: 72ch; }
.foot-note a { color: var(--n-cyan); font-weight: 700; text-decoration: none; }
.foot-note a:hover { color: var(--n-lime); text-decoration: underline; }
.foot-note a:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }

/* footer links to the 44px minimum on touch widths. This block sits AFTER the
   base .foot-grid rules on purpose: both selectors weigh the same, so an
   override declared up in the header section would lose the cascade. */
@media (max-width: 1080px) {
  .foot-grid ul { gap: var(--space-2); }
  .foot-grid a { min-height: 44px; }
}

/* the shared pills are anchored to the viewport by assets/js/widgets.js, where
   they would land on this page's header and hero copy. On the arcade pages they
   move into the empty inline-end margin; the game pages keep them as they were.
   Fixed position, so moving them costs no layout.

   `:not(.sa-in-head)` — once the timer has a real slot in the header it is a
   flow item and must not be pinned to the viewport at all. */
#sa-break:not(.sa-in-head) { top: calc(var(--head-h) + var(--space-2)) !important; inset-inline: auto var(--space-4) !important; }
.head-timer #sa-break { position: relative !important; inset: auto !important; max-width: none; }
#sa-prayer { inset-inline: auto var(--space-4) !important; }
/* both pills now sit against the inline-end edge, so their panels must open
   inward from that same edge. Anchored from the start edge (the default, which
   is right for the game pages where the pill sits bottom-left), a 210px panel
   hanging off a much narrower pill ran past the viewport and clipped the whole
   times column — names visible, times off-screen. */
#sa-prayer .sa-panel { inset-inline-start: auto !important; inset-inline-end: 0 !important; }

/* ── view transitions ────────────────────────────────────────────────
   Only the root crossfade survives. Each `view-transition-name` forces its
   element into its own snapshot layer for the WHOLE life of the document, not
   just during a navigation — eight card thumbnails plus the sticky header was
   nine permanently promoted layers, one of them a blurred bar being
   re-composited on every scroll frame. The crossfade reads the same. */

/* ── off-screen animation gate ────────────────────────────────────────
   The marquee was already paused out of view, on the argument that a loop
   which is never done keeps the compositor ticking for the whole life of the
   page. The same argument applies to every other permanent loop, and the two
   that were left running are the ones the deferred sections do not cover:
   the card thumb glyphs in #featured and #family (those sections paint
   immediately, so content-visibility never gates them) and the hero button's
   breathe. app.js adds .ca-idle when the owner leaves the viewport. Pausing
   is state-only — no reflow, no restart, and the glyph resumes mid-cycle. */
.gcard.ca-idle .thumb span { animation-play-state: paused; }
.btn-neon.ca-idle::after { animation-play-state: paused; }

/* ── the arrival ─────────────────────────────────────────────────────────
   Cards rise into place as they are scrolled to, staggered along their row.
   Two properties only — opacity and the `translate` longhand — so the whole
   effect runs on the compositor and costs no layout or paint. `translate`
   rather than `transform` on purpose: the hover lift owns `transform`, and
   the two must not fight over the same property.

   html.ca-motion is written by ca-boot.js before first paint, and only when
   the device has not asked for reduced motion. app.js removes it if there is
   no IntersectionObserver to drive it, so the cards can never be left
   invisible by a script that did not run. */
html.ca-motion .gcard {
  opacity: 0;
  translate: 0 20px;
  transition: opacity .55s ease, translate .55s cubic-bezier(.2,.8,.3,1),
              transform .18s ease, box-shadow .18s ease;
}
html.ca-motion .gcard.is-in { opacity: 1; translate: 0 0; }

/* the logo breathes — one small glyph, one transform, nothing else */
html.ca-motion .brand-mark { animation: ca-float 6.5s ease-in-out infinite; }
html.ca-motion .hero .kicker i { animation: ca-bob 4.2s ease-in-out infinite; }

@media (max-width: 560px) {
  .sec-note { margin-inline-start: 0; flex-basis: 100%; }
}

/* Phones: the two aurora blobs are 46vmax and 38vmax textures under a 60px
   blur, drifting — by far the most expensive paint on the page, and on a
   phone GPU they alone can hold the first scroll under 60fps. Replaced by a
   static wash across the hero that reads the same at a glance. */
/* Phones: one drifting light instead of two. The layer is a single gradient
   fill moved by `transform` alone, which the compositor owns outright — the
   page feels alive from the first frame and the main thread never hears
   about it. The second blob and the 60px blur that used to sit under both
   are still gone; that was the expensive part, not the movement. */
@media (max-width: 760px) {
  .aurora { display: block; opacity: .38; }
  .aurora i:nth-child(2) { display: none; }
  .aurora i:nth-child(1) {
    width: 76vw; height: 76vw;
    inset-block-start: -22vw; inset-inline-start: -16vw;
    animation-duration: 34s;
  }
  .hero {
    background:
      radial-gradient(60% 70% at 6% 0%, color-mix(in srgb, var(--n-cyan) 22%, transparent), transparent 70%),
      radial-gradient(52% 60% at 100% 4%, color-mix(in srgb, var(--n-magenta) 18%, transparent), transparent 70%);
  }
  .gcard .thumb span { animation: none; }
  .feat-item .ico { animation: none; }
}

@media (prefers-reduced-motion: reduce) {
  .aurora i, .ticker-track, .btn-neon::after,
  .gcard .thumb span, .gcard:hover::before, .feat-item .ico,
  .brand-mark, .hero .kicker i { animation: none; }
  .gcard, .gcard .thumb span, .gcard .thumb::after, .feat-item { transition: none; }
  .gcard { opacity: 1 !important; translate: none !important; }
  .gcard:hover .thumb span { scale: 1; rotate: 0deg; }
  @view-transition { navigation: none; }
}


/* ═══════════════════════════════════════════════════════════════════════
   Grid density — the 2026 expansion.

   With twenty-three games on the page, auto-fill was landing on three or
   five cards a row depending on the viewport, and a five-card row made the
   artwork too small to read. The track count is now explicit at each
   breakpoint: four across on desktop, three on a landscape tablet, two on a
   portrait tablet or large phone, one on a small phone. minmax(0, 1fr) — not
   1fr — so a long game title can never push a track past its share.
   ═══════════════════════════════════════════════════════════════════════ */
.grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 1000px) { .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 700px) and (max-width: 999.98px) { .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* the featured row stays two-up: those cards carry a paragraph each */
.grid.duo { grid-template-columns: repeat(auto-fit, minmax(min(100%, 330px), 1fr)); }
@media (min-width: 1000px) { .grid.duo { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* Four across at 1160px gives each card ~279px, so the card interior is
   tightened to match: smaller art well, tighter heading, and a blurb clamped
   to four lines so an uneven row of cards still lines its buttons up. */
@media (min-width: 700px) {
  .gcard .thumb { font-size: clamp(40px, 4.4vw, 58px); }
  .gcard .body { padding: var(--space-4) var(--space-4) var(--space-4); gap: var(--space-2); }
  .gcard h3 { font-size: 16px; letter-spacing: -0.015em; }
  /* The blurb is capped at four lines so an uneven row still lines its Play
     buttons up. NOT -webkit-line-clamp: .gcard .body is a flex container, and
     a flex item's display is blockified — "-webkit-box" computes to
     "flow-root" there and the clamp silently does nothing. A max-height in em
     is the same four lines and it survives blockification. */
  .gcard p {
    font-size: 13.5px; line-height: 1.5;
    max-height: 6em;           /* 4 lines x 1.5 */
    overflow: hidden;
  }
  .gcard p.meta { max-height: 3em; font-size: 12px; }
  .grid.duo .gcard.feat p { max-height: 7.5em; font-size: 14.5px; }
}
/* phones read the full blurb — there is room for it in a single column */
@media (max-width: 470px) {
  .gcard p, .gcard p.meta { max-height: none; overflow: visible; }
}

/* ══════════════════════════════════════════════════════════════════════
   Phones: four games to a row.

   A phone card is a TILE, not a miniature of the desktop card: art, title,
   and a play mark. The blurb, the meta line and the flag badge are dropped
   — at 77px wide they were unreadable before they were informative, and
   dropping them is what lets four fit a 360px viewport without the page
   ever widening. The whole card is the link, so the tap target is the tile
   itself and stays far above 44px however small the play mark is drawn.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 699.98px) {
  .grid, .grid.duo {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: clamp(6px, 1.8vw, 10px);
  }
  .gcard, .gcard.feat, .grid.duo .gcard.feat { flex-direction: column; }
  .gcard .thumb,
  .gcard.feat .thumb,
  .grid.duo .gcard.feat .thumb {
    aspect-ratio: 1 / 1;
    min-height: 0;
    flex: none;
    font-size: clamp(21px, 7vw, 36px);
  }
  .gcard .body,
  .gcard.feat .body,
  .grid.duo .gcard.feat .body {
    padding: 6px 5px 8px;
    gap: 3px;
    align-items: center;
    justify-content: flex-start;
  }
  .gcard h3,
  .gcard.feat h3,
  .grid.duo .gcard.feat h3 {
    font-size: clamp(10px, 2.9vw, 12.5px);
    line-height: 1.24;
    letter-spacing: -0.005em;
    text-align: center;
    text-wrap: balance;
    max-height: 3.72em;            /* three lines */
    overflow: hidden;
  }
  .gcard p,
  .gcard .meta,
  .gcard .flag-tag,
  .grid.duo .gcard.feat p { display: none; }
  .gcard .go,
  .gcard.feat .go,
  .grid.duo .gcard.feat .go {
    width: 36px; min-height: 36px; padding: 0;
    margin-block-start: auto;
    align-self: center;
    font-size: 0; gap: 0;
  }
  .gcard .go i { font-size: 17px; }
  .gcard .go svg { width: 17px; height: 17px; }
  /* A banner card spans every track by default. On a phone that is a card
     the width of the screen sitting in a four-up row — the shape the
     translated homepages were showing. In the tile layout there are no
     banner cards at all, so the span is dropped outright. */
  .gcard.feat, .grid .gcard.feat, .grid.duo .gcard.feat { grid-column: auto; }
}

/* ── standalone content pages: terms, faq, contact ───────────────────────
   Three pages of prose sharing the arcade's chrome. One measure, generous
   leading, and no card around it — a page of terms is read top to bottom,
   not scanned. */
.page-stamp {
  font-size: 12px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
  color: color-mix(in srgb, var(--color-text) 55%, transparent);
  margin-block-start: var(--space-4);
}
.prose { max-width: 74ch; display: grid; gap: var(--space-6); }
.prose > section { display: grid; gap: var(--space-2); }
.prose h3 { margin: 0; font-size: 17px; font-weight: 700; letter-spacing: -0.01em; color: var(--neon); }
.prose p {
  margin: 0; font-size: 15px; font-weight: 400; line-height: 1.7; text-wrap: pretty;
  color: color-mix(in srgb, var(--color-text) 84%, transparent);
}
.prose p.prose-lead {
  font-size: 17px; font-weight: 600; line-height: 1.55;
  color: color-mix(in srgb, var(--color-text) 96%, transparent);
  margin-block-end: var(--space-2);
}
.link-row { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-block-start: var(--space-6); }
.link-card {
  display: inline-flex; align-items: center; gap: var(--space-2);
  /* the pill is sized by its label, never squeezed by its neighbours: a
     shrunk flex item kept its border where the row wanted it and let the
     text run straight out through the curve */
  flex: 0 0 auto; max-width: 100%; white-space: nowrap;
  min-height: 52px; padding-block: var(--space-3); padding-inline: calc(var(--space-8) * 1.3);
  border-radius: 999px;
  font-size: 14px; font-weight: 700; line-height: 1.4; text-decoration: none; color: var(--neon);
  border: 1px solid color-mix(in srgb, var(--neon) 55%, transparent);
  background: color-mix(in srgb, var(--neon) 9%, transparent);
  box-shadow: 0 0 20px -10px var(--neon), inset 0 0 18px -14px var(--neon);
  transition: background .18s ease, box-shadow .18s ease;
}
/* a narrow phone gets one pill per line, wrapping inside its own shape */
@media (max-width: 620px) {
  .link-card {
    flex: 1 1 100%; justify-content: flex-start;
    white-space: normal; border-radius: var(--radius-lg); overflow-wrap: anywhere;
  }
}
.link-card:hover { background: color-mix(in srgb, var(--neon) 18%, transparent); box-shadow: 0 0 24px -6px var(--neon); }
.link-card:focus-visible { outline: 2px solid var(--neon); outline-offset: 2px; }
.link-card .ico { font-size: 17px; line-height: 0; }
@media (prefers-reduced-motion: reduce) { .link-card { transition: none; } }

/* Follow us on social media — sits directly under the Reach Out links */
.social-block { margin-block-start: var(--space-8, 32px); display: grid; gap: var(--space-3); }
.social-h { margin: 0; font-size: 15px; font-weight: 500; color: var(--color-text); }
.social-row { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.social-link {
  --tint: var(--neon);
  display: inline-flex; align-items: center; gap: var(--space-3);
  padding: 8px 16px 8px 8px; border-radius: 999px; text-decoration: none;
  color: var(--color-text);
  border: 1px solid color-mix(in srgb, var(--tint) 45%, transparent);
  background: color-mix(in srgb, var(--tint) 6%, transparent);
  transition: background .15s ease, box-shadow .15s ease, transform .15s ease;
}
.social-instagram { --tint: var(--n-magenta, #ff2bd6); }
.social-facebook { --tint: var(--n-cyan, #00e9ff); }
.social-linkedin { --tint: var(--n-cyan, #00e9ff); }
.social-ico {
  display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%;
  color: var(--tint); line-height: 0;
  background: color-mix(in srgb, var(--tint) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--tint) 50%, transparent);
}
.social-ico svg { width: 20px; height: 20px; display: block; }
.social-txt { display: grid; line-height: 1.25; }
.social-net { font-weight: 600; font-size: 14px; }
.social-handle { font-size: 12.5px; color: color-mix(in srgb, var(--color-text) 70%, transparent); }
.social-link:hover { background: color-mix(in srgb, var(--tint) 16%, transparent); box-shadow: 0 0 22px -8px var(--tint); transform: translateY(-1px); }
.social-link:active { transform: translateY(0); }
.social-link:focus-visible { outline: 2px solid var(--tint); outline-offset: 2px; }
@media (max-width: 620px) { .social-link { flex: 1 1 100%; } }
@media (prefers-reduced-motion: reduce) { .social-link { transition: none; } }

/* The Fluffy Shepherd 2 flock is a black sheep with a golden-brown face,
   ears and horns — drawn rather than tinted, because no filter can recolour
   one part of an emoji. It rides the same float animation as every other
   thumbnail glyph, so nothing else in the grid has to know. */
.gcard .thumb span.ink-sheep { display: block; line-height: 0; filter: none; }
.gcard .thumb span.ink-sheep svg { display: block; width: 1.2em; height: 1.2em; }

/* ── footer columns ──────────────────────────────────────────────────────
   On phones and tablets the three columns sit side by side rather than
   stacking: the footer is reference material, and three short columns are
   one glance where three stacked ones are a scroll. min-width: 0 on the
   tracks so a long translated label wraps inside its column instead of
   widening it. */
.foot-about a { overflow-wrap: anywhere; }
@media (max-width: 1080px) {
  .foot-grid {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--space-5) var(--space-4);
  }
  .foot-grid > * { flex: 1 1 0; min-width: 0; }
  .foot-grid ul { gap: 2px; }
  .foot-grid a {
    font-size: 13px; min-height: 40px; line-height: 1.3;
    display: flex; align-items: center; overflow-wrap: anywhere;
  }
}
@media (max-width: 480px) {
  .foot-grid { gap: var(--space-4) var(--space-3); }
  .foot-grid h2 { font-size: 10.5px; letter-spacing: 0.06em; }
  .foot-grid a { font-size: 12px; min-height: 38px; }
}

/* ── the orientation prompt ─────────────────────────────────────────────
   Every game names the orientation it is played in on its shell
   (data-orient="landscape" | "portrait"; the control panel can change it or
   allow any). ca-tools.js drops a .ca-orient card over the game frame, and
   these queries decide when it shows: a touch phone or tablet held the other
   way round — never a desktop window. It covers the frame only, so the page
   around it stays readable, and it cannot be dismissed: the game starts when
   the device turns. In full screen ca-tools.js also asks the browser to lock
   the orientation where it can (Android). */
.ca-orient { display: none; }
@media (orientation: portrait) and (max-width: 1100px) and (pointer: coarse) {
  [data-orient="landscape"] .ca-orient { display: grid; }
}
@media (orientation: landscape) and (max-height: 600px) and (pointer: coarse) {
  [data-orient="portrait"] .ca-orient { display: grid; }
}
.ca-orient {
  position: absolute; inset: 0; z-index: 30;
  place-items: center; padding: 16px; text-align: center;
  background: rgba(12,8,24,.94);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.ca-orient-in { display: flex; flex-direction: column; align-items: center; gap: 10px; max-width: 28ch; }
.ca-orient-ico {
  width: 44px; height: 70px; border-radius: 10px;
  border: 3px solid #00e9ff;
  box-shadow: 0 0 30px -8px #00e9ff, inset 0 0 18px -12px #00e9ff;
  animation: ca-orient-land 2.6s ease-in-out infinite;
}
.ca-orient-ico.is-portrait { animation-name: ca-orient-port; }
.ca-orient strong {
  font-size: 19px; font-weight: 800; line-height: 1.2; color: #f0f4f8;
  text-shadow: 0 0 18px rgba(0,233,255,.5);
}
.ca-orient p { margin: 0; font-size: 14px; font-weight: 500; line-height: 1.45; color: rgba(240,244,248,.84); }
.ca-orient small { font-size: 12.5px; font-weight: 500; line-height: 1.4; color: rgba(240,244,248,.6); }
@keyframes ca-orient-land { 0%, 22% { transform: rotate(0deg); } 55%, 86% { transform: rotate(-90deg); } 100% { transform: rotate(0deg); } }
@keyframes ca-orient-port { 0%, 22% { transform: rotate(-90deg); } 55%, 86% { transform: rotate(0deg); } 100% { transform: rotate(-90deg); } }
@media (prefers-reduced-motion: reduce) {
  .ca-orient-ico { animation: none; transform: rotate(-90deg); }
  .ca-orient-ico.is-portrait { transform: none; }
}

/* board-game thumbnails: drawn, not emoji (v3.23.0) */
/* the art's span fills the well and centres it, so the SVG's percentage width
   resolves against the card (not a shrink-to-fit span) on every screen size */
.gcard .thumb span:has(> .bgt) { width: 100%; height: 100%; display: grid; place-items: center; }
.gcard .thumb .bgt { display: block; width: min(70%, 210px); max-height: 84%; height: auto; margin: auto; overflow: visible; filter: drop-shadow(0 10px 14px rgba(0, 0, 0, .28)); }
@media (max-width: 699.98px) { .gcard .thumb .bgt { width: 86%; } }
:root[data-theme="day"] .gcard .thumb .bgt { filter: drop-shadow(0 10px 12px rgba(58, 46, 30, .22)); }
/* v4.2.0: the art is a file pair from Brand/Game Assets/<game>/ — the Night file by night, the Day file by day */
.gcard .thumb img.bgt { aspect-ratio: 160 / 110; object-fit: contain; }
:root[data-theme="day"] .gcard .thumb .bgt-night, :root:not([data-theme="day"]) .gcard .thumb .bgt-day { display: none; }

/* desktop bar: its final height (the theme switch and timer are 44px tall)
   is reserved before the scripts that add them run (v3.25.0) */
@media (min-width: 861px) { .site-head .nav { min-height: 61px; } }

/* the card art is drawn only when it is near the screen (v3.25.0). The well
   keeps its own shape (aspect-ratio against the card's width) while it is
   skipped, so nothing ever moves: this is not the section-level deferral the
   note above warns about. It removes most of the homepage's style, layout
   and paint work on a phone, and the float animations of off-screen art. */
.gcard .thumb { content-visibility: auto; contain-intrinsic-size: auto 160px; }

/* phones and portrait tablets: the card art breathes (v3.26.0). A gentle
   rise and swell, moved by `transform` alone so the compositor runs it with
   no layout or paint; off-screen art is skipped (content-visibility above),
   and the stagger keeps a row from pulsing in step. Never with reduced
   motion. */
@keyframes ca-breathe { 0%, 100% { transform: translateY(0) scale(1); } 50% { transform: translateY(-3px) scale(1.035); } }
@media (prefers-reduced-motion: no-preference) and (max-width: 760px), (prefers-reduced-motion: no-preference) and (orientation: portrait) and (max-width: 1100px) {
  .gcard .thumb span { animation: ca-breathe 5.2s ease-in-out infinite; }
  .grid .gcard:nth-child(4n+2) .thumb span { animation-delay: -1.3s; }
  .grid .gcard:nth-child(4n+3) .thumb span { animation-delay: -2.6s; }
  .grid .gcard:nth-child(4n+4) .thumb span { animation-delay: -3.9s; }
}
