@font-face { font-family:"Grotesk"; src:url("/fonts/SpaceGrotesk_700Bold.woff2") format("woff2");
             font-weight:700; font-display:swap }
@font-face { font-family:"Manrope"; src:url("/fonts/Manrope_400Regular.woff2") format("woff2");
             font-weight:400; font-display:swap }
@font-face { font-family:"Manrope"; src:url("/fonts/Manrope_600SemiBold.woff2") format("woff2");
             font-weight:600; font-display:swap }
@font-face { font-family:"Manrope"; src:url("/fonts/Manrope_800ExtraBold.woff2") format("woff2");
             font-weight:800; font-display:swap }

/* ── THEME ────────────────────────────────────────────────────────────────────────────────
   The site follows the browser: black-based in dark, white-based in light. Two rules make that
   work without the whole design collapsing into "the dark one with the colours inverted":

   1. THE SCRIM NEVER FLIPS. The hero, the two product tiles and the pot claim are photographs
      and coloured fields with type ON them. Those grounds stay dark in both themes — exactly as
      Apple's black product tiles stay black on a light macOS — because a photograph does not
      become legible by being asked to be white. --scrim is that always-dark ground; --stage
      is the alternating section ground, and it is the one that flips.
   2. THE BRAND DOES NOT FLIP. #00C853 and the gold are the app's own tokens and are fixed. Only
      the gold's TEXT form is darkened in light mode, where F5C518 on white fails contrast.

   The runtime's feel engine (site.js) writes --bg/--card/--line/--ink-soft as it dims toward
   20:00. It now checks the theme first and leaves a light page alone, so a visitor in light mode
   does not watch their page turn dark green at 19:30. */
:root{
  --brand:#00C853; --glow:#22E58B; --gold:#F5C518;
  --mark-ink:#07120C;
  --dim:0; --nav-h:4.5rem;

  /* The always-dark ground: photographic scrims and the pot claim. Fixed, never themed. */
  --scrim:#080D0B;
  --scrim-ink:#FFFFFF;
  --scrim-ink-soft:#9DB0A5;
  --scrim-line:rgba(255,255,255,.16);

  /* Radius scales with the size of the box (Apple 5/8/10/12, PlayStation 4/13/24/32).
     One radius everywhere is the template tell — in a real system radius carries scale. */
  --r-tag:4px; --r-sm:8px; --r-card:14px; --r-tile:24px; --r-slab:34px; --r-pill:999px;
  --display:"Grotesk", "Space Grotesk", ui-monospace, monospace; --ui:"Manrope", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --pad:clamp(1.125rem,4vw,2rem);
  --gut:min(100% - 2.5rem, 78rem);
  --gut-wide:min(100% - 2.5rem, 90rem);

  /* ── LIGHT is the default declaration, so every value has a definition outside a media
        query. Paper rather than pure white: #FFF against a white browser chrome has no edge,
        and the card then has nowhere lighter to go. ─────────────────────────────────────── */
  --bg:#FFFFFF;
  --card:#F4F7F5;
  --ink:#08110C;
  --ink-soft:#55635C;
  --line:#E2E8E4;
  --stage:#F0F4F1;           /* the alternating ground — a shade of paper, not of ink */
  --raise:#FFFFFF;
  --hair:#DCE4DF;
  --gold-text:#8A6D00;       /* F5C518 on white is 1.7:1. This is the same hue at 5.2:1. */
  --brand-text:#00893A;      /* likewise: the brand green, darkened only where it is TYPE */
  --shadow:0 1px 2px rgba(8,17,12,.06),0 12px 32px rgba(8,17,12,.08);
  --shadow-lg:0 24px 60px rgba(8,17,12,.14);
  color-scheme:light;
}

@media (prefers-color-scheme:dark){
  :root{
    --bg:#101915;
    --card:#18211D;
    --ink:#FFFFFF;
    --ink-soft:#9DB0A5;
    --line:#26312C;
    --stage:#080D0B;
    --raise:#18211D;
    --hair:#1E2723;
    --gold-text:var(--gold);
    --brand-text:var(--brand);
    --shadow:0 2px 8px rgba(0,0,0,.4);
    --shadow-lg:0 24px 60px rgba(0,0,0,.5);
    color-scheme:dark;
  }
}
*,*::before,*::after{box-sizing:border-box;margin:0}
[hidden]{display:none!important}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{background:var(--bg);color:var(--ink);font-family:var(--ui);font-weight:400;line-height:1.6;
     -webkit-font-smoothing:antialiased;overflow-x:hidden}
body,.card,.btn,.stat,.faq details,.docwrap{transition:background-color 1.2s linear,color 1.2s linear,border-color 1.2s linear}
a{color:inherit;text-decoration:none}
img{display:block;max-width:100%}
:focus-visible{outline:2px solid var(--brand);outline-offset:3px;border-radius:4px}
.wrap{width:var(--gut);margin-inline:auto}
.wrap.wide{width:var(--gut-wide)}
section{padding:clamp(4.5rem,10vw,9rem) 0;position:relative}
section.tight{padding:clamp(2.75rem,5vw,4rem) 0}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ── Grounds ──────────────────────────────────────────────────────────────────────────────
   Apple alternates a section of white against a section of black and the rhythm is half the
   design. §5 gives us two colourways rather than a white one, so the alternation is won at the
   dark end: a near-black stage against the lit ground. The gap between them is now 10 points of
   luminance rather than 4, which is the difference between a rhythm and a rounding error. */
.on-stage{background:var(--stage)}
.on-stage>.wrap,.on-stage .wrap{--line:var(--hair)}
.hairline{border-top:1px solid var(--hair)}

/* ── THE SCRIM CONTRACT ───────────────────────────────────────────────────────────────────
   Three kinds of section carry type over a photograph or a coloured field: the hero, the two
   product tiles, and the pot claim. They stay dark in BOTH themes — asking a night photograph of
   Lagos to become white does not make it legible, it makes it grey. Apple's black product tiles
   stay black on a light Mac for the same reason.

   Redefining --stage locally to --scrim is what lets every gradient inside these sections stay
   written in terms of --stage: the scrim overrides the ground, and the components below need no
   theme-awareness of their own. */
.hero,.tile,.claim:not(.brand){
  background:var(--scrim);
  --stage:var(--scrim);
  --ink:var(--scrim-ink);
  --ink-soft:var(--scrim-ink-soft);
  --line:var(--scrim-line);
  --hair:var(--scrim-line);
  --brand-text:var(--brand);
  --gold-text:var(--gold);
  color:var(--scrim-ink)
}

/* ── Type ─────────────────────────────────────────────────────────────────────────────────
   Tracking, leading and weight follow Apple's production scale, measured off
   /v/homepage/a/styles/main.built.css (see DESIGN-SPEC.md §1):

       56px  lh 1.071  tracking -.005em      40px  lh 1.10   tracking  0em
       48px  lh 1.083  tracking -.002em      32px  lh 1.125  tracking +.002em

   Two rules that a single flat value cannot express: large type is TIGHTENED because its
   counters read loose, small type is OPENED because its do not; and leading tightens as size
   grows. Space Grotesk sets wider than SF Pro, so the curve is shifted a little tighter overall
   — but it is a curve, not a constant. The whole curve is now shifted UP: the reference sites
   set their hero at 80–110px and we were setting ours at 56. */
.eyebrow{font-size:.75rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;color:var(--brand-text)}
.eyebrow.gold{color:var(--gold-text)}
.eyebrow.plain{color:var(--ink-soft)}
h1{font-family:var(--display);font-weight:700;
   font-size:clamp(2.35rem,6.4vw,4.25rem);line-height:1.06;letter-spacing:-.026em;margin-top:1rem}
h2{font-family:var(--display);font-weight:700;
   font-size:clamp(1.95rem,4.6vw,3.25rem);line-height:1.08;letter-spacing:-.02em;margin-top:.85rem}
h3{font-family:var(--display);font-weight:700;font-size:clamp(1.375rem,2vw,1.6rem);line-height:1.16;letter-spacing:-.008em}
h4{font-size:1.0625rem;font-weight:700;line-height:1.3;letter-spacing:0}
/* The hero. Apple's homepage sets "iPhone Duo" at 96px on a 1440 viewport; Cloudflare's claim
   runs past 100. This is the one size that is allowed to dominate a viewport. */
.mega{font-family:var(--display);font-weight:700;
      font-size:clamp(2.6rem,8.2vw,6rem);line-height:1.01;letter-spacing:-.035em}
.display{font-family:var(--display);font-weight:700;
   font-size:clamp(2.5rem,8vw,4.5rem);line-height:1.05;letter-spacing:-.03em}
.green{color:var(--brand-text)}
.goldtext{color:var(--gold-text)}
p{color:var(--ink-soft)}
.lede{margin-top:1.35rem;max-width:58ch;font-size:clamp(1.0625rem,1.5vw,1.25rem);line-height:1.5}
.lede.big{font-size:clamp(1.15rem,1.9vw,1.5rem);line-height:1.45;max-width:34ch;color:var(--ink)}
strong{color:var(--ink);font-weight:700}
em{font-style:italic}
.prose p+p,.prose ul,.prose ol{margin-top:1rem}
.prose h2{margin-top:2.6rem}
.prose h3{margin-top:1.8rem}
.prose ul,.prose ol{color:var(--ink-soft);padding-left:1.2rem}
.prose li{margin-top:.45rem}
.prose a{color:var(--brand-text);text-decoration:underline;text-underline-offset:3px}
.num{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}

/* ── The bar ──────────────────────────────────────────────────────────────────────────────── */
/* Transparent while it is over the hero, painted once it leaves it. A translucent bar sitting
   on a full-bleed photograph from the first pixel is the tell of a template; Apple, NVIDIA and
   Cloudflare all let the hero run under a bar that has not committed to a background yet.
   .bar-over carries the scrim's ink so the links are legible on the photograph, and gives it
   up the moment the bar sticks to a themed ground. */
.bar{position:sticky;top:0;z-index:60;height:var(--nav-h);display:flex;align-items:center;
     background:transparent;border-bottom:1px solid transparent;
     transition:background-color .25s ease,border-color .25s ease,backdrop-filter .25s ease}
.bar:not(.bar-over),.bar.stuck{
     background:color-mix(in srgb,var(--bg) 82%,transparent);
     backdrop-filter:blur(18px) saturate(140%);-webkit-backdrop-filter:blur(18px) saturate(140%)}
.bar.stuck{border-bottom-color:var(--line)}
.bar-over:not(.stuck){
  --ink:var(--scrim-ink);--ink-soft:var(--scrim-ink-soft);--line:var(--scrim-line);--hair:var(--scrim-line);
  color:var(--scrim-ink)}
.bar .wrap{display:flex;align-items:center;gap:1.25rem;width:var(--gut-wide)}
.bar .wordmark{width:5.6rem;height:auto;flex:none}
.bar nav{display:flex;gap:.15rem;margin-right:auto;font-size:.92rem;font-weight:600}
.bar nav>a,.bar .drop>button{color:var(--ink-soft);background:none;border:0;cursor:pointer;
     font:inherit;padding:.5rem .8rem;border-radius:999px;display:inline-flex;align-items:center;gap:.35rem}
.bar nav>a:hover,.bar .drop>button:hover{color:var(--ink);background:color-mix(in srgb,var(--ink) 8%,transparent)}
.bar nav>a[aria-current="page"]{color:var(--brand-text)}
.bar .drop{position:relative}
.bar .drop>button::after{content:"";width:.4rem;height:.4rem;border-right:2px solid currentColor;
     border-bottom:2px solid currentColor;transform:rotate(45deg) translateY(-1px);opacity:.7}
.menu{position:absolute;top:calc(100% + .6rem);left:0;min-width:21rem;padding:.6rem;
      background:var(--raise);border:1px solid var(--line);border-radius:var(--r-tile);
      box-shadow:var(--shadow-lg);
      display:grid;gap:.2rem;opacity:0;visibility:hidden;transform:translateY(-6px);
      transition:opacity .16s ease,transform .16s ease,visibility .16s}
.drop[data-open="true"] .menu{opacity:1;visibility:visible;transform:none}
.menu a{display:grid;gap:.15rem;padding:.7rem .8rem;border-radius:12px}
.menu a:hover{background:color-mix(in srgb,var(--ink) 6%,transparent)}
.menu b{font-size:.95rem;font-weight:800;color:var(--ink)}
.menu span{font-size:.82rem;color:var(--ink-soft);font-weight:400;line-height:1.45}
.bar .cta{flex:none}
.burger{display:none;flex:none;width:2.6rem;height:2.6rem;border-radius:999px;background:none;
        border:1px solid var(--line);color:var(--ink);cursor:pointer;align-items:center;justify-content:center}
.burger span{display:block;width:1rem;height:2px;background:currentColor;position:relative}
.burger span::before,.burger span::after{content:"";position:absolute;left:0;width:1rem;height:2px;background:currentColor}
.burger span::before{top:-5px} .burger span::after{top:5px}
@media (max-width:1068px){
  .bar nav{display:none}
  .burger{display:inline-flex}
  .bar .cta{margin-left:auto}
}
/* The drawer. A real menu, not a jump-link list. */
.drawer{position:fixed;inset:var(--nav-h) 0 0;z-index:55;background:var(--bg);
        padding:1.5rem var(--pad) 3rem;overflow-y:auto;display:none}
.drawer.open{display:block}
.drawer h5{font-size:.72rem;font-weight:800;letter-spacing:.16em;text-transform:uppercase;
           color:var(--brand-text);margin-top:1.6rem}
.drawer h5:first-child{margin-top:0}
.drawer a{display:block;padding:.75rem 0;font-size:1.1rem;font-weight:700;border-bottom:1px solid var(--line)}
.drawer a span{display:block;font-size:.85rem;font-weight:400;color:var(--ink-soft);margin-top:.15rem}

/* ── Buttons ──────────────────────────────────────────────────────────────────────────────── */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.55rem;min-height:3.25rem;
     padding:.9rem 1.7rem;border-radius:var(--r-pill);font-weight:700;font-size:1rem;
     border:1px solid transparent;cursor:pointer;font-family:var(--ui);
     transition:background-color .16s ease,border-color .16s ease,color .16s ease,transform .16s ease}
.btn svg{width:1.15rem;height:1.15rem;flex:none}
.btn-primary{background:var(--brand);color:var(--mark-ink)}
.btn-primary:hover{background:var(--glow)}
.btn-ghost{background:color-mix(in srgb,var(--ink) 5%,transparent);
  border-color:color-mix(in srgb,var(--ink) 20%,transparent);color:var(--ink)}
.btn-ghost:hover{border-color:var(--ink);background:color-mix(in srgb,var(--ink) 10%,transparent)}
/* Used inside scrims only, where --ink is always white. */
.btn-light{background:var(--scrim-ink);color:var(--mark-ink)}
.btn-light:hover{background:#E8F5EC}
.btn-sm{min-height:2.5rem;padding:.45rem 1.15rem;font-size:.88rem}
.btn-link{padding:0;min-height:0;background:none;color:var(--brand-text);border:0}
.btn-link:hover{color:var(--brand)}
.btn-link::after{content:"\2192";transition:transform .16s ease}
.btn-link:hover::after{transform:translateX(3px)}
.btn-link.ink{color:var(--ink)}
.stores{display:flex;flex-wrap:wrap;gap:.75rem;margin-top:2rem}
@media (max-width:390px){.stores .btn{flex:1 1 100%}}

/* ── THE HERO ─────────────────────────────────────────────────────────────────────────────
   Centred, full-bleed, and the photograph is at full strength rather than washed to 30%.
   Apple and Cloudflare both centre; NVIDIA runs type left with the image right. Centred wins
   here because the hero photograph is a city rather than a product — there is no subject to
   sit beside, so the type belongs on top of it.

   The scrim is a two-stop vertical plus a floor, which is what keeps 60px type legible over a
   lit skyline without turning the skyline into mud. */
.hero{position:relative;overflow:hidden;isolation:isolate;
      min-height:min(94svh,52rem);display:flex;align-items:center;
      padding:calc(var(--nav-h) + 3rem) 0 clamp(3rem,7vw,5rem);margin-top:calc(var(--nav-h) * -1)}
.hero-img{position:absolute;inset:0;z-index:-2}
.hero-img img{width:100%;height:100%;object-fit:cover;object-position:50% 42%;
  filter:brightness(.78) contrast(1.16) saturate(1.12)}
.hero-img::after{content:"";position:absolute;inset:0;background:
  linear-gradient(to bottom,color-mix(in srgb,var(--stage) 88%,transparent) 0%,
                            color-mix(in srgb,var(--stage) 42%,transparent) 34%,
                            color-mix(in srgb,var(--stage) 62%,transparent) 68%,
                            var(--stage) 100%),
  radial-gradient(72% 60% at 50% 46%,transparent 30%,color-mix(in srgb,var(--stage) 72%,transparent) 100%)}
.hero .wrap{position:relative;z-index:1;text-align:center;display:flex;flex-direction:column;align-items:center}
.hero .lede{max-width:46ch;margin-inline:auto;color:color-mix(in srgb,var(--ink) 82%,transparent)}
.hero .stores{justify-content:center}
.hero .mega{margin-top:1.5rem;text-shadow:0 2px 40px rgba(0,0,0,.5)}

/* The pill above the headline — Cloudflare puts its conference line in exactly this position,
   a hairline capsule that gives the headline something to sit under. Ours carries the live
   countdown, which is the one thing on the page that is different every second. */
.herotag{display:inline-flex;align-items:center;gap:.7rem;padding:.55rem 1.1rem .55rem .9rem;
  border:1px solid color-mix(in srgb,var(--ink) 24%,transparent);border-radius:var(--r-pill);
  background:color-mix(in srgb,var(--stage) 55%,transparent);backdrop-filter:blur(8px);
  font-size:.85rem;font-weight:600;color:color-mix(in srgb,var(--ink) 88%,transparent)}
.herotag b{font-family:var(--display);font-variant-numeric:tabular-nums;letter-spacing:.01em}
.herotag .dot{width:.45rem;height:.45rem;border-radius:999px;background:var(--brand);flex:none;
  box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 22%,transparent)}
@media (prefers-reduced-motion:no-preference){
  .herotag .dot{animation:pulse 2.4s ease-in-out infinite}
}

/* The hero glow, kept for interior page heads. The glow bleeds 10% past its box on each side by
   design. Without a clip that bleed becomes real page width — every page but home was 10% wider
   than the viewport until this was added. */
.hero-glow{position:relative;overflow:hidden}
.hero-glow::before{content:"";position:absolute;inset:-30% -10% auto;height:40rem;z-index:0;
  background:radial-gradient(50% 50% at 50% 0%,rgba(0,200,83,calc(.05 + .12*var(--dim))),transparent 70%);
  pointer-events:none}

/* ── Live figures ─────────────────────────────────────────────────────────────────────────── */
.figures{display:flex;flex-wrap:wrap;justify-content:center;gap:clamp(1.5rem,5vw,4rem);margin-top:3rem;
         padding-top:2rem;border-top:1px solid color-mix(in srgb,var(--ink) 14%,transparent);width:100%}
.figure b{display:block;font-family:var(--display);font-weight:700;line-height:1;
          font-size:clamp(1.6rem,4vw,2.35rem);letter-spacing:-.025em;font-variant-numeric:tabular-nums}
.figure span{display:block;margin-top:.6rem;font-size:.7rem;font-weight:800;letter-spacing:.14em;
             text-transform:uppercase;color:var(--ink-soft)}
.figure.is-gold b{color:var(--gold)}

/* ── THE CLAIM ────────────────────────────────────────────────────────────────────────────
   Cloudflare's move, and the one this site most needed. Their homepage opens with a single
   enormous sentence on a fully saturated brand field, and later closes on another. Nothing on
   the page competes with it — that is what makes it read as a claim rather than a heading.

   Arena has exactly one fact that earns this treatment, and it is true and checkable: the pot
   has been sitting there unclaimed since the day it was created. The number is read live from
   /slip/pot, so the day somebody wins it, this panel stops saying nobody has. */
.claim{position:relative;overflow:hidden;text-align:center;
       padding:clamp(5rem,12vw,9rem) 0;background:var(--stage)}
.claim::before{content:"";position:absolute;inset:-20% -10% auto;height:130%;pointer-events:none;
  background:radial-gradient(52% 52% at 50% 40%,color-mix(in srgb,var(--gold) 26%,transparent),transparent 70%),
             radial-gradient(78% 70% at 50% 40%,color-mix(in srgb,var(--gold) 10%,transparent),transparent 78%)}
.claim .wrap{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center}
.claim-num{display:block;font-family:var(--display);font-weight:700;color:var(--gold);
  --gold-text:var(--gold);
  font-size:clamp(3.75rem,15vw,10.5rem);line-height:.92;letter-spacing:-.045em;margin:1.75rem 0;
  font-variant-numeric:tabular-nums;text-shadow:0 0 90px color-mix(in srgb,var(--gold) 28%,transparent)}
.claim h2{font-size:clamp(1.9rem,5vw,3.5rem);max-width:18ch}
.claim .lede{margin-inline:auto;max-width:52ch}
.claim .stores{justify-content:center}
.potfoot{margin-top:1.5rem;font-size:.95rem;color:var(--ink-soft)}
.claim.brand{background:var(--brand);color:var(--mark-ink)}
.claim.brand::before{background:radial-gradient(60% 70% at 50% 118%,
  color-mix(in srgb,var(--gold) 55%,transparent),transparent 68%)}
.claim.brand h2,.claim.brand .claim-num{color:var(--mark-ink);text-shadow:none}
.claim.brand p,.claim.brand .lede{color:color-mix(in srgb,var(--mark-ink) 76%,transparent)}
.claim.brand .eyebrow{color:color-mix(in srgb,var(--mark-ink) 68%,transparent)}
.claim.brand .mark{color:var(--mark-ink)}

/* ── THE PRODUCT TILE ─────────────────────────────────────────────────────────────────────
   Apple's homepage is a stack of these and nothing else: eyebrow → the product's name, enormous
   → one or two centred lines of tagline → two calls to action, one to read and one to act →
   then the product itself, large, as the bottom two-thirds of the viewport.

   The previous version of this site put both games in a 2-up card grid at 27rem wide, which is
   a catalogue listing. A catalogue is right when you have forty products. With two, each one
   gets a stage. */
.tile{position:relative;overflow:hidden;isolation:isolate;text-align:center;
      background:var(--stage);padding:clamp(4.5rem,10vw,7.5rem) 0 0}
.tile-img{position:absolute;inset:0;z-index:-2}
/* Graded, then scrimmed. A flat 82%-opacity wash over an overcast daytime photograph turns it
   into grey haze — the image stops being a photograph without ever becoming a ground. Crushing
   the blacks and lifting saturation first means the scrim is darkening something with contrast
   left in it, which is the difference between atmosphere and mud.

   .lit is for source photographs that are already night: crushing an underexposed frame by a
   further half stop leaves a black rectangle. The Night's crowd shot needed it. */
.tile-img img{width:100%;height:100%;object-fit:cover;object-position:50% 38%;
  filter:brightness(.5) contrast(1.22) saturate(1.15)}
.tile.lit .tile-img img{filter:brightness(1.05) contrast(1.1) saturate(1.2)}
/* Solid at both ends, open in the middle. The scrim used to start at 62% and end solid, so where
   one tile's solid floor met the next tile's 62% ceiling there was a visible horizontal seam.
   Closing both ends removes the seam AND frames the photograph as a band the headline sits in,
   which is the better composition anyway. */
.tile-img::after{content:"";position:absolute;inset:0;background:
  linear-gradient(to bottom,var(--stage) 0%,
                            color-mix(in srgb,var(--stage) 78%,transparent) 14%,
                            color-mix(in srgb,var(--stage) 66%,transparent) 40%,
                            color-mix(in srgb,var(--stage) 88%,transparent) 72%,
                            var(--stage) 93%),
  radial-gradient(70% 54% at 50% 36%,color-mix(in srgb,var(--stage) 52%,transparent),transparent 78%)}
.tile .wrap{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center}
.tile-name{font-family:var(--display);font-weight:700;margin-top:1.1rem;
  font-size:clamp(2.6rem,7.4vw,5.25rem);line-height:1;letter-spacing:-.038em}
.tile .lede{max-width:44ch;margin-inline:auto;font-size:clamp(1.1rem,1.7vw,1.35rem)}
.tile .ctas{justify-content:center;margin-top:2rem;padding-top:0}
/* The spec row. PlayStation puts price and platform under a product name in exactly this
   register: small, wide-tracked, separated by hairlines. It is the part that makes a product
   feel specified rather than described. */
.tilespecs{display:flex;flex-wrap:wrap;justify-content:center;gap:0;margin-top:2.5rem;width:100%}
.tilespecs div{padding:0 clamp(1rem,3vw,2.25rem);border-left:1px solid color-mix(in srgb,var(--ink) 15%,transparent)}
.tilespecs div:first-child{border-left:0}
.tilespecs dt{font-size:.68rem;font-weight:800;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-soft)}
.tilespecs dd{font-family:var(--display);font-weight:700;font-size:clamp(1rem,1.6vw,1.2rem);
  margin-top:.5rem;letter-spacing:-.01em}
.tilespecs dd.green{color:var(--brand)}
.tilespecs dd.gold{color:var(--gold)}
@media (max-width:734px){
  .tilespecs{gap:1.5rem 0}
  .tilespecs div{flex:1 0 50%;border-left:0;padding:0 .5rem}
}

/* ── THE DEVICE ───────────────────────────────────────────────────────────────────────────
   One screenshot, large, is the product. Five at 150px is a contact sheet.

   The frame is drawn rather than photographed: a hairline bezel, a real shadow, and a floor
   glow so the device is standing on the stage instead of pasted onto it. Apple, NVIDIA and
   PlayStation all light the product from below for exactly this reason. */
.device{position:relative;margin:clamp(3rem,6vw,4.5rem) auto 0;width:min(100%,24rem);z-index:1}
/* The floor glow is inset to the device's OWN box and the radial is widened to compensate,
   rather than the box being bled 40% past each edge. A bleed is only safe where an ancestor
   clips it: inside a .tile the stage clips, but the same component in an ordinary section made
   the document 465px wide at a 390px viewport. Sizing the gradient instead of the box means the
   glow looks the same and cannot overflow anything, anywhere. */
.device::after{content:"";position:absolute;inset:auto 0 -8% 0;height:55%;z-index:-1;
  background:radial-gradient(115% 60% at 50% 100%,color-mix(in srgb,var(--brand) 26%,transparent),transparent 70%);
  pointer-events:none}
.device.gold::after{background:radial-gradient(115% 60% at 50% 100%,color-mix(in srgb,var(--gold) 26%,transparent),transparent 70%)}
.device .screen{border-radius:clamp(1.75rem,3vw,2.5rem);overflow:hidden;background:#000;
  border:1px solid color-mix(in srgb,var(--ink) 16%,transparent);
  box-shadow:0 40px 90px rgba(0,0,0,.6),0 8px 24px rgba(0,0,0,.4);
  aspect-ratio:640/1386;position:relative}
.device .screen img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:50% 0}
/* The device cropped, so a tile can show the product without the tile becoming as tall as a
   phone. A mask does the cropping rather than a shorter box: shortening the box alone chopped
   the screen mid-content and left a bezel with no bottom edge, which reads as a rendering bug
   rather than as a product standing in the frame. The mask fades the last fifth to nothing, so
   the device emerges from the stage the way Apple's and NVIDIA's do. */
.device.crop .screen{aspect-ratio:640/1050;border-bottom:0;
  border-radius:clamp(1.75rem,3vw,2.5rem) clamp(1.75rem,3vw,2.5rem) 0 0;
  -webkit-mask-image:linear-gradient(to bottom,#000 62%,transparent 99%);
          mask-image:linear-gradient(to bottom,#000 62%,transparent 99%);
  box-shadow:0 40px 90px rgba(0,0,0,.5)}

/* A trio of devices, the middle one forward. Used once, on the app section — it is the one
   place where showing more than one screen says something the single screen cannot. */
.devices{display:flex;align-items:flex-end;justify-content:center;gap:clamp(.75rem,2vw,1.75rem);
  margin-top:clamp(3rem,6vw,4.5rem);position:relative}
.devices .device{margin:0;width:min(30%,15rem);flex:none}
.devices .device.lead{width:min(38%,19rem);z-index:2}
.devices .device.lead .screen{box-shadow:0 50px 110px rgba(0,0,0,.7),0 10px 30px rgba(0,0,0,.5)}
.devices .device:not(.lead){opacity:.72}
.devices .device:not(.lead)::after{display:none}
@media (max-width:734px){
  .devices .device:not(.lead){display:none}
  .devices .device.lead{width:min(74%,17rem)}
}

/* ── The screenshot rail — the remaining screens, captioned ───────────────────────────────── */
.phones{display:grid;grid-auto-flow:column;grid-auto-columns:min(46%,11rem);gap:1.25rem;margin-top:2.75rem;
  overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;
  padding-inline:max(1.25rem,calc(50vw - 39rem));margin-inline:calc(50% - 50vw);padding-bottom:.5rem}
.phones::-webkit-scrollbar{display:none}
@media (min-width:1069px){
  .phones{grid-auto-flow:row;grid-template-columns:repeat(5,1fr);grid-auto-columns:auto;
          overflow:visible;width:min(100% - 2.5rem,66rem);margin-inline:auto;padding-inline:0;gap:1.5rem}
}
.phone{scroll-snap-align:start;margin:0}
.phone .screen{border-radius:var(--r-tile);overflow:hidden;border:1px solid var(--line);
               background:#000;box-shadow:var(--shadow);aspect-ratio:9/19.5;position:relative}
.phone .screen img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:50% 0}
.phone figcaption{margin-top:.9rem;font-size:.82rem;color:var(--ink-soft);text-align:center;line-height:1.4}

/* ── Cards & grids ────────────────────────────────────────────────────────────────────────── */
.grid{display:grid;gap:1.25rem;margin-top:2.75rem}
.g2{grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
.g3{grid-template-columns:repeat(auto-fit,minmax(16rem,1fr))}
.g4{grid-template-columns:repeat(auto-fit,minmax(13rem,1fr))}
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--r-tile);padding:1.75rem 1.85rem}
.on-stage .card{background:var(--raise);border-color:var(--line)}
.card .n{font-family:var(--display);font-size:.95rem;color:var(--brand-text);font-weight:700}
.card h4{margin-top:.75rem;font-size:1.125rem}
.card p{margin-top:.6rem;font-size:.95rem}
a.card:hover{border-color:var(--brand)}

/* ── THE PROOF BAND ───────────────────────────────────────────────────────────────────────
   Cloudflare frames their proof numbers inside a ruled grid with the cell borders showing, which
   is what makes four numbers read as a specification rather than four floating claims. Taken
   directly, including the hairline cells. */
.band{background:var(--stage);border-block:1px solid var(--line)}
.alt{background:var(--stage);border-block:1px solid var(--line)}

.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(11rem,1fr));
  border:1px solid var(--line);border-radius:var(--r-tile);overflow:hidden}
.stat{padding:clamp(1.75rem,3.5vw,2.5rem) clamp(1.25rem,2.5vw,2rem);
  border-left:1px solid var(--line);border-top:1px solid var(--line)}
.stat b{display:block;font-family:var(--display);font-weight:700;font-size:clamp(2rem,4.5vw,2.9rem);
        line-height:1;letter-spacing:-.032em;font-variant-numeric:tabular-nums}
.stat span{display:block;margin-top:.75rem;color:var(--ink-soft);font-size:.92rem;line-height:1.45}

/* ── The catalogue rail — still used on /games/ where a side-by-side comparison is the point ── */
.rail-head{display:flex;align-items:flex-end;justify-content:space-between;gap:1rem}
.rail-nav{display:flex;gap:.55rem;flex:none}
.rail-nav button{width:2.75rem;height:2.75rem;border-radius:999px;background:transparent;
  border:1px solid var(--line);color:var(--ink);cursor:pointer;font-size:1rem;display:grid;place-items:center}
.rail-nav button:hover:not(:disabled){border-color:var(--brand);color:var(--brand)}
.rail-nav button:disabled{opacity:.3;cursor:default}
.rail{display:grid;grid-auto-flow:column;grid-auto-columns:min(85%,28rem);gap:1.25rem;margin-top:2.5rem;
      overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;-webkit-overflow-scrolling:touch;
      padding-inline:max(1.25rem,calc(50vw - 39rem));margin-inline:calc(50% - 50vw);padding-bottom:.5rem}
.rail::-webkit-scrollbar{display:none}
@media (min-width:735px){
  .rail{grid-auto-flow:row;grid-template-columns:repeat(2,1fr);grid-auto-columns:auto;overflow:visible;
        gap:1.75rem;width:var(--gut);margin-inline:auto;padding-inline:0}
  .rail-nav{display:none}
}
.gamecard{scroll-snap-align:start;background:var(--card);border:1px solid var(--line);
          border-radius:var(--r-slab);overflow:hidden;display:flex;flex-direction:column}
.on-stage .gamecard{background:var(--raise);border-color:var(--line)}
a.gamecard:hover{border-color:var(--brand)}
.gamecard .shot{position:relative;aspect-ratio:4/3}
/* Absolute, so the image cannot drive the box's height. As a normal-flow child of a column
   flex item its intrinsic 2:3 beat the declared aspect-ratio and every card ran 900px tall. */
.gamecard .shot img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.gamecard .shot::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,var(--card),rgba(20,27,24,.15) 55%,transparent)}
.on-stage .gamecard .shot::after{background:linear-gradient(to top,var(--raise),rgba(20,27,24,.15) 55%,transparent)}
.tag{position:absolute;z-index:1;top:1rem;left:1rem;padding:.35rem .75rem;
     font-size:.66rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
     background:var(--brand);color:var(--mark-ink);border-radius:var(--r-tag)}
.tag.gold{background:var(--gold);color:#3A2E00}
.gamecard .body{padding:1.6rem 1.75rem 1.85rem;display:flex;flex-direction:column;flex:1}
.gamecard .one-line{margin-top:.6rem;font-size:.97rem}
.specs{margin-top:1.4rem;display:grid;gap:.7rem}
.spec{display:flex;justify-content:space-between;gap:1rem;align-items:baseline;
      border-top:1px solid var(--line);padding-top:.7rem;font-size:.9rem}
.spec dt{color:var(--ink-soft)}
.spec dd{font-weight:800;text-align:right}
.spec dd.green{color:var(--brand)}
.gamecard .btn{margin-top:auto;align-self:flex-start}
.gamecard .specs+.btn{margin-top:1.6rem}

/* ── Quick links — NVIDIA's move: the section header doubles as navigation. Every major
      section there is eyebrow + heading + description + a row of 5-7 links + a rail. ──────── */
.quick{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:1.9rem}
.quick a{display:inline-flex;align-items:center;gap:.4rem;padding:.5rem 1rem;
  border:1px solid var(--line);border-radius:var(--r-pill);font-size:.86rem;font-weight:600;
  color:var(--ink-soft);background:color-mix(in srgb,var(--ink) 3%,transparent)}
.quick a:hover{border-color:var(--brand);color:var(--brand-text)}

/* ── Rail progress — NVIDIA pairs arrows with a numbered indicator, so a rail says how much
      is left rather than only offering to move. ─────────────────────────────────────────── */
.rail-count{font-family:var(--display);font-size:.85rem;color:var(--ink-soft);
  font-variant-numeric:tabular-nums;min-width:3rem;text-align:right;align-self:center}
.rail-bar{height:2px;background:var(--line);border-radius:2px;margin-top:1.5rem;overflow:hidden;
  width:var(--gut);margin-inline:auto}
.rail-bar i{display:block;height:100%;background:var(--brand);width:50%;
  transition:width .25s ease,transform .25s ease}
@media (min-width:735px){.rail-bar{display:none}}

/* ── Dual CTA — Apple gives every tile two: one to read, one to act ("Learn more" /
      "View pricing"); PlayStation the same ("Find out more" / "Buy now"). One filled button
      per card and a text link beside it keeps a page from becoming a wall of green pills. ── */
.ctas{display:flex;flex-wrap:wrap;align-items:center;gap:.75rem 1.5rem;margin-top:auto;padding-top:1.5rem}
.ctas .btn-link{font-size:.95rem;font-weight:700}

/* ── Editorial card — Amazon and PlayStation both carry a category label and a date above the
      headline, which is what makes a grid of cards read as a publication. ────────────────── */
.post{display:flex;flex-direction:column;background:var(--card);border:1px solid var(--line);
      border-radius:var(--r-tile);overflow:hidden}
.on-stage .post{background:var(--raise);border-color:var(--line)}
a.post:hover{border-color:var(--brand)}
.post .thumb{position:relative;aspect-ratio:16/9;background:var(--stage)}
.post .thumb img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.post .body{padding:1.3rem 1.4rem 1.5rem}
.post .meta{display:flex;flex-wrap:wrap;gap:.5rem;align-items:center;font-size:.72rem;
  font-weight:700;letter-spacing:.1em;text-transform:uppercase}
.post .cat{color:var(--brand-text)}
.post .date{color:var(--ink-soft)}
.post h4{margin-top:.7rem}
.post p{margin-top:.5rem;font-size:.92rem}

/* ── Tabs — PlayStation runs one rail with two datasets behind a pair of pills. ──────────── */
.tabs{display:inline-flex;gap:.25rem;padding:.25rem;margin-top:1.6rem;
      background:var(--card);border:1px solid var(--line);border-radius:var(--r-pill)}
.tabs button{border:0;background:none;color:var(--ink-soft);font:inherit;font-weight:700;
  font-size:.9rem;padding:.5rem 1.1rem;border-radius:var(--r-pill);cursor:pointer}
.tabs button[aria-selected="true"]{background:var(--brand);color:var(--mark-ink)}

/* ── Centred slab ────────────────────────────────────────────────────────────────────────
   Screenshotted off apple.com on 2026-09-10. Every product section there is CENTRED: an
   enormous name on its own line, a short tagline of one or two centred lines beneath it, then
   the calls to action — never a left-aligned column of paragraphs. */
.slab{text-align:center}
.slab .wrap{display:flex;flex-direction:column;align-items:center}
/* Centring the wrap makes its children shrink to content, which breaks any child that bleeds
   past the gutter with a negative inline margin — it stops being stretched, so the margin
   pushes it out of the page instead. Full-bleed children opt back into stretching. */
.slab .wrap>.phones,.slab .wrap>.rail,.slab .wrap>.creed,
.slab .wrap>.portraits,.slab .wrap>.grid,.slab .wrap>.steps,
.slab .wrap>.faq,.slab .wrap>.tablewrap,.slab .wrap>.stats,
.slab .wrap>.devices,.slab .wrap>.figures{align-self:stretch}
.slab .lede{margin-inline:auto;max-width:46ch}
.slab .stores,.slab .quick,.slab .ctas{justify-content:center}
.slab h2{font-size:clamp(2.25rem,6vw,4rem);letter-spacing:-.03em;line-height:1.03}

/* ── Split rows ───────────────────────────────────────────────────────────────────────────── */
.split{display:grid;gap:clamp(2rem,5vw,4.5rem);align-items:center;grid-template-columns:1fr}
@media (min-width:735px){.split{grid-template-columns:1fr 1fr}.split.flip .art{order:-1}}
.split .art{border-radius:var(--r-slab);overflow:hidden;border:1px solid var(--line);background:var(--card)}
.on-stage .split .art{border-color:var(--line);background:var(--raise)}
.split .art img{width:100%;aspect-ratio:4/3;object-fit:cover;max-height:32rem}

/* ── Checks ───────────────────────────────────────────────────────────────────────────────── */
.checks{margin-top:1.9rem;display:grid;gap:1rem}
.check{display:flex;gap:.85rem;align-items:flex-start;color:var(--ink-soft);font-size:1rem}
.check svg{width:1.2rem;height:1.2rem;flex:none;margin-top:.22rem;color:var(--brand-text)}

/* ── Steps ────────────────────────────────────────────────────────────────────────────────── */
.steps{margin-top:2.75rem;display:grid;gap:0;text-align:left}
.step{display:grid;gap:.4rem 1.6rem;grid-template-columns:auto 1fr;padding:1.75rem 0;border-top:1px solid var(--line)}
.step:last-child{border-bottom:1px solid var(--line)}
.step .n{font-family:var(--display);font-weight:700;font-size:1.75rem;color:var(--brand-text);line-height:1;
         grid-row:span 2;min-width:2.6rem}
.step h4{font-size:1.2rem}
.step p{margin-top:.4rem;max-width:60ch}

/* ── FAQ ──────────────────────────────────────────────────────────────────────────────────── */
.faq{margin-top:2.25rem;display:grid;gap:.75rem;text-align:left}
.faq details{background:var(--card);border:1px solid var(--line);border-radius:var(--r-tile);padding:1.2rem 1.4rem}
.on-stage .faq details{background:var(--raise);border-color:var(--line)}
.faq details[open]{border-color:var(--brand)}
.faq summary{cursor:pointer;font-weight:800;font-size:1.02rem;list-style:none;display:flex;
             justify-content:space-between;gap:1rem;align-items:flex-start}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"+";font-family:var(--display);color:var(--brand-text);font-size:1.35rem;line-height:1}
.faq details[open] summary::after{content:"\2212"}
.faq p{margin-top:.85rem;font-size:.96rem}
.faq p+p{margin-top:.6rem}

/* ── Table ────────────────────────────────────────────────────────────────────────────────── */
.tablewrap{margin-top:1.9rem;overflow-x:auto;border:1px solid var(--line);border-radius:var(--r-tile);text-align:left}
table{border-collapse:collapse;width:100%;min-width:32rem;font-size:.95rem}
th,td{text-align:left;padding:1rem 1.2rem;border-bottom:1px solid var(--line)}
th{font-size:.72rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft)}
tr:last-child td{border-bottom:0}
td strong{font-weight:800}

/* ── Portrait grid ────────────────────────────────────────────────────────────────────────
   PlayStation's games grid: a CONTAINED grid of small uniform tiles with the title BELOW the
   art in plain, small, low-contrast text — the art is the hero and the label just names it. */
.portraits{display:grid;gap:1.1rem;margin-top:2.5rem;text-align:left;
           grid-template-columns:repeat(auto-fit,minmax(min(10rem,45%),1fr))}
.portraits figure{margin:0}
.portraits .frame{border-radius:var(--r-tile);overflow:hidden;border:1px solid var(--line);
                  background:var(--card);aspect-ratio:3/4;position:relative}
.portraits img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.portraits figcaption{margin-top:.75rem;font-size:.85rem;line-height:1.4;color:var(--ink-soft)}

/* ── Note ─────────────────────────────────────────────────────────────────────────────────── */
.note{border-left:2px solid var(--brand);padding-left:1.2rem;margin-top:1.75rem;text-align:left}
.note.gold{border-left-color:var(--gold-text)}

/* ── Page head / breadcrumb ───────────────────────────────────────────────────────────────
   Interior pages get a stage of their own rather than dropping straight into body copy. */
.crumb{display:flex;gap:.5rem;align-items:center;font-size:.85rem;color:var(--ink-soft);flex-wrap:wrap}
.crumb a:hover{color:var(--brand)}
.crumb span{opacity:.5}
.pagehead{background:var(--stage);
  padding:clamp(3rem,7vw,5.5rem) 0 clamp(3rem,6vw,4.5rem);position:relative;overflow:hidden}
.pagehead .lede{max-width:54ch}

/* ── CTA close ────────────────────────────────────────────────────────────────────────────── */
.close{text-align:center}
.close .wrap{display:flex;flex-direction:column;align-items:center}
.close .lede{margin-inline:auto}
.close .stores{justify-content:center}
.close .mark{width:3.5rem;height:3.5rem;color:var(--brand-text);margin-bottom:1.6rem}

/* ── Footer ───────────────────────────────────────────────────────────────────────────────── */
footer{background:var(--stage);border-top:1px solid var(--line);
       padding:clamp(3rem,6vw,4.5rem) 0 3rem;color:var(--ink-soft);font-size:.88rem}
.footgrid{display:grid;gap:2.25rem;grid-template-columns:repeat(auto-fit,minmax(9.5rem,1fr))}
.footgrid h5{font-size:.72rem;font-weight:800;letter-spacing:.14em;text-transform:uppercase;
             color:var(--ink);margin-bottom:1rem}
.footgrid a{display:block;padding:.32rem 0}
.footgrid a:hover{color:var(--brand)}
.footbase{margin-top:2.75rem;padding-top:1.75rem;border-top:1px solid var(--line);
          display:flex;flex-wrap:wrap;gap:1rem;justify-content:space-between;align-items:flex-start}
.colophon{max-width:56ch}
.legalid{margin-top:.6rem;font-size:.82rem;opacity:.75}
.footbase{flex-direction:column}
.footmark{width:2.25rem;height:2.25rem;color:var(--brand-text);margin-bottom:1rem}

/* ── The art slot when it holds a device rather than a photograph ──────────────────────────
   overflow:hidden is load-bearing, not tidiness. The device's floor glow is inset -40% on each
   side by design; inside a .tile or .hero that bleed is clipped by the stage, but this slot sits
   in an ordinary section with nothing to clip it, and 40% of a 19rem device is 121px of real
   page width on each side. At a 390px viewport it made the document 465px wide. This is the same
   bug the hero glow had, in a new place — a decorative bleed is only decorative if something
   clips it. */
.artdevice{display:flex;justify-content:center;overflow:hidden}
.artdevice .device{margin:0;width:min(100%,19rem)}

/* ══ PAGE TRANSITIONS ══════════════════════════════════════════════════════════════════════
   Navigating between pages used to be a hard swap: the old page vanishes, the browser paints the
   new ground, then content appears. On a site whose sections are near-black stages that reads as
   a flash and a snap — brutal, in a way a single page never is.

   The cross-document View Transitions API fixes it at the source: the browser holds the outgoing
   frame, paints the incoming one, and cross-fades between them. It needs no script, degrades to
   exactly the old behaviour where it is unsupported, and — because the transition is the
   BROWSER's, not a fake overlay — it cannot leave the page stuck mid-animation if something
   throws.

   The pair below is deliberately gentle and slightly asymmetric: the outgoing frame leaves faster
   than the incoming one arrives, which is what stops a cross-fade from reading as a dissolve. */
@view-transition{navigation:auto}
::view-transition-old(root){animation:vtOut .28s cubic-bezier(.4,0,1,1) both}
::view-transition-new(root){animation:vtIn .46s cubic-bezier(0,0,.2,1) both}
@keyframes vtOut{from{opacity:1;transform:none}to{opacity:0;transform:translateY(-6px)}}
@keyframes vtIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
/* The bar and the footer are continuous furniture — they should not fade with the body, they
   should stay put while the page under them changes. Naming them takes them out of the root
   snapshot and gives each its own, which here is simply "do not animate". */
.bar{view-transition-name:bar}
footer{view-transition-name:foot}
::view-transition-old(bar),::view-transition-new(bar),
::view-transition-old(foot),::view-transition-new(foot){animation:none;mix-blend-mode:normal}

/* The first paint of a cold load, softened the same way. Gated on .js so a scriptless browser
   never holds an invisible page: the class is added by the runtime, so if it never runs there is
   nothing to fade in from. */
.js main{animation:vtIn .5s cubic-bezier(0,0,.2,1) both}

/* ══ MOTION ════════════════════════════════════════════════════════════════════════════════
   Every rule below is written so that the page is COMPLETE without it. Reveal states are added
   by script, never by markup, so a browser that never runs the script — or one where it throws —
   shows a finished page rather than a blank one. And every one of them collapses to nothing
   under prefers-reduced-motion, which is checked in the runtime as well as here: the observer is
   never even attached, so reduced-motion users pay no scroll cost either.

   The vocabulary is deliberately small — rise, settle, and a parallax drift — because a page
   where six different things move in six different ways reads as a demo, not as a product. */
:root{--ease:cubic-bezier(.22,.61,.36,1);--ease-out:cubic-bezier(.16,1,.3,1)}

/* The scroll reveal. A rise with a slight scale so it reads as approaching rather than sliding. */
.reveal{opacity:0;transform:translateY(14px);will-change:opacity,transform}
.reveal.seen{opacity:1;transform:none;
  transition:opacity 1s var(--ease-out),transform 1s var(--ease-out);
  transition-delay:var(--d,0ms)}

/* The hero entrance. Runs on load rather than on scroll — it is already in view — and is
   staggered so the eye is walked down the composition instead of hit with all of it. */
@keyframes rise{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
@keyframes riseIn{from{opacity:0;transform:translateY(22px) scale(.985)}to{opacity:1;transform:none}}
@keyframes fade{from{opacity:0}to{opacity:1}}
@keyframes slowZoom{from{transform:scale(1.08)}to{transform:scale(1)}}
.js .hero .herotag,.js .hero .eyebrow,.js .hero .mega,
.js .hero .lede,.js .hero .stores,.js .hero .figures{opacity:0;animation:rise 1.15s var(--ease-out) forwards}
.js .hero .herotag{animation-delay:.05s}
.js .hero .eyebrow{animation-delay:.16s}
.js .hero .mega{animation-delay:.24s;animation-name:riseIn}
.js .hero .lede{animation-delay:.38s}
.js .hero .stores{animation-delay:.48s}
.js .hero .figures{animation-delay:.6s}
/* The photograph settles rather than snapping in — 1.8s of a very slow push-in, once. */
.js .hero-img img{animation:slowZoom 2.4s var(--ease-out) forwards,fade 1.2s ease forwards}

/* Parallax. The runtime writes --p (roughly -1 → 1 across the viewport) onto each parallax
   element and CSS decides what to do with it, so the scroll handler stays a single property
   write and the compositor does the rest. */
.hero-img img,.tile-img img{transform:translate3d(0,calc(var(--p,0) * 4.5%),0) scale(1.12);
  transform-origin:50% 50%;backface-visibility:hidden}
.device{transform:translate3d(0,calc(var(--p,0) * -2.2rem),0)}
.tile .device{transform:translate3d(0,calc(var(--p,0) * -3rem),0)}

/* The claim number counts up when it arrives. The odometer is the runtime's; this is the lift. */
.claim-num{animation:none}
.claim-num.seen{animation:riseIn 1s var(--ease-out) both}

/* Buttons: a real press, and a lift that does not shift the layout. */
.btn:active{transform:scale(.97)}
.btn-primary:hover,.btn-light:hover{transform:translateY(-1px)}
a.card,a.post,a.gamecard{transition:transform .28s var(--ease),border-color .2s ease,box-shadow .28s var(--ease)}
a.card:hover,a.post:hover,a.gamecard:hover{transform:translateY(-3px);box-shadow:var(--shadow-lg)}
.portraits .frame{overflow:hidden}
.portraits img{transition:transform .6s var(--ease)}
.portraits figure:hover img{transform:scale(1.05)}

/* The countdown capsule breathes while the night is still ahead of it. */
@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.45;transform:scale(.86)}}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  ::view-transition-old(root),::view-transition-new(root),.js main{animation:none}
  .reveal,.reveal.seen{opacity:1;transform:none;transition:none}
  .js .hero .herotag,.js .hero .eyebrow,.js .hero .mega,
  .js .hero .lede,.js .hero .stores,.js .hero .figures,
  .js .hero-img img,.claim-num.seen{animation:none;opacity:1}
  .hero-img img,.tile-img img{transform:scale(1.02)}
  .device,.tile .device{transform:none}
  body,.card,.btn,.gamecard,.stat{transition:none}
  .menu{transition:none}
  .btn:active,.btn-primary:hover,.btn-light:hover,
  a.card:hover,a.post:hover,a.gamecard:hover{transform:none}
  .portraits figure:hover img{transform:none}
  .herotag .dot{animation:none}
}