  :root{
    --ink:#0b0b0f;
    --mist:#151519;
    --fog:#c9a15a;
    --parchment:#f2efe8;
    --ember:#c9a15a;
    --signal:#c9a15a;

    --combat-a:#3a120c; --combat-b:#c94a2c;
    --explore-a:#16281a; --explore-b:#9fae5c;
    --tension-a:#0b1224; --tension-b:#3d4f8f;
    --respite-a:#2b1a0c; --respite-b:#d9a24a;
  }

  *{margin:0;padding:0;box-sizing:border-box;}

  /* iOS Safari "text autosizing": it silently inflates the font of any block
     it decides is too small for its width. The credits ticker is one long
     nowrap line, so the widest entry in it — "National Museum – Palace of the
     Grand Dukes of Lithuania" — got boosted to roughly double everything
     around it, on the phone only. This pins text to the size we actually
     asked for. It does NOT stop the user pinch-zooming. */
  html{
    -webkit-text-size-adjust:100%;
    text-size-adjust:100%;
  }
  /* Settling into a cue is handled in JS (js/scenes/scroll-settle.js), NOT by
     CSS scroll-snap. Both native options were wrong for this page:
       - `proximity` only pulls you in if you happen to stop right next to a
         scene, so stopping halfway between two of them just left you there,
         half one cue and half the next.
       - `mandatory` always snaps, but it also snaps while you are still
         scrolling and it has no idea the page continues into long, non-snapping
         sections — that is the version that fought the trackpad and vibrated.
     The JS settle waits until you have actually come to rest, glides you to the
     nearest cue, and aborts the instant you touch the wheel/trackpad again.
     There is deliberately no global `scroll-behavior:smooth` either — it routed
     every programmatic scroll through the browser's own animator, which then
     fought ours. Nav jumps pass `behavior:'smooth'` to scrollIntoView per call
     instead, which works without the CSS property. */
  body{
    background:var(--ink);
    color:var(--parchment);
    font-family:'IBM Plex Sans', sans-serif;
    overflow-x:clip;
  }

  /* Silkscreen has no Ą Č Ę Ė Į Ų Ū (it only carries Š and Ž), so Lithuanian
     words fell back per-glyph to the system monospace and one letter in the
     middle of a word came out smooth among the pixel ones. 'Pixelify Sans' is
     listed second purely to catch those seven letters: it is the closest pixel
     match to Silkscreen of the eight fonts tested, and it is already loaded for
     the display headlines, so this costs nothing. English is unaffected —
     Silkscreen covers it completely and renders every character itself. */
  .label{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.92rem;
    letter-spacing:0.12em;
    text-transform:uppercase;
    color:var(--fog);
    margin-bottom:0.5rem;
  }

  /* subtle CRT chromatic fringing - used once, only on display headlines */
  .title{
    text-shadow:
      1px 1px 0 rgba(233,225,205,0.28),
      2px 2px 0 rgba(233,225,205,0.16),
      3px 3px 0 rgba(233,225,205,0.08);
  }

  /* ---------- Chunky beveled control (PS2-dashboard button feel) ---------- */
  .bevel{
    border-radius:3px;
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,0.18),
      inset 0 -2px 0 rgba(0,0,0,0.35),
      0 1px 0 rgba(0,0,0,0.4);
  }

  /* ---------- Unlock gate ---------- */
  #gate{
    position:fixed; inset:0; z-index:100;
    background:var(--ink);
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    gap:1.5rem;
    transition:opacity 0.9s ease, visibility 0.9s ease;
    overflow:hidden;
  }
  #gate.hidden{opacity:0; visibility:hidden; pointer-events:none;}

  /* Subtle gold blast-wave ripples — very faint, just enough to keep the
     intro background from feeling flat and empty. */
  #gateWaveCanvas{
    position:absolute; inset:0; width:100%; height:100%;
    z-index:0;
    pointer-events:none;
  }
  #gate #enterBtn{position:relative; z-index:1;}
  #enterBtn{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.95rem;
    letter-spacing:0.08em;
    text-transform:uppercase;
    background:transparent;
    color:rgba(201,161,90,0.85);
    border:2px solid rgba(201,161,90,0.55);
    padding:0.95rem 2.1rem;
    cursor:pointer;
    transition:background 0.08s steps(1), color 0.08s steps(1), border-color 0.08s steps(1),
               box-shadow 0.35s ease, transform 0.35s ease;
    animation:enterBtnBreathe 4.5s ease-in-out infinite, enterBtnBob 3.2s ease-in-out infinite;
  }
  @keyframes enterBtnBreathe{
    0%,100%{ box-shadow:0 0 0px rgba(201,161,90,0); }
    50%{ box-shadow:0 0 16px rgba(201,161,90,0.25); }
  }
  @keyframes enterBtnBob{
    0%,100%{ transform:translateY(0); }
    50%{ transform:translateY(-3px); }
  }
  @media (prefers-reduced-motion: reduce){
    #enterBtn{animation:none;}
  }
  #enterBtn .btn-hover{display:none;}
  #enterBtn:hover .btn-default{display:none;}
  #enterBtn:hover .btn-hover{display:inline;}
  #enterBtn:hover{
    background:var(--ember);
    color:var(--ink);
    border-color:var(--ember);
    box-shadow:0 0 30px rgba(201,161,90,0.55);
    transform:scale(1.06) translateY(0);
    animation-play-state:paused;
  }
  #gate .label{margin-bottom:0.7rem;}

  /* ---------- Scenes (hero + 4 mood sections) ---------- */
  .scene{
    position:relative;
    /* svh = the SMALL viewport height: the page as it is with the URL bar
       showing. Unlike dvh it never changes as the bar slides away, so the
       layout stays put through the whole animation instead of reflowing
       under the visitor's finger — and unlike plain vh (which on iOS is the
       LARGE viewport) the bottom of each cue isn't hidden behind the bar
       when you first land. vh stays as the fallback for older browsers. */
    height:100vh;
    height:100svh;
    width:100%;
    display:flex;
    flex-direction:column;
    align-items:center;
    justify-content:center;
    overflow:hidden;
    text-align:center;
    padding:2rem;
  }
  /* Only the mood scenes are settle targets (see scroll-settle.js). The
     interactive demo and the About / Credits / Contact sections below are
     never settled to, so once you're past the last cue you scroll freely. */

  .scene-bg{
    position:absolute; inset:-9%;
    background-size:400% 400%;
    background-position:50% 50%;
    filter:blur(18px) saturate(0.9) brightness(0.55);
    transform:scale(1.08);
    transition:filter 1.1s ease, transform 1.1s ease, opacity 1.1s ease;
    /* drift moves the layer via `translate` (a compositor-only property,
       kept separate from the `transform` scale above). The old version
       animated `background-position`, which repainted this larger-than-
       viewport element AND re-ran the 18px blur every single frame — that
       was the main reason hover states and clicks landed a beat late and
       scrolling felt rough. Moving the layer instead costs nothing. */
    animation:drift 26s ease-in-out infinite;
    z-index:0;
  }
  /* Set by pixelate.js once the scene's dithered canvas is actually painting
     opaque footage over this layer — see the comment there. */
  .scene.has-pixels .scene-bg{ display:none; }
  .scene.active .scene-bg{
    filter:blur(2px) saturate(1.05) brightness(0.7);
    transform:scale(1.0);
  }
  @keyframes drift{
    0%,100%{translate:-2.4% -1.6%;}
    50%{translate:2.4% 1.6%;}
  }

  .scene::after{
    content:'';
    position:absolute; inset:0;
    background:linear-gradient(180deg, rgba(11,11,15,0.42) 0%, rgba(11,11,15,0.66) 50%, rgba(11,11,15,0.88) 100%);
    z-index:1;
  }
  .scene::before{
    content:'';
    position:absolute; inset:0;
    background:radial-gradient(ellipse 60% 45% at 50% 48%, rgba(6,6,8,0.4) 0%, transparent 75%);
    z-index:1;
    pointer-events:none;
  }

  .scene-content{position:relative; z-index:2; max-width:640px;}

  .pixel-canvas{
    position:absolute; inset:0; width:100%; height:100%;
    z-index:0;
    image-rendering:pixelated;
    image-rendering:crisp-edges;
  }
  .source-video{
    position:absolute; width:2px; height:2px; opacity:0;
    pointer-events:none; overflow:hidden;
  }

  #hero .scene-bg{background:radial-gradient(circle at 30% 30%, var(--combat-b), var(--tension-a) 70%);}
  #combat .scene-bg{background:linear-gradient(120deg, var(--combat-a), var(--combat-b), var(--combat-a));}
  #explore .scene-bg{background:linear-gradient(120deg, var(--explore-a), var(--explore-b), var(--explore-a));}
  #tension .scene-bg{background:linear-gradient(120deg, var(--tension-a), var(--tension-b), var(--tension-a));}
  /* Tension's source footage is genuinely dark (night scene) — lift it
     so it reads clearly instead of disappearing into the overlay. */
  #respite .scene-bg{background:linear-gradient(120deg, var(--respite-a), var(--respite-b), var(--respite-a));}

  /* mood-tint RGB triplets, used by the pixel-stair headline effect below */
  #hero{--stairRGB:159,180,189;}
  #combat{--stairRGB:201,74,44;}
  #explore{--stairRGB:159,174,92;}
  #tension{--stairRGB:61,79,143;}
  #respite{--stairRGB:217,162,74;}

  h1.title{
    font-family:'Pixelify Sans', monospace;
    font-weight:700;
    font-size:clamp(2.4rem, 7vw, 4.6rem);
    line-height:1.0;
    letter-spacing:0.01em;
    margin-bottom:0.6rem;
  }
  .scene p.desc{
    font-size:1rem;
    color:#cfd9d2;
    max-width:46ch;
    margin:0.9rem auto 0;
    line-height:1.6;
  }
  .scene .game-name{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-style:normal;
    font-size:1rem;
    color:var(--signal);
    margin-top:1rem;
  }

  /* ---------- Atmosphere nav ---------- */
  #atmoNav{
    position:relative; z-index:3;
    display:flex; gap:0.6rem; flex-wrap:wrap; justify-content:center;
    margin-top:1.2rem;
  }
  .atmo-btn{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.85rem;
    letter-spacing:0.04em;
    text-transform:uppercase;
    color:var(--parchment);
    background:none;
    border:2px solid rgba(233,225,205,0.5);
    padding:0.35rem 0.55rem;
    cursor:pointer;
    transition:color 0.08s steps(1), border-color 0.08s steps(1), background 0.08s steps(1);
  }
  .atmo-btn:hover{color:var(--ink); background:var(--ember); border-color:var(--ember);}
  .atmo-btn.on{color:var(--ink); background:var(--ember); border-color:var(--ember); position:relative;}
  .atmo-btn.on::before{
    content:'▶'; position:absolute; left:-1.1em; top:50%; transform:translateY(-50%);
    color:var(--ember); font-size:0.7em;
    animation:cursorBlink 1s steps(1) infinite;
  }
  @keyframes cursorBlink{0%,49%{opacity:1;}50%,100%{opacity:0;}}
  .interactive-btn{color:var(--ember); border-color:rgba(201,161,90,0.65);}
  .interactive-btn:hover{color:var(--ink); background:var(--ember); border-color:var(--ember);}
  .interactive-btn.on{color:var(--ink); background:var(--ember); border-color:var(--ember);}

  .loop-hint{
    position:relative; z-index:3;
    margin-top:1.2rem;
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.78rem;
    letter-spacing:0.04em;
    color:var(--fog);
    max-width:38ch;
    margin-left:auto; margin-right:auto;
  }

  /* ---------- Waveform ---------- */
  #waveform{
    position:absolute; bottom:0; left:0; width:100%; height:90px;
    z-index:2; opacity:0.85;
  }

  /* ---------- Credit line on mood scenes ---------- */
  .credit{
    position:relative; z-index:2;
    margin-top:1.6rem;
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.72rem;
    letter-spacing:0.04em;
    color:var(--fog);
  }

  /* ---------- Site nav (About / Credits / Contact) ---------- */
  /* Anchored to the top of the page (absolute, not fixed) — it scrolls
     away with the content instead of following the viewport. */
  #siteNav{
    position:absolute; top:1.4rem; right:1.6rem; z-index:50;
    display:flex; gap:1.4rem;
  }
  #siteNav a{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.78rem;
    letter-spacing:0.08em;
    text-transform:uppercase;
    color:var(--fog);
    text-decoration:none;
    border-bottom:1px solid transparent;
    padding-bottom:2px;
    transition:color 0.25s ease, border-color 0.25s ease;
  }
  #siteNav a:hover{color:var(--ember); border-color:var(--ember);}

  /* ---------- Language switch (top-left, hover to reveal) ---------- */
  /* Anchored to the top of the page (absolute, not fixed) — it scrolls
     away with the content, matching #siteNav. Collapsed state shows only
     the active language; hover / keyboard focus reveals the other. */
  #langSwitch{
    position:absolute; top:1.4rem; left:1.6rem; z-index:50;
    display:flex; flex-direction:column; align-items:flex-start; gap:0.3rem;
  }
  .lang-btn{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.78rem;
    letter-spacing:0.08em;
    color:var(--fog);
    background:none;
    border:none;
    border-bottom:1px solid transparent;
    padding:0 0 2px;
    cursor:pointer;
    display:none;
    transition:color 0.2s ease, border-color 0.2s ease, opacity 0.2s ease;
  }
  /* Collapsed: only the active language is visible, and it always sits
     first so it doesn't shift position when the menu expands */
  .lang-btn.on{
    display:block;
    order:-1;
    color:var(--ember);
    border-color:var(--ember);
  }
  /* Expanded on hover / focus: show the alternative(s) too */
  #langSwitch:hover .lang-btn,
  #langSwitch:focus-within .lang-btn{display:block;}
  #langSwitch:hover .lang-btn:not(.on),
  #langSwitch:focus-within .lang-btn:not(.on){
    color:var(--fog);
    opacity:0.8;
  }
  .lang-btn:not(.on):hover,
  .lang-btn:not(.on):focus-visible{color:var(--ember); opacity:1;}

  /* ---------- Scene up/down arrow nav (bottom-right) ---------- */
  #sceneNav{
    position:fixed; bottom:1.6rem; right:1.6rem; z-index:50;
    display:flex; flex-direction:column; gap:0.5rem;
    /* Transition TRANSFORM, never `bottom`. This is a bottom-anchored fixed
       element, and `bottom` is exactly the property the browser re-resolves on
       every frame while an iOS bottom URL bar slides away — with a 0.45s eased
       transition on it, each of those micro-changes got animated, so the
       control chased the bar with a springy lag. That is the wobble. transform
       is compositor-only and the viewport change doesn't touch it. */
    transition:transform 0.45s cubic-bezier(.2,.7,.2,1);
  }
  #sceneNav button{
    display:block;
    width:1.6rem; height:1.1rem;
    background:none;
    border:none;
    border-top:1px solid rgba(233,225,205,0.35);
    color:var(--fog);
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-size:0.55rem;
    line-height:1.1rem;
    text-align:center;
    cursor:pointer;
    padding:0;
    transition:color 0.15s steps(1), border-color 0.15s steps(1);
  }
  #sceneNav button:first-child{border-top:none; border-bottom:1px solid rgba(233,225,205,0.35);}
  #sceneNav button:hover{color:var(--ember); border-color:var(--ember);}
  #sceneNav button:disabled{opacity:0.25; cursor:default;}
  #sceneNav button:disabled:hover{color:var(--fog); border-color:rgba(233,225,205,0.35);}
  @media (max-width:600px){
    #sceneNav{bottom:1rem; right:1rem;}
  }
  @media (max-width:600px){
    #siteNav{gap:0.9rem; top:1rem; right:1rem;}
    #siteNav a{font-size:0.62rem;}
    #langSwitch{top:1rem; left:1rem;}
    .lang-btn{font-size:0.62rem;}
  }

  /* ---------- Info sections: About / Credits / Contact ---------- */
  .info-section{
    position:relative;
    /* Was --mist (#151519). Work / Services / Credits / About all sat on that
       slightly-lifted grey while Contact alone was true black, so the page
       visibly changed shade partway down. All of them are --ink now and the
       run from the demo to the footer is one continuous black. */
    background:var(--ink);
    padding:6.5rem 1.5rem;
    display:flex; justify-content:center;
  }
  .info-inner{max-width:660px; width:100%; text-align:center;}
  #credits .info-inner{max-width:920px;}
  .info-inner h2{
    font-family:'Pixelify Sans', monospace;
    font-weight:700;
    font-size:clamp(1.8rem, 4.6vw, 2.6rem);
    line-height:1.3;
    margin:0.5rem 0 1.1rem;
  }
  .info-inner p{
    color:#cfd9d2;
    line-height:1.7;
    font-size:1.02rem;
    max-width:56ch;
    margin:0 auto;
  }
  .info-inner p + p{margin-top:1rem;}

  /* The About headline is a full sentence, not a 2-3 word title like the
     other sections — at the shared clamp it broke to four lines. Smaller,
     a touch more line spacing, and a wider inner so each half of the
     <br> sits on one line. It still wraps gracefully on narrow screens. */
  #about .info-inner{max-width:820px;}
  #about .info-inner h2{
    font-size:clamp(1.4rem, 3.4vw, 2rem);
    line-height:1.45;
  }

  /* credits chip grid — deliberately secondary: the four headline stats
     above carry the message, this is the supporting "also worked with" row */
  .credit-grid{
    display:flex; flex-wrap:wrap; gap:0.6rem; justify-content:center;
    margin-top:1.4rem;
  }
  .credit-chip{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.74rem;
    letter-spacing:0.02em;
    /* dimmed to sit at the same weight as the logo images, which render
       white at opacity 0.6 — the plain-text names were reading brighter */
    color:rgba(242,239,232,0.6);
    background:rgba(233,225,205,0.05);
    border:1px solid rgba(233,225,205,0.14);
    padding:0.5rem 0.85rem;
    text-decoration:none;
    display:inline-flex;
    align-items:center;
    justify-content:center;
    line-height:1;
    transition:border-color 0.25s ease, color 0.25s ease, background 0.25s ease;
  }
  .credit-chip:hover{
    border-color:var(--ember);
    color:var(--ink);
    background:var(--ember);
  }
  .credit-chip.credit-logo{
    padding:0.7rem 1rem;
    display:inline-flex;
    align-items:center;
    justify-content:center;
    background:rgba(233,225,205,0.04);
  }
  .credit-chip.credit-logo img{
    height:24px;
    width:auto;
    max-width:140px;
    object-fit:contain;
    filter:brightness(0) invert(1); /* guarantees pure white regardless of source */
    opacity:0.6;
    transition:opacity 0.25s ease;
  }
  .credit-chip.credit-logo:hover{
    background:rgba(233,225,205,0.04); /* logos stay on dark — no fill flip like text chips */
    border-color:var(--ember);
  }
  .credit-chip.credit-logo:hover img{
    opacity:1;
  }

  /* Custom name treatments — evoking each artist's own visual identity */
  .credit-name-rokas{
    font-family:'Bebas Neue', sans-serif;
    /* Bebas is a tall, solid, high-ink display face. Kept it recognisable
       but pulled the size down near the other names and the alpha well
       below the shared 0.6 — at its old 1.5rem / 0.4 it still dominated
       the row and read as highlighted. */
    font-size:1.02rem;
    letter-spacing:0.06em;
    line-height:1;
    color:rgba(242,239,232,0.34);
  }
  .credit-name-nombeko{
    font-family:'Fraunces', serif;
    font-weight:400;
    font-style:italic;
    font-size:1.15rem;
    letter-spacing:0.005em;
    line-height:1;
  }
  .credit-name-monika{
    font-family:'Unbounded', sans-serif;
    font-weight:600;
    font-size:0.72rem;
    letter-spacing:0.14em;
    text-transform:uppercase;
    line-height:1;
  }
  .credit-chip:hover .credit-name-rokas,
  .credit-chip:hover .credit-name-nombeko,
  .credit-chip:hover .credit-name-monika{
    color:var(--ink);
  }

  /* contact */
  #contact{background:var(--ink);}
  .contact-btn{
    display:inline-block;
    margin-top:1.8rem;
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.85rem;
    letter-spacing:0.08em;
    text-transform:uppercase;
    color:var(--ink);
    background:var(--ember);
    padding:0.85rem 1.8rem;
    text-decoration:none;
  }
  /* Plain, copyable address under the button — a fallback for anyone who
     doesn't want a mail client launched at them. `user-select:all` means one
     click grabs the whole address instead of a word at a time. */
  .contact-direct{
    margin-top:1.1rem;
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.72rem;
    letter-spacing:0.04em;
    color:var(--fog);
  }
  .contact-email{
    color:var(--ember);
    user-select:all;
    -webkit-user-select:all;
  }
  .contact-links{
    margin-top:1.4rem;
    display:flex; gap:1.2rem; justify-content:center;
    font-family:'Silkscreen', 'Pixelify Sans', monospace; font-size:0.8rem;
    font-weight:700;
  }
  .contact-links a{color:var(--fog); text-decoration:none;}
  .contact-links a:hover{color:var(--ember);}

  /* ---------- Interactive stem demo ---------- */
  .stem-demo-section{
    min-height:100vh;
    min-height:100svh;
    padding:5rem 1.5rem;
    position:relative;
    overflow:hidden;
    background:var(--ink);
    /* No snap point here on purpose: the four mood scenes above are the
       last things that snap. Once you scroll into the interactive section
       there's nothing pulling you back, so continuing down into About /
       Credits / Contact is completely free. */
  }
  #stemSkyline{
    position:absolute; inset:0; width:100%; height:100%;
    z-index:0;
  }
  .stem-demo-section::before{
    content:'';
    position:absolute; inset:-10%;
    background:radial-gradient(circle at 50% 40%, rgba(201,161,90,0.16), transparent 60%);
    animation:stemGlow 8s ease-in-out infinite;
    pointer-events:none;
    z-index:0;
  }
  @keyframes stemGlow{
    0%,100%{opacity:0.7; transform:scale(1);}
    50%{opacity:1; transform:scale(1.08);}
  }
  .stem-demo-section .info-inner{
    position:relative; z-index:1;
    opacity:0; transform:translateY(24px);
    transition:opacity 0.9s ease, transform 0.9s ease;
  }
  .stem-demo-section.in-view .info-inner{
    opacity:1; transform:translateY(0);
  }
  .stem-demo-section{align-items:center;}
  .stem-demo-title{
    transition:opacity 0.9s ease, max-height 0.9s ease, margin 0.9s ease, filter 0.9s ease;
    filter:blur(0px);
    overflow:hidden;
    margin-bottom:0.6rem !important;
  }
  .stem-demo-title.faded{
    opacity:0; max-height:0; margin:0 !important; filter:blur(12px);
    pointer-events:none;
  }
  .console-box{
    max-width:560px; margin:1rem auto 0;
    border:2px solid rgba(233,225,205,0.5);
    background:rgba(11,11,15,0.55);
    padding:1rem 1.2rem 1.3rem;
  }
  .console-header{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-size:0.68rem; letter-spacing:0.08em;
    color:var(--ember);
    text-align:center;
    padding-bottom:0.7rem;
    margin-bottom:0.7rem;
    border-bottom:1px solid rgba(233,225,205,0.3);
  }
  .console-divider{
    height:1px;
    background:rgba(233,225,205,0.25);
    margin:0.7rem 0;
  }
  #storyLog{
    display:flex; flex-direction:column; gap:0.35rem;
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-size:0.68rem; letter-spacing:0.02em;
    color:var(--fog);
    opacity:0.7;
    text-align:left;
    min-height:0;
  }
  #storyLog:empty{display:none;}
  #storyLog:empty + .console-divider{display:none;}
  #storyLog .log-line{cursor:pointer; transition:color 0.15s ease;}
  #storyLog .log-line::before{content:'— '; opacity:0.5;}
  #storyLog .log-line:hover{color:var(--ember);}
  #storyLog .log-line:hover::after{content:' (rewind)'; opacity:0.6; font-size:0.9em;}
  /* End-of-branch choice: hand the room back to the mood atmospheres */
  .stem-btn-return{
    margin-top:1.2rem;
    opacity:0.72;
    border-style:dashed;
    border-color:rgba(233,225,205,0.35);
  }
  .stem-btn-return:hover{opacity:1;}

  footer.site-footer{
    text-align:center; padding:2rem 1rem 3rem;
    background:var(--ink);
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.7rem; letter-spacing:0.06em;
    line-height:1.8;
    color:var(--fog);
  }
  .stem-demo-title{
    font-family:'Pixelify Sans', monospace;
    font-weight:700;
    font-size:clamp(1.5rem, 3.2vw, 2.2rem) !important;
    line-height:1.25 !important;
  }
  #stemWaveform{
    display:block;
    margin:1rem auto 0;
    width:100%; max-width:680px; height:90px;
    opacity:0.9;
  }
  .stem-buttons{
    display:flex; flex-wrap:wrap; gap:0.8rem; justify-content:center;
    margin-top:0; min-height:2.5rem;
  }
  .stem-buttons.digesting{
    animation:digestOut 0.4s ease forwards;
  }
  /* While a choice is resolving, the console takes no input at all — the
     JS `busy` flag is authoritative, this just stops the cursor lying. */
  .stem-buttons.locked, #storyLog.locked{pointer-events:none;}
  .stem-buttons.digest-in{
    animation:digestIn 0.5s ease forwards;
  }
  @keyframes digestOut{
    0%{opacity:1; transform:scale(1);}
    100%{opacity:0; transform:scale(0.8);}
  }
  @keyframes digestIn{
    0%{opacity:0; transform:scale(1.12);}
    100%{opacity:1; transform:scale(1);}
  }
  .stem-btn{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-size:0.85rem;
    letter-spacing:0.02em;
    text-transform:uppercase;
    background:none;
    border:2px solid rgba(233,225,205,0.5);
    color:var(--parchment);
    padding:0.7rem 1.3rem;
    cursor:pointer;
    transition:color 0.08s steps(1), border-color 0.08s steps(1), background 0.08s steps(1);
    animation:stemBtnIn 0.4s ease;
  }
  @keyframes stemBtnIn{
    0%{opacity:0; transform:translateY(8px);}
    100%{opacity:1; transform:translateY(0);}
  }
  .stem-btn:hover{color:var(--ink); background:var(--ember); border-color:var(--ember);}

  /* Picking a choice: the row recedes, the pick holds while its layer loads */
  .stem-btn.dimmed{
    opacity:0.16;
    pointer-events:none;
    transition:opacity 0.5s ease;
  }
  .stem-btn.chosen{
    pointer-events:none;
    color:var(--ember);
    border-color:var(--ember);
    opacity:0.55;
    transform:scale(0.96);
    transition:opacity 0.6s ease, transform 0.6s ease, color 0.3s ease, border-color 0.3s ease;
  }
  .stem-btn.loading{
    animation:stemLoadingPulse 1.15s ease-in-out infinite;
  }
  .stem-btn.loading::after{
    content:attr(data-loading);
    display:block;
    margin-top:0.4rem;
    font-size:0.6rem;
    letter-spacing:0.14em;
    text-transform:lowercase;
    color:var(--ember);
  }
  @keyframes stemLoadingPulse{
    0%,100%{opacity:0.45;}
    50%{opacity:0.95;}
  }

  /* ---------- Composer commentary toggle + subtitle panel ---------- */
  .commentary-toggle{
    margin-top:1.4rem;
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.7rem;
    letter-spacing:0.04em;
    text-transform:uppercase;
    color:var(--parchment);
    background:none;
    border:2px solid rgba(233,225,205,0.5);
    padding:0.35rem 0.55rem;
    cursor:pointer;
    transition:color 0.08s steps(1), border-color 0.08s steps(1), background 0.08s steps(1);
  }
  .commentary-toggle:hover{color:var(--ink); background:var(--ember); border-color:var(--ember);}
  .commentary-toggle.on{background:var(--ember); border-color:var(--ember); color:var(--ink); position:relative;}
  .commentary-toggle.on::before{
    content:'▶'; position:absolute; left:-1.1em; top:50%; transform:translateY(-50%);
    color:var(--ember); font-size:0.7em;
    animation:cursorBlink 1s steps(1) infinite;
  }

  .commentary-panel{
    position:absolute; left:50%; bottom:9%; transform:translate(-50%,12px);
    z-index:4; width:min(640px,86%);
    background:rgba(11,11,15,0.78);
    border:1px solid rgba(233,225,205,0.15);
    padding:1rem 1.3rem;
    opacity:0; pointer-events:none;
    transition:opacity 0.4s ease, transform 0.4s ease;
  }
  .commentary-panel.open{opacity:1; transform:translate(-50%,0); pointer-events:auto;}
  .commentary-panel p{
    font-family:'IBM Plex Sans', sans-serif;
    font-size:0.9rem; line-height:1.55; color:var(--parchment);
    text-align:left; margin:0;
  }
  .commentary-panel .cc-label{
    font-family:'Silkscreen', 'Pixelify Sans', monospace; font-size:0.6rem; letter-spacing:0.1em;
    font-weight:700;
    color:var(--fog); text-transform:uppercase; display:block; margin-bottom:0.5rem;
  }

  #scrollHint{
    position:absolute; bottom:1.4rem; left:50%; transform:translateX(-50%);
    z-index:3; font-family:'Silkscreen', 'Pixelify Sans', monospace; font-size:0.75rem;
    font-weight:700;
    letter-spacing:0.1em; color:var(--fog); text-transform:uppercase;
    animation:bob 2.4s ease-in-out infinite;
  }
  @keyframes bob{0%,100%{transform:translate(-50%,0);}50%{transform:translate(-50%,6px);}}

  @media (max-width:600px){
    .atmo-btn{font-size:0.68rem; padding:0.55rem 0.85rem;}
  }

  @media (prefers-reduced-motion: reduce){
    .scene-bg{animation:none;}
    /* scroll-settle.js checks this same query and disables itself, so a
       reduced-motion visitor is never moved by anything but their own input. */
  }

  /* ============================================================
     Game-composer restructure — hero positioning, adaptive-music
     framing, selected work, capabilities, credibility stats.
     ============================================================ */

  /* ---------- Gate identity ---------- */
  .gate-id{
    position:relative; z-index:1;
    text-align:center;
    margin-bottom:0.4rem;
  }
  .gate-id .label{ margin-bottom:0.7rem; }
  .gate-name{
    font-family:'Pixelify Sans', monospace;
    font-weight:700;
    font-size:clamp(2rem, 6vw, 3.2rem);
    line-height:1;
    color:var(--parchment);
    text-shadow:
      1px 1px 0 rgba(233,225,205,0.22),
      2px 2px 0 rgba(233,225,205,0.11);
  }
  .gate-role{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.78rem;
    letter-spacing:0.1em;
    text-transform:uppercase;
    color:var(--fog);
    margin-top:0.75rem;
  }
  @media (max-width:600px){
    .gate-role{ font-size:0.62rem; letter-spacing:0.06em; }
  }

  /* ---------- Hero value proposition + CTA ---------- */
  .hero-tagline{
    font-family:'IBM Plex Sans', sans-serif;
    font-size:clamp(0.95rem, 1.7vw, 1.15rem);
    line-height:1.6;
    color:#d7ddd6;
    max-width:46ch;
    margin:1rem auto 0;
  }
  .cue-caption{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.66rem;
    letter-spacing:0.14em;
    text-transform:uppercase;
    color:var(--fog);
    margin-top:1.6rem;
  }
  #atmoNav{ margin-top:0.7rem; }
  .hero-cta{ margin-top:1.5rem; }
  .hero-cta-btn{
    display:inline-block;
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.82rem;
    letter-spacing:0.08em;
    text-transform:uppercase;
    text-decoration:none;
    cursor:pointer;
    padding:0.85rem 1.9rem;
    transition:box-shadow 0.3s ease, transform 0.15s steps(1);
  }
  .hero-cta-btn.primary{
    background:var(--ember);
    color:var(--ink);
  }
  .hero-cta-btn.primary:hover{
    box-shadow:0 0 26px rgba(201,161,90,0.5);
  }
  /* Credits ticker — a single line that scrolls continuously, the strip
     never wraps and never crowds the hero. */
  .hero-proof{
    margin:1.9rem auto 0;
    max-width:min(560px, 84vw);
    overflow:hidden;
    -webkit-mask-image:linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
    mask-image:linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
  }
  .hero-proof-track{
    display:inline-flex;
    align-items:center;
    white-space:nowrap;
    /* No `will-change:transform` here on purpose. With it, Safari commits
       this animation to the compositor and then, the moment the hover rule
       below flips `animation-play-state` to paused, re-resolves the
       transform from a lagging main-thread clock — the strip visibly snaps
       backward a few frames. Without the hint the paused position matches
       the running one and the jump is gone. */
    animation:heroProofScroll 52s linear infinite; /* JS overrides the duration to hold a constant speed as the list grows; this is the slower fallback */
  }
  /* Pause-on-hover is done in JS (hero-ticker.js), not with
     `animation-play-state:paused` here — that made Safari snap the strip
     backward a few frames the instant the pause engaged. The JS version
     freezes on the live transform and resumes at the same phase. */
  .hero-proof-track span,
  .hero-proof-track a{
    flex:none;
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.62rem;
    letter-spacing:0.06em;
    text-transform:uppercase;
    color:var(--fog);
    opacity:0.8;
    text-decoration:none;
    transition:color 0.2s ease, opacity 0.2s ease;
    /* Silkscreen's glyphs sit above the tight line box, so a bare inline
       hit area misses the visible letters (you could only hover just
       under them). Pad the box out vertically and pull the layout back
       with a matching negative margin so the strip doesn't get taller. */
    padding-block:0.6em;
    margin-block:-0.6em;
  }
  .hero-proof-track .pri{
    color:var(--ember);
    opacity:1;
  }
  /* the strip pauses on hover (rule above), so a link can be aimed at */
  .hero-proof-track a:hover{
    color:var(--parchment);
    opacity:1;
  }
  .hero-proof-track span::after,
  .hero-proof-track a::after{
    content:'·';
    margin:0 1.4rem;
    opacity:0.4;
    color:var(--fog);
  }
  @keyframes heroProofScroll{
    /* translateZ(0) is baked into both keyframes so the strip keeps ONE
       stable compositing layer whether the animation is running or paused
       on hover — this is what stops Safari snapping it backward when the
       pause rule kicks in. */
    from{ transform:translateX(0) translateZ(0); }
    to{ transform:translateX(-50%) translateZ(0); }
  }
  @media (prefers-reduced-motion: reduce){
    .hero-proof{ overflow:visible; -webkit-mask-image:none; mask-image:none; }
    .hero-proof-track{ animation:none; white-space:normal; }
    .hero-proof-track .dup{ display:none; }
  }
  @media (max-width:600px){
    #hero{ height:auto; min-height:100vh; min-height:100svh; padding-top:5.5rem; padding-bottom:4rem; }
    .cue-caption{ margin-top:1.2rem; }
    .hero-proof{ max-width:88vw; }
  }

  /* ---------- Adaptive-music section framing ---------- */
  .stem-demo-section .stem-tech{
    font-family:'IBM Plex Mono', monospace;
    font-weight:400;
    font-size:0.8rem;
    letter-spacing:0.01em;
    color:var(--fog);
    opacity:0.8;
    margin:1.7rem auto 0;
    max-width:52ch;
    line-height:1.7;
  }

  /* ---------- Selected game work — carousel + per-project player ---------- */
  .work-carousel{
    margin-top:2rem;
    overflow:hidden;
  }
  .work-track{
    display:flex;
    transition:transform 0.55s cubic-bezier(.4, 0, .2, 1);
    will-change:transform;
  }
  @media (prefers-reduced-motion: reduce){
    .work-track{ transition:none; }
  }
  .work-card{
    flex:0 0 100%;
    min-width:0;
    padding:2.6rem 2rem;
    border:1px solid #fff;
    /* the faint warm wash is gone too — the card sits on plain black now */
    background:var(--ink);
  }
  .work-logo{
    height:42px; width:auto; max-width:220px;
    object-fit:contain;
    filter:brightness(0) invert(1);
    opacity:0.9;
    margin-bottom:1rem;
  }
  .work-status{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.56rem;
    letter-spacing:0.14em;
    text-transform:uppercase;
    color:var(--fog);
    opacity:0.75;
    margin-bottom:0.9rem;
  }
  .work-status::before{
    content:'';
    display:inline-block;
    width:6px; height:6px;
    border-radius:50%;
    background:var(--ember);
    margin-right:0.5rem;
    vertical-align:middle;
    animation:workDevPulse 2.4s ease-in-out infinite;
  }
  @keyframes workDevPulse{ 0%,100%{ opacity:0.35; } 50%{ opacity:1; } }
  @media (prefers-reduced-motion: reduce){ .work-status::before{ animation:none; } }
  .work-card h2{ margin:0 0 0.55rem; }
  .work-meta{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.68rem;
    letter-spacing:0.06em;
    text-transform:uppercase;
    color:var(--ember);
    margin-bottom:1rem;
  }
  .work-meta .dot{ opacity:0.5; margin:0 0.5rem; }
  .work-card p{ margin:0 auto; }

  .work-play{
    display:inline-flex;
    align-items:center;
    gap:0.55rem;
    margin-top:1.5rem;
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.66rem;
    letter-spacing:0.06em;
    text-transform:uppercase;
    color:var(--parchment);
    background:none;
    border:2px solid rgba(233,225,205,0.5);
    padding:0.6rem 1.1rem;
    cursor:pointer;
    transition:color 0.08s steps(1), border-color 0.08s steps(1), background 0.08s steps(1), opacity 0.3s ease;
  }
  .work-play:hover:not(:disabled){ color:var(--ink); background:var(--ember); border-color:var(--ember); }
  .work-play:disabled{ opacity:0.4; cursor:default; }
  .work-play.playing{ color:var(--ink); background:var(--ember); border-color:var(--ember); }
  .work-play .wp-icon{ font-size:0.85em; line-height:1; }

  .work-nav{
    display:flex;
    align-items:center;
    justify-content:center;
    gap:1rem;
    margin-top:1.3rem;
  }
  .work-nav-btn{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-size:0.85rem;
    color:var(--fog);
    background:none;
    border:none;
    cursor:pointer;
    padding:0.3rem 0.55rem;
    transition:color 0.15s steps(1), transform 0.12s ease;
  }
  .work-nav-btn:hover{ color:var(--ember); }
  .work-nav-btn:active{ transform:scale(0.88); }
  .work-dots{ display:flex; gap:0.5rem; }
  .work-dot{
    width:7px; height:7px;
    border:1px solid var(--fog);
    background:none;
    padding:0;
    cursor:pointer;
    transition:background 0.2s ease, border-color 0.2s ease;
  }
  .work-dot.on{ background:var(--ember); border-color:var(--ember); }

  /* ---------- What I can do ---------- */
  .services-section .services-lead{
    font-family:'IBM Plex Sans', sans-serif;
    font-size:1rem;
    line-height:1.65;
    color:#cfd9d2;
    max-width:52ch;
    margin:0.7rem auto 0;
  }
  /* Plain white rules. The 1px grid gap shows this background through as the
     dividing lines, so the grid colour and the border have to match. */
  .services-grid{
    display:grid;
    grid-template-columns:repeat(2, 1fr);
    gap:1px;
    margin-top:2.2rem;
    background:#fff;
    border:1px solid #fff;
  }
  .service{
    background:var(--ink);
    padding:1.9rem 1.6rem;
    text-align:left;
  }
  .service h3{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.8rem;
    letter-spacing:0.06em;
    text-transform:uppercase;
    color:var(--ember);
    margin-bottom:0.7rem;
  }
  .service p{
    font-family:'IBM Plex Sans', sans-serif;
    font-size:0.93rem;
    line-height:1.6;
    color:#cfd9d2;
    margin:0;
    max-width:none;
  }
  /* Five capabilities in a 2-wide grid would leave a dead sixth cell.
     Instead the last one spans the full width and centres itself —
     the grid reads as a deliberate 2 + 2 + 1 pyramid. */
  .services-grid > .service:last-child{
    grid-column:1 / -1;
    text-align:center;
  }
  .services-grid > .service:last-child p{
    max-width:46ch;
    margin-left:auto;
    margin-right:auto;
  }
  @media (max-width:600px){
    .services-grid{ grid-template-columns:1fr; }
    /* single column already — keep every card identical */
    .services-grid > .service:last-child{ text-align:left; }
    .services-grid > .service:last-child p{ max-width:none; margin:0; }
  }

  /* ---------- Credibility stats ---------- */
  .cred-stats{
    display:grid;
    grid-template-columns:repeat(2, 1fr);
    gap:1px;
    margin-top:2rem;
    background:#fff;
    border:1px solid #fff;
    text-align:left;
  }
  .cred-stat{
    background:var(--ink);
    padding:1.6rem 1.3rem;
  }
  .cred-stat .n{
    font-family:'Pixelify Sans', monospace;
    font-weight:700;
    font-size:1.05rem;
    line-height:1.25;
    color:var(--parchment);
  }
  .cred-stat .n a{
    color:inherit;
    text-decoration:none;
    border-bottom:1px solid rgba(201,161,90,0.45);
    transition:color 0.2s ease, border-color 0.2s ease;
  }
  .cred-stat .n a:hover{
    color:var(--ember);
    border-bottom-color:var(--ember);
  }
  .cred-stat .s{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.58rem;
    letter-spacing:0.05em;
    text-transform:uppercase;
    color:var(--fog);
    margin-top:0.5rem;
  }
  .credits-also{
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-weight:700;
    font-size:0.64rem;
    letter-spacing:0.14em;
    text-transform:uppercase;
    color:var(--fog);
    margin-top:2.6rem;
  }
  @media (max-width:600px){
    .cred-stats{ grid-template-columns:1fr; }
  }

  /* ---------- "Phone is on silent" nudge (iOS only, injected by JS) ---------- */
  #muteWarning{
    position:fixed;
    left:50%;
    bottom:1rem;
    transform:translate(-50%, calc(100% + 1.5rem));
    z-index:95;
    display:flex;
    align-items:center;
    gap:0.55rem;
    width:min(92vw, 30rem);
    padding:0.7rem 0.8rem;
    background:rgba(11,11,15,0.94);
    border:2px solid var(--ember);
    box-shadow:0 0 24px rgba(201,161,90,0.22), inset 0 1px 0 rgba(255,255,255,0.08);
    color:var(--parchment);
    font-family:'IBM Plex Sans', sans-serif;
    font-size:0.8rem;
    line-height:1.35;
    transition:transform 0.5s cubic-bezier(.2,.7,.2,1);
  }
  #muteWarning.show{ transform:translate(-50%, 0); }
  #muteWarning .mw-icon{ font-size:1.05rem; flex:none; }
  #muteWarning .mw-text{ flex:1 1 auto; }
  #muteWarning .mw-again{
    flex:none;
    font-family:'Silkscreen', 'Pixelify Sans', monospace;
    font-size:0.56rem;
    letter-spacing:0.05em;
    text-transform:uppercase;
    color:var(--ink);
    background:var(--ember);
    border:none;
    padding:0.45rem 0.55rem;
    cursor:pointer;
  }
  #muteWarning .mw-again:hover{ filter:brightness(1.1); }
  #muteWarning .mw-close{
    flex:none;
    background:transparent;
    border:none;
    color:var(--fog);
    font-size:0.85rem;
    line-height:1;
    padding:0.25rem 0.3rem;
    cursor:pointer;
  }
  #muteWarning .mw-close:hover{ color:var(--ember); }
  @media (prefers-reduced-motion: reduce){
    #muteWarning{ transition:none; }
  }
  /* While the nudge is up, lift the bottom-right cue nav above it and mute
     the decorative scroll hint so nothing sits under the banner. */
  body.mute-nudge-open #sceneNav{ transform:translateY(-6.9rem); } /* 8.5rem - 1.6rem, as a transform so it can't fight the URL bar */
  body.mute-nudge-open #scrollHint{ opacity:0; pointer-events:none; }
  @media (max-width:600px){
    body.mute-nudge-open #sceneNav{ transform:translateY(-7rem); } /* 8rem - 1rem */
  }
