/* Eight Worlds: tokens per world, the type, the layout, the stage framings, the choreography, the map.
   Each section.world is --len screens tall; its .pin sticks while the world plays. JS writes three numbers on
   every section: --t (0..1 through the pinned span), --e (0..1 as it rises in), --x (0..1 as it leaves). */

:root {
  --font-display: 'Fraunces', 'Iowan Old Style', Georgia, serif;
  --font-text: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;
  --gutter: clamp(16px, 4vw, 56px);
  --maxw: 1320px;
  --bg: #05060a; --ink: #e8fbf5; --muted: rgba(232, 251, 245, .62); --accent: #67f0d2; --accent2: #f3fff9; --line: rgba(232, 251, 245, .16);
}
[data-world="field"] { --bg: #03040b; --ink: #efeaff; --muted: rgba(239, 234, 255, .62); --accent: #b69cff; --accent2: #ff7ad9; --line: rgba(239, 234, 255, .16); }
[data-world="page"] { --bg: #05060a; --ink: #e8fbf5; --muted: rgba(232, 251, 245, .62); --accent: #67f0d2; --accent2: #f3fff9; --line: rgba(232, 251, 245, .16); }
[data-world="fieldplay3d"] { --bg: #06050a; --ink: #fff2e0; --muted: rgba(255, 242, 224, .62); --accent: #ff8a2a; --accent2: #ffd27a; --line: rgba(255, 242, 224, .16); }
[data-world="slay4k"] { --bg: #e9dfc6; --ink: #1d2a3a; --muted: rgba(29, 42, 58, .66); --accent: #e07a3c; --accent2: #3f5570; --line: rgba(29, 42, 58, .2); }
[data-world="counterintelligence"] { --bg: #0b0d10; --ink: #d8e6dc; --muted: rgba(216, 230, 220, .6); --accent: #f0a04b; --accent2: #4f8cff; --line: rgba(216, 230, 220, .16); }
[data-world="ledger"] { --bg: #07141d; --ink: #dff7f5; --muted: rgba(223, 247, 245, .6); --accent: #1fd1c3; --accent2: #e8c15a; --line: rgba(223, 247, 245, .16); }
[data-world="fretnot"] { --bg: #f6f1e6; --ink: #2b2b2b; --muted: rgba(43, 43, 43, .64); --accent: #9a5b1e; --accent2: #5a4632; --line: rgba(43, 43, 43, .18); }
[data-world="couchplay"] { --bg: #1f1927; --ink: #f4efe6; --muted: rgba(244, 239, 230, .62); --accent: #f2b45f; --accent2: #6fd0a8; --line: rgba(244, 239, 230, .16); }
[data-world="fretnot-phone"], #fretnot.night { --bg: #120e0b; --ink: #f6ecdc; --muted: rgba(246, 236, 220, .62); --accent: #f2a33a; --accent2: #ffd9a0; --line: rgba(246, 236, 220, .16); }
[data-world="learning"] { --bg: #f5f6f0; --ink: #1f2a26; --muted: rgba(31, 42, 38, .64); --accent: #274739; --accent2: #ff5a5f; --line: rgba(31, 42, 38, .18); }

* { box-sizing: border-box; }
html { scroll-behavior: auto; }
body { margin: 0; background: #05060a; color: var(--ink); font-family: var(--font-text); font-size: 16px; line-height: 1.55;
  -webkit-font-smoothing: antialiased; overflow-x: hidden; }
a { color: inherit; }
::selection { background: var(--accent); color: var(--bg); }

canvas#flow { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 0; display: block; }
canvas#planes { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 2; display: block; pointer-events: none; }
body:not(.gl-on) section.world { background: var(--bg); }
.gl-on .media { visibility: hidden; }            /* the GL plane draws the picture where the element sits */
.gl-on [data-dom] .media { visibility: visible; }  /* ... except in a frame that turns in 3D (data-dom: no plane) */

main { position: relative; z-index: 1; }
section.world { height: calc(var(--len, 1.8) * 100svh + var(--pinpx, 0px)); color: var(--ink); position: relative; }   /* --pinpx: a world sized in beats (main.js) */
.pin { position: sticky; top: 0; height: 100svh; display: grid; place-items: center; padding: 72px var(--gutter) 96px; }
.inner { width: min(100%, var(--maxw)); display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(28px, 5vw, 80px); align-items: center; }
.world.flip .inner { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
.world.flip .copy { order: 2; }

/* ---------- copy */
.eyebrow { font-family: var(--font-mono); font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--accent); margin: 0 0 14px; text-wrap: balance; }
h2 { font-family: var(--font-display); font-weight: 500; font-size: clamp(36px, 4.2vw, 62px); line-height: 1.02; letter-spacing: -.015em; margin: 0 0 18px;
  font-variation-settings: 'opsz' 96, 'SOFT' 40, 'WONK' 1; }
.what { font-size: clamp(16px, 1.25vw, 19px); margin: 0 0 12px; }
.hard { color: var(--muted); font-size: 15px; margin: 0 0 20px; }
.chips { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.chips li { font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .06em; text-transform: uppercase; padding: 7px 11px; border: 1px solid var(--line);
  border-radius: 999px; color: var(--ink); background: color-mix(in srgb, var(--bg) 55%, transparent); backdrop-filter: blur(6px); }
.chips a { text-decoration: none; border-bottom: 1px solid var(--accent); }
.chips a:hover { color: var(--accent); }
.chips a.web { display: inline-flex; align-items: center; gap: 6px; }
.chips a.web svg { width: 12px; height: 12px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.2; opacity: .85; }

/* wipes: each line of copy clips in from the left when its world is on screen */
.copy > * { clip-path: inset(0 100% 0 0); opacity: 0; transition: clip-path .75s cubic-bezier(.2, .7, .2, 1), opacity .5s; }
.world.in .copy > * { clip-path: inset(0 -2% 0 0); opacity: 1; }
.copy > :nth-child(2) { transition-delay: .07s; } .copy > :nth-child(3) { transition-delay: .14s; }
.copy > :nth-child(4) { transition-delay: .21s; } .copy > :nth-child(5) { transition-delay: .28s; }

/* ---------- hero: the word in the top half (the particles write it: gl/word3d.js, placed by main.js placeWord), the
   tagline at the seam, the code rain in the bottom half */
#field .pin { display: block; padding: 0; overflow: hidden; }
/* the code rain fills the bottom half of the opening from the start; as the opening leaves it rises over the whole
   screen, then clears to show fieldplay3D (main.js sets --show, --rise and --clear, 0..1). Over the particles, under
   the words */
canvas.rain { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 0; display: block; pointer-events: none;
  --top: calc(48% * (1 - var(--rise, 0))); opacity: calc(var(--show, 0) * (1 - var(--clear, 1)));
  -webkit-mask-image: linear-gradient(to bottom, transparent var(--top), #000 calc(var(--top) + 14%), #000 92%, transparent 100%);
          mask-image: linear-gradient(to bottom, transparent var(--top), #000 calc(var(--top) + 14%), #000 92%, transparent 100%); }
/* the tagline's foot sits on the middle of the screen; without WebGL the page's own "Keyz" stands over it, filling
   the top half. Fixed, as the word and the rain are: the opening is one screen and scrolls away at once, and the words
   fade (--x) as the letters crash into the rain instead of sliding off with the page */
.hero { position: fixed; left: 0; right: 0; bottom: calc(50% - 4px); margin: 0 auto; padding: 0 var(--gutter); max-width: 1100px; text-align: center;
  opacity: calc(1 - var(--x, 0) * 3); pointer-events: none; }
#field.gone .hero { visibility: hidden; }            /* faded out (main.js): nothing of it may catch a click over the next worlds */
/* the tour's invitation (scroll.js tour), small and quiet over the tagline, in the display face's italic: a click starts
   the page scrolling itself (a pause mark while it does) */
.tour-go { display: inline-flex; align-items: center; gap: 7px; margin: 0 0 4px; padding: 3px 6px; border: 0; background: none; cursor: pointer; pointer-events: auto;
  font: italic 300 15px/1.4 var(--font-display); font-variation-settings: 'opsz' 14, 'SOFT' 100; letter-spacing: .01em; color: rgba(239, 234, 255, .5);
  transition: color .3s; }
.tour-go svg { width: 9px; height: 9px; fill: var(--accent); opacity: .55; transition: transform .3s, opacity .3s; }
.tour-go .stop, .tour-go[aria-pressed="true"] .go { display: none; }
.tour-go[aria-pressed="true"] .stop { display: inline; }
.tour-go:hover, .tour-go:focus-visible { color: rgba(239, 234, 255, .92); outline: none; }
.tour-go:hover svg, .tour-go:focus-visible svg { opacity: 1; transform: translateX(2px); }
.tour-go:focus-visible { text-decoration: underline; text-decoration-color: var(--accent); text-underline-offset: 4px; }
.gl-on .hero .name { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }   /* the particles write it */
@media (prefers-reduced-motion: no-preference) { body:not(.gl-on) .hero .name { animation: keyz-float 9s ease-in-out infinite; } }   /* the particles' word floats in main.js */
@keyframes keyz-float { 0%, 100% { transform: translateY(0) rotate(-1.4deg); } 50% { transform: translateY(-7px) rotate(1.4deg); } }
.hero .name { font-family: var(--font-display); font-weight: 500; font-size: clamp(48px, 9vw, 170px); line-height: .95; letter-spacing: -.03em; margin: 0 0 .12em;
  font-variation-settings: 'opsz' 144, 'SOFT' 60, 'WONK' 1; color: #ff8a2a; text-shadow: 0 0 40px rgba(255, 106, 0, .3), 0 0 2px rgba(255, 106, 0, .55); }
.hero .tag { font-size: clamp(18px, 2vw, 26px); font-weight: 300; color: rgba(239, 234, 255, .86); margin: 0; letter-spacing: .005em; }
.hero .tag b { font-weight: 500; color: var(--accent); }
/* the chevron at the foot of the opening: a thin stroke that breathes downward */
.hint { position: absolute; left: 50%; bottom: 84px; transform: translateX(-50%); color: var(--muted); line-height: 0; }
.hint svg { width: 26px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round;
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--accent) 45%, transparent)); animation: nudge 2.2s ease-in-out infinite; }
@keyframes nudge { 0%, 100% { transform: translateY(0); opacity: .55 } 50% { transform: translateY(7px); opacity: 1 } }

/* ---------- stages */
.stage { position: relative; min-width: 0; }
.frame { position: relative; width: 100%; aspect-ratio: 16 / 9; margin: 0; }
.media { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: inherit; display: block; background: #000; }
.frame figcaption { position: absolute; left: 0; right: 0; bottom: -30px; font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }

/* the void: just a lit rectangle in the dark */
.frame--void { border-radius: 18px; box-shadow: 0 0 0 1px rgba(255, 255, 255, .07), 0 30px 90px rgba(0, 0, 0, .7), 0 0 120px rgba(255, 138, 42, .12); }

/* parchment: a torn sheet, slightly askew, the picture inked onto it */
.frame--parchment { aspect-ratio: auto; padding: 22px 22px 30px; transform: rotate(-1.4deg); filter: drop-shadow(0 18px 30px rgba(29, 42, 58, .28));
  background: linear-gradient(160deg, #f1e8d2, #e3d6b8 55%, #d9c9a5); clip-path: polygon(0.8% 1.6%, 7% 0.4%, 14% 1.9%, 22% 0.2%, 31% 1.5%, 40% 0.6%, 49% 1.8%, 58% 0.3%, 67% 1.6%, 76% 0.5%, 85% 1.7%, 93% 0.4%, 99.4% 1.9%, 98.9% 11%, 99.6% 23%, 98.7% 35%, 99.5% 48%, 98.8% 61%, 99.6% 73%, 98.9% 86%, 99.4% 98.3%, 92% 99.6%, 83% 98.2%, 73% 99.7%, 62% 98.4%, 52% 99.5%, 41% 98.3%, 30% 99.6%, 19% 98.4%, 9% 99.5%, 0.7% 98.1%, 1.3% 86%, 0.4% 73%, 1.4% 61%, 0.5% 48%, 1.5% 35%, 0.6% 23%, 1.3% 11%); }
.frame--parchment .pic { position: relative; aspect-ratio: 16 / 9; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(29, 42, 58, .25); }
.frame--parchment .pic .media { border-radius: 3px; }
.frame--parchment .rubric { display: flex; justify-content: space-between; gap: 14px; margin-top: 12px; font-family: var(--font-mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: #3f5570; }
.stage--slay4k .frame--second { position: absolute; right: -4%; bottom: -14%; width: 44%; transform: rotate(2.2deg); z-index: 2; }

/* the dossier: a monospace strip, a screen with a bar, the replay card tucked behind */
.frame--screen { border-radius: 10px; background: #15181d; padding: 8px; box-shadow: 0 0 0 1px rgba(216, 230, 220, .12), 0 30px 80px rgba(0, 0, 0, .7); aspect-ratio: auto; }
.frame--screen .bar { display: flex; justify-content: space-between; align-items: center; font-family: var(--font-mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: #9fb4a6; padding: 2px 6px 8px; }
.frame--screen .bar b { color: var(--accent); font-weight: 600; }
.frame--screen .bar i { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: #ff4d4d; margin-right: 6px; box-shadow: 0 0 8px #ff4d4d; animation: rec 1.6s steps(1) infinite; }
@keyframes rec { 50% { opacity: .25 } }
.frame--screen .pic { position: relative; aspect-ratio: 16 / 9; border-radius: 5px; overflow: hidden; }
.stage--ci .frame--dossier { position: absolute; left: -6%; bottom: -16%; width: 42%; aspect-ratio: 1440 / 1100; border-radius: 8px; z-index: 2;
  box-shadow: 0 0 0 1px rgba(216, 230, 220, .16), 0 24px 60px rgba(0, 0, 0, .7); background: #0b0d10; transform: rotate(-2deg); }
.stage--ci .frame--dossier .tab { position: absolute; top: -22px; left: 14px; font-family: var(--font-mono); font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--bg);
  background: var(--accent); padding: 5px 10px; border-radius: 4px 4px 0 0; }

/* a trailer (js/worlds/trailer.js): the poster and a Play pill, then the video with its own controls and sound */
.trailer .pic { position: relative; overflow: hidden; background: #000; }
.trailer-v { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; background: #000; border-radius: inherit; }
.trailer.playing .trailer-v { object-fit: contain; }
.trailer-go { position: absolute; left: 14px; bottom: 14px; z-index: 1; display: inline-flex; align-items: center; gap: 9px; height: 38px; padding: 0 15px 0 13px;
  border: 0; border-radius: 999px; cursor: pointer; font: 600 13.5px/1 var(--font-text); color: #fff; background: rgba(8, 10, 14, .66);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); box-shadow: 0 0 0 1px rgba(255, 255, 255, .16), 0 10px 26px rgba(0, 0, 0, .45);
  transition: background .2s, transform .2s; }
.trailer-go:hover, .trailer-go:focus-visible { background: rgba(8, 10, 14, .86); transform: translateY(-1px); }
.trailer-go svg { width: 12px; height: 12px; fill: currentColor; }
.trailer-go .len { font: 500 11px/1 var(--font-mono); letter-spacing: .08em; color: rgba(255, 255, 255, .6); }
.trailer.playing .trailer-go, .trailer[data-notrailer] .trailer-go { display: none; }
.trailer[data-notrailer] [data-trailer-only] { display: none; }   /* no trailer here: no words about one */
.stage--slay4k .frame--second { transition: opacity .35s ease; }
#slay4k.watching .frame--second { opacity: 0; pointer-events: none; }

/* CounterIntelligence: the radar card is the real replay (js/worlds/ci.js, the viewer in js/vendor/ci). At rest it is a
   live map and nothing else (a click opens it); the screening (.watching) puts it beside the trailer, condensed: the
   round, the map, the transport. No pen, no GIF, no Big view, no 3D, no side panel (the app has those) */
.stage--ci .trailer-go { left: auto; right: 14px; }
.stage--ci .ci-replay { aspect-ratio: auto; width: 32%; bottom: -32%; padding: 7px; }
.ci-replay .ci-rp { min-height: 60px; }
.ci-replay[data-failed] { display: none; }
.ci-replay .rp { --font: var(--font-text); --font-d: var(--font-text); --mono: var(--font-mono); gap: 8px; font-size: 12.5px; }
.ci-replay .rp-stage { border-radius: 6px; }
.ci-open { position: absolute; inset: 0; z-index: 4; border: 0; padding: 0; background: none; cursor: pointer; border-radius: inherit; }
.ci-open:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.frame .ci-cap { position: static; display: flex; align-items: baseline; gap: 10px; margin: 7px 2px 1px; font: 500 10.5px/1.3 var(--font-mono); letter-spacing: .1em; text-transform: uppercase; color: var(--muted); white-space: nowrap; overflow: hidden; }
.ci-cap b { color: var(--ink); font-weight: 600; }
.ci-cap a { margin-left: auto; color: var(--muted); text-decoration: none; display: none; }
.ci-cap a:hover { color: var(--accent); }
#counterintelligence:not(.watching) .ci-replay .rp > :not(.rp-view),
#counterintelligence:not(.watching) .ci-replay :is(.rp-tools, .rp-feed, .rp-card, .rp-menu, .rp-tip) { display: none; }
.ci-replay :is(.rp-side, .rp-gif, .rp-3d, .rp-pen, .rp-sep, .rp-floor),
.ci-replay .rp-ib:is([aria-label="Draw on the map"], [aria-label="Erase drawings"], [aria-label^="Undo drawing"], [aria-label="Clear drawings"], [aria-label="Make a GIF clip"], [aria-label="Big view"]) { display: none; }
.ci-close { display: none; }
@media (min-width: 961px) {
  #counterintelligence { --rpw: min(470px, 35vw, calc(100svh - 350px)); }
  #counterintelligence .copy { transition: opacity .3s ease; }
  #counterintelligence.watching .copy { position: absolute; opacity: 0; visibility: hidden; pointer-events: none; }
  #counterintelligence.watching .inner { grid-template-columns: minmax(0, 1fr); }
  #counterintelligence.watching .stage--ci { display: grid; grid-template-columns: minmax(0, 1fr) var(--rpw); gap: 30px; align-items: center; transform: none; }
  #counterintelligence.watching .stage--ci .frame { transform: none; }
  #counterintelligence.watching .ci-replay { position: relative; left: auto; bottom: auto; width: auto; padding: 12px 12px 8px; border-radius: 10px; }
  #counterintelligence.watching .ci-open { display: none; }
  #counterintelligence.watching .ci-cap a { display: inline; }
  #counterintelligence.watching .ci-close { display: grid; place-items: center; position: absolute; right: -6px; top: -50px; width: 34px; height: 34px; padding: 0;
    border: 0; border-radius: 50%; cursor: pointer; color: var(--ink); background: rgba(255, 255, 255, .06); box-shadow: 0 0 0 1px var(--line); }
  #counterintelligence.watching .ci-close:hover { background: rgba(255, 255, 255, .12); }
  .ci-close svg { width: 11px; height: 11px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; }
}

/* hextech glass: gold edges, notched corners, teal light inside */
.stage--ledger { display: grid; grid-template-columns: 1fr 1.25fr; gap: 18px; align-items: end; }
.frame--glass { aspect-ratio: auto; padding: 10px; background: linear-gradient(180deg, rgba(31, 209, 195, .10), rgba(7, 20, 29, .6)); border: 1px solid rgba(232, 193, 90, .55);
  clip-path: polygon(14px 0, calc(100% - 14px) 0, 100% 14px, 100% calc(100% - 14px), calc(100% - 14px) 100%, 14px 100%, 0 calc(100% - 14px), 0 14px);
  box-shadow: inset 0 0 40px rgba(31, 209, 195, .12); }
.frame--glass .pic { position: relative; overflow: hidden; }
.frame--glass.labels .pic { aspect-ratio: 1440 / 1000; }
.frame--glass.board .pic { aspect-ratio: 1140 / 906; }
.frame--glass .cap { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--accent2); padding: 9px 4px 2px; display: flex; justify-content: space-between; }

/* paper: cream, a shadow, the staff lines running in from the left edge */
.frame--paper { aspect-ratio: 1150 / 950; background: #fbf7ee; border-radius: 4px; box-shadow: 0 1px 0 rgba(0, 0, 0, .06), 0 24px 60px rgba(43, 43, 43, .22); padding: 12px; }
.frame--paper::before { content: ''; position: absolute; left: -60px; top: 12%; width: 60px; height: 44px;
  background: repeating-linear-gradient(to bottom, rgba(43, 43, 43, .55) 0 1px, transparent 1px 10px); opacity: .5; }
.frame--paper .pic { position: relative; width: 100%; height: 100%; overflow: hidden; }

/* learning: two cards, one soft, one ruled */
.stage--learning { display: grid; grid-template-columns: 1.1fr 1fr; gap: 20px; align-items: center; }
.frame--card { aspect-ratio: 1016 / 990; border-radius: 14px; background: #fff; box-shadow: 0 1px 0 rgba(0, 0, 0, .05), 0 20px 50px rgba(31, 42, 38, .18); padding: 8px; }
.frame--card .pic { position: relative; width: 100%; height: 100%; border-radius: 8px; overflow: hidden; }
.frame--ruled { aspect-ratio: 1100 / 760; border-radius: 10px; padding: 8px; background: #fcfdff; box-shadow: 0 1px 0 rgba(0, 0, 0, .05), 0 20px 50px rgba(31, 42, 38, .18); transform: rotate(1.6deg); }
.frame--ruled .pic { position: relative; width: 100%; height: 100%; border-radius: 6px; overflow: hidden; }

/* ---------- the end: "Contact me" drifting round the screen (js/worlds/contact.js moves it; colour changes at each bounce) */
.page .pin { display: block; overflow: hidden; }
.dodge { position: absolute; left: 0; top: 0; will-change: transform; white-space: nowrap; font-family: var(--font-display);
  font-size: clamp(30px, 4.2vw, 60px); line-height: 1.1; letter-spacing: -.01em; text-decoration: underline;
  text-decoration-thickness: .055em; text-underline-offset: .16em; transition: color .35s; }

/* ---------- the map */
.map { position: fixed; left: 50%; bottom: 14px; transform: translateX(-50%); width: min(600px, 94vw); z-index: 5; color: var(--ink); }
.map svg { width: 100%; height: auto; display: block; overflow: visible; }
.map .road { fill: none; stroke: var(--ink); stroke-opacity: .32; stroke-width: 1.2; stroke-dasharray: 3 5; stroke-linecap: round; }
.map .inked { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linecap: round; transition: stroke .4s; }
.map .node .halo { fill: var(--accent); opacity: 0; transition: opacity .35s; }
.map .node .disc { fill: var(--bg); stroke: var(--ink); stroke-opacity: .55; stroke-width: 1.2; transition: fill .35s, stroke .35s; }
.map .node .glyph { fill: none; stroke: var(--ink); stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; transition: stroke .35s; }
.map .node.on .halo { opacity: .22; animation: halo 2.4s ease-in-out infinite; }
.map .node.on .disc { fill: var(--accent); stroke: var(--accent); }
.map .node.on .glyph { stroke: var(--bg); }
@keyframes halo { 50% { transform: scale(1.35); opacity: .08 } }
.map .node { transform-box: fill-box; transform-origin: center; }
.map .node .halo { transform-box: fill-box; transform-origin: center; }
.mapbtns { position: absolute; inset: 0; }
.mapbtns button { position: absolute; top: 50%; width: 30px; height: 30px; margin: -15px 0 0 -15px; border: 0; border-radius: 50%; background: transparent; cursor: pointer; }
.mapbtns button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.maplabel { position: absolute; left: 50%; top: -22px; transform: translateX(-50%); font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); white-space: nowrap; }

/* ---------- the sound switch (js/sound.js): a speaker that mutes the whole site; hovering it (or focusing it) opens a
   volume slider under it, without moving anything around it */
.snd { position: relative; display: inline-flex; align-items: center; }
.snd-btn svg .spk { fill: currentColor; }
.snd-btn svg .wave, .snd-btn svg .mute { transition: opacity .2s; }
.snd:not(.on) .snd-btn svg .wave { opacity: 0; }
.snd.on .snd-btn svg .mute { opacity: 0; }
.snd-pop { position: absolute; top: 100%; left: 50%; padding-top: 8px; transform: translate(-50%, -4px); opacity: 0; pointer-events: none; transition: opacity .18s, transform .18s; z-index: 2; }
.snd:hover .snd-pop, .snd:focus-within .snd-pop { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
.snd-vol { -webkit-appearance: none; appearance: none; display: block; width: 112px; height: 28px; margin: 0; padding: 0 12px; border-radius: 999px; cursor: pointer;
  background: rgba(16, 14, 12, .8); box-shadow: 0 0 0 1px rgba(244, 239, 230, .16); backdrop-filter: blur(6px); }
.snd-vol:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.snd-vol::-webkit-slider-runnable-track { height: 3px; border-radius: 2px; background: linear-gradient(to right, var(--accent) calc(var(--vol, .7) * 100%), rgba(244, 239, 230, .25) 0); }
.snd-vol::-webkit-slider-thumb { -webkit-appearance: none; width: 12px; height: 12px; margin-top: -4.5px; border-radius: 50%; background: #f4efe6; box-shadow: 0 1px 3px rgba(0, 0, 0, .5); }
.snd-vol::-moz-range-track { height: 3px; border-radius: 2px; background: rgba(244, 239, 230, .25); }
.snd-vol::-moz-range-progress { height: 3px; border-radius: 2px; background: var(--accent); }
.snd-vol::-moz-range-thumb { width: 12px; height: 12px; border: 0; border-radius: 50%; background: #f4efe6; }
.top-r { display: inline-flex; align-items: center; gap: 20px; }
.top-snd .snd-btn { display: inline-flex; align-items: center; gap: 7px; padding: 4px 10px; margin: 0 -10px; border: 1px solid transparent; border-radius: 999px;
  background: none; color: inherit; cursor: pointer; font: inherit; letter-spacing: inherit; text-transform: inherit;
  transition: color .4s, border-color .3s, background .3s, box-shadow .3s; }
.top-snd .snd-btn:hover { color: var(--accent); }
/* unmuted: lit, a pill in the world's accent; on but still waiting for the first click or key, it pulses */
.top-snd.on .snd-btn { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 60%, transparent);
  background: color-mix(in srgb, var(--accent) 14%, transparent); box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 35%, transparent); }
.snd.blocked .snd-btn { animation: snd-wait 1.4s ease-in-out infinite; }
@keyframes snd-wait { 50% { box-shadow: 0 0 22px color-mix(in srgb, var(--accent) 70%, transparent); border-color: var(--accent); } }
@media (prefers-reduced-motion: reduce) { .snd.blocked .snd-btn { animation: none; } }
.top-snd svg { width: 15px; height: 15px; }
.top-snd .snd-pop { left: auto; right: -10px; transform: translateY(-4px); }
.top-snd:hover .snd-pop, .top-snd:focus-within .snd-pop { transform: none; }

/* ---------- the achievements (js/achievements.js): the tab in the top line, the glass menu over the centre third of the
   screen, the toast when one unlocks. Snow Leopard's glossy Aqua (the horizon highlight, gel badges, the striped candy
   progress bar, graphite for what is still to find) in today's fluid glass (clear and saturated, a lens that bends the
   page at the rim, a light that follows the pointer, a shape that flows out of the tab). The menu's own colours stay
   the same in every world: system glass over whatever is behind it */
.ach-tab { position: relative; display: inline-flex; align-items: center; gap: .55em; height: 26px; margin: -4px 0; padding: 0 12px; border: 0; border-radius: 13px;
  cursor: pointer; font: inherit; letter-spacing: inherit; text-transform: inherit; color: var(--ink); white-space: nowrap;
  background: linear-gradient(to bottom, rgba(255, 255, 255, .26), rgba(255, 255, 255, .1) 50%, rgba(255, 255, 255, .03) 50%, rgba(255, 255, 255, .09));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), inset 0 0 0 1px rgba(255, 255, 255, .16), 0 2px 10px rgba(0, 0, 0, .22);
  -webkit-backdrop-filter: blur(8px) saturate(1.6); backdrop-filter: blur(8px) saturate(1.6); transition: color .4s, box-shadow .2s; }
.ach-tab:hover, .ach-tab[aria-expanded="true"] { box-shadow: inset 0 1px 0 rgba(255, 255, 255, .62), inset 0 0 0 1px rgba(255, 255, 255, .3), 0 2px 14px rgba(0, 0, 0, .3); }
.ach-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.top .ach-tab .ach-n { color: var(--muted); transition: color .4s; }
.top .ach-tab.some .ach-n { color: var(--accent); }
.ach-tab.got { animation: ach-got 1.2s ease-out; }
@keyframes ach-got {
  0% { transform: scale(1); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .6), inset 0 0 0 1px rgba(255, 255, 255, .3), 0 0 0 0 rgba(79, 155, 240, .8); }
  18% { transform: scale(1.08); }
  100% { transform: scale(1); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), inset 0 0 0 1px rgba(255, 255, 255, .16), 0 0 0 16px rgba(79, 155, 240, 0); }
}

.ach, .ach-toast { --tint: rgba(20, 22, 30, .48); }
.ach[data-light], .ach-toast[data-light] { --tint: rgba(14, 16, 24, .7); }
.ach { position: fixed; z-index: 30; left: 0; top: 0; width: 480px; height: 320px; border-radius: 26px; overflow: hidden; color: #f3f5fa;
  font-family: var(--font-text); box-shadow: 0 30px 80px rgba(0, 0, 0, .42), 0 6px 18px rgba(0, 0, 0, .28); }
.ach[hidden] { display: none; }
.ach:focus { outline: none; }
.ach-lens, .ach-rim, .ach-gloss { position: absolute; inset: 0; border-radius: inherit; pointer-events: none; }
/* the glass: in the middle what is behind is frosted (blurred, saturated, a little brighter, under a smoky tint) so the
   words read; at the rim it is clear and bent, through a lens made for the panel's size (an SVG displacement map and a
   soft ring, js/achievements.js), which comes in once the panel has settled */
.ach-lens { background: var(--tint); -webkit-backdrop-filter: blur(14px) saturate(1.8) brightness(1.1); backdrop-filter: blur(14px) saturate(1.8) brightness(1.1); }
.ach-rim { display: none; opacity: 0; transition: opacity .3s; -webkit-backdrop-filter: blur(1px) saturate(1.9) brightness(1.18); backdrop-filter: blur(1px) saturate(1.9) brightness(1.18); }
.ach.lensed .ach-rim { display: block; opacity: 1; filter: var(--lens, none); }
@starting-style { .ach.lensed .ach-rim { opacity: 0; } }
.ach-gloss {
  background:
    radial-gradient(340px 240px at var(--mx, 50%) var(--my, -30%), rgba(255, 255, 255, .14), transparent 70%),
    linear-gradient(to bottom, rgba(255, 255, 255, .22), rgba(255, 255, 255, .07) 54px, rgba(255, 255, 255, 0) 55px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55), inset 0 -1px 0 rgba(255, 255, 255, .12), inset 0 0 0 1px rgba(255, 255, 255, .08); }
.ach-gloss::before { content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1.2px;   /* the specular rim */
  background: linear-gradient(155deg, rgba(255, 255, 255, .85), rgba(255, 255, 255, .14) 28%, rgba(255, 255, 255, .04) 62%, rgba(255, 255, 255, .45));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude; }
.ach-body { position: relative; box-sizing: border-box; display: flex; flex-direction: column; height: 100%; padding: 14px 20px 16px; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; }
.ach-head { display: flex; align-items: center; justify-content: space-between; height: 26px; }
.ach-head h2 { margin: 0; font-family: var(--font-text); font-size: 15px; font-weight: 600; letter-spacing: .01em; line-height: 1; text-shadow: 0 -1px 0 rgba(0, 0, 0, .5); }
.ach-count { font-family: var(--font-mono); font-size: 12px; letter-spacing: .12em; color: rgba(243, 245, 250, .78); }
.ach-bar { --p: 0; position: relative; height: 12px; margin: 15px 0 14px; border-radius: 6px; overflow: hidden;
  background: linear-gradient(to bottom, rgba(0, 0, 0, .42), rgba(255, 255, 255, .07)); box-shadow: inset 0 1px 2px rgba(0, 0, 0, .55), 0 1px 0 rgba(255, 255, 255, .12); }
.ach-bar i { position: absolute; left: 0; top: 0; bottom: 0; width: calc(var(--p) * 100%); border-radius: inherit; transition: width .9s cubic-bezier(.2, .9, .3, 1);
  background:
    linear-gradient(to bottom, rgba(255, 255, 255, .72), rgba(255, 255, 255, .22) 50%, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, .2)),
    repeating-linear-gradient(-45deg, #1f6fd6 0 7px, #4f9bf0 7px 14px);
  background-size: 100% 100%, 39.6px 100%; animation: ach-candy .9s linear infinite; }
@keyframes ach-candy { to { background-position: 0 0, 39.6px 0; } }
.ach-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.ach-list li { display: grid; grid-template-columns: 44px 1fr auto; align-items: center; gap: 14px; padding: 10px 12px; border-radius: 15px;
  background: linear-gradient(to bottom, rgba(255, 255, 255, .08), rgba(255, 255, 255, .025)); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .13), inset 0 0 0 1px rgba(255, 255, 255, .05); }
.ach-text b { display: block; font-size: 14.5px; font-weight: 600; text-shadow: 0 -1px 0 rgba(0, 0, 0, .45); }
.ach-text span { display: block; margin-top: 2px; font-size: 12.5px; line-height: 1.38; color: rgba(243, 245, 250, .68); }
.ach-state { font-family: var(--font-mono); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; padding: 4px 9px; border-radius: 999px;
  color: rgba(243, 245, 250, .62); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .18); }
.ach-list li.got .ach-state { color: #fff; background: linear-gradient(to bottom, #6ab4fb, #2a78dc 50%, #1d68cf 50%, #3d8ef0); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), 0 1px 3px rgba(0, 0, 0, .4); }
.ach-foot { margin: auto 2px 0; padding-top: 14px; font-size: 12px; color: rgba(243, 245, 250, .55); }
.ach-left { color: rgba(243, 245, 250, .85); }
/* gel badges: graphite while still to find, Aqua blue once found */
.ach-badge { position: relative; display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; color: #fff;
  background: radial-gradient(circle at 50% 115%, #cdd5de 0, #8e98a5 36%, #4b535e 72%, #2c3138 100%);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .42), inset 0 -5px 9px rgba(255, 255, 255, .2), 0 2px 6px rgba(0, 0, 0, .4); }
.ach-badge::after { content: ''; position: absolute; left: 13%; right: 13%; top: 5%; height: 46%; border-radius: 50% 50% 46% 46% / 72% 72% 28% 28%;
  background: linear-gradient(to bottom, rgba(255, 255, 255, .86), rgba(255, 255, 255, .1)); pointer-events: none; }
.ach-badge svg { width: 22px; height: 22px; filter: drop-shadow(0 -1px 0 rgba(0, 0, 0, .35)); }
.ach-list li:not(.got) .ach-badge svg { opacity: .7; }
.ach-list li.got .ach-badge, .ach-toast .ach-badge { background: radial-gradient(circle at 50% 115%, #a6d6ff 0, #3f90f2 36%, #1653c0 74%, #0b3486 100%);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .38), inset 0 -5px 9px rgba(160, 215, 255, .5), 0 2px 6px rgba(0, 0, 0, .35), 0 0 16px rgba(79, 155, 240, .45); }

.ach-toasts { position: fixed; z-index: 31; top: 62px; left: 0; right: 0; display: flex; justify-content: center; pointer-events: none; }
.ach-toast { display: inline-flex; align-items: center; gap: 12px; padding: 7px 20px 7px 7px; border-radius: 999px; color: #f3f5fa; font-family: var(--font-text);
  background: linear-gradient(to bottom, rgba(255, 255, 255, .22), rgba(255, 255, 255, .07) 50%, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, .06)), var(--tint);
  -webkit-backdrop-filter: blur(14px) saturate(1.8) brightness(1.1); backdrop-filter: blur(14px) saturate(1.8) brightness(1.1);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55), inset 0 0 0 1px rgba(255, 255, 255, .12), 0 14px 40px rgba(0, 0, 0, .4); }
.ach-toast[hidden] { display: none; }
.ach-toast .ach-badge { width: 38px; height: 38px; }
.ach-toast .ach-badge svg { width: 19px; height: 19px; }
.ach-tt em { display: block; font-style: normal; font-family: var(--font-mono); font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: #9cc9ff; }
.ach-tt b { display: block; margin-top: 1px; font-size: 14.5px; font-weight: 600; text-shadow: 0 -1px 0 rgba(0, 0, 0, .45); }
.ach-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
body.idle .ach *, body.idle .hero .name, body.idle .hint svg, body.idle .map .node.on .halo, body.idle .frame--screen .bar i,
body.idle .tour .caret { animation-play-state: paused !important; }   /* the loops reduced motion stops: none run while idle */
@media (prefers-reduced-motion: reduce) { .ach-bar i { animation: none; transition: none; } }

/* ---------- the top line */
.top { position: fixed; top: 0; left: 0; right: 0; z-index: 5; display: flex; justify-content: space-between; align-items: center; padding: 18px var(--gutter);
  font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); pointer-events: none;
  transition: color .4s; }
.top .brand, .top a { transition: color .4s; }
.top a, .top span { pointer-events: auto; text-decoration: none; color: inherit; }
.top a:hover { color: var(--accent); }
.top .brand { color: var(--ink); }

/* ---------- fieldplay3D: the live attractor and its code card */
.stage--fp3d .frame--void { aspect-ratio: 4 / 3; background: #030205; }
/* its scrollbar, in the gap between the words and the player and as tall as the player. The page holds still here
   while the attractors change, so this shows the scroll is doing something: the thumb runs the whole track once per
   function and the next comes in behind it (js/worlds/fieldplay3d.js sets --f and --g, where each thumb is, 0..1) */
.fp-scroll { --f: 0; --g: 9; position: absolute; top: 0; bottom: 0; left: calc(clamp(28px, 5vw, 80px) / -2 - 3px); width: 6px; border-radius: 3px; overflow: hidden;
  background: linear-gradient(to right, rgba(255, 255, 255, .04), rgba(255, 255, 255, .1), rgba(255, 255, 255, .04)); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .05);
  -webkit-mask-image: linear-gradient(transparent, #000 8%, #000 92%, transparent); mask-image: linear-gradient(transparent, #000 8%, #000 92%, transparent); }
.fp-scroll i { position: absolute; left: 0; right: 0; top: 0; height: 26%; border-radius: 3px; will-change: transform; transition: background .4s;
  background: linear-gradient(to right, color-mix(in srgb, var(--tour) 70%, #000), var(--tour) 45%, color-mix(in srgb, var(--tour) 55%, #fff));
  transform: translateY(calc((var(--f) / .26 - .5) * 100%)); }
.fp-scroll i + i { transform: translateY(calc((var(--g) / .26 - .5) * 100%)); }
/* a new function: the background flashes once, softly, in its colour (js/worlds/fieldplay3d.js) */
.fp-flash { position: absolute; inset: 0; z-index: -1; pointer-events: none; opacity: 0; background: radial-gradient(70% 80% at 62% 52%, var(--tour), transparent 72%); }
.fp-flash.on { animation: fp-flash 1.2s ease-out; }
@keyframes fp-flash { 0% { opacity: 0; } 14% { opacity: .16; } 100% { opacity: 0; } }
/* the renderer takes a hand: drag turns it, hovering pulls, the right button pushes */
.stage--fp3d canvas.live { cursor: grab; touch-action: pan-y; }
.stage--fp3d canvas.live.dragging { cursor: grabbing; }
/* from Aizawa on: the renderer fills the screen, the title above it at the left, the function centred below */
@media (min-width: 961px) {
  #fieldplay3d.big .inner { height: 100%; width: min(100%, 1240px); grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr) auto;
    gap: 12px; align-items: stretch; }
  #fieldplay3d.big .copy { display: contents; }
  #fieldplay3d.big .copy > :not(h2):not(.tour) { display: none; }
  #fieldplay3d.big .copy > h2 { grid-row: 1; justify-self: start; margin: 0; }
  #fieldplay3d.big .stage { grid-row: 2; min-height: 0; }
  #fieldplay3d.big .stage--fp3d .frame--void { aspect-ratio: auto; height: 100%; }
  #fieldplay3d.big .frame figcaption { left: 18px; right: auto; bottom: 12px; }
  #fieldplay3d.big .tour { grid-row: 3; justify-self: center; width: min(760px, 100%); margin: 0; padding: 10px 14px 8px; }
  #fieldplay3d.big .tour pre { font-size: 11.5px; line-height: 1.45; height: calc(10 * 1.45em); }
  #fieldplay3d.big .tour .dots { display: none; }
}
@media (prefers-reduced-motion: reduce) { .fp-flash.on { animation: none; } }
/* Sync to music (js/music.js): under the renderer, at its left (the right is where Couchplay's radio docks); inside the
   renderer's corner in the big layout and on phones. While it plays the bars move with the beat and the level (--b,
   --l: js/worlds/fieldplay3d.js) */
.fp-tools { position: absolute; left: 0; bottom: -42px; z-index: 3; display: flex; gap: 8px; }
.fp-sync, .fp-count { display: inline-flex; align-items: center; gap: 9px; height: 30px; padding: 0 13px 0 11px;
  font: 500 11px/1 var(--font-mono); letter-spacing: .12em; text-transform: uppercase; color: var(--ink); cursor: pointer;
  border: 1px solid var(--line); border-radius: 999px; background: color-mix(in srgb, #05040a 62%, transparent); backdrop-filter: blur(6px);
  transition: border-color .3s, color .3s, background .3s; }
.fp-sync:hover, .fp-sync:focus-visible, .fp-count:hover, .fp-count:focus-visible { border-color: var(--tour); color: #fff; outline: none; }
.fp-sync[aria-pressed="true"] { border-color: var(--tour); color: #fff; background: color-mix(in srgb, var(--tour) 20%, #05040a);
  box-shadow: 0 0 calc(8px + var(--b, 0) * 16px) color-mix(in srgb, var(--tour) 40%, transparent); }
.fp-sync .eq { display: inline-flex; align-items: flex-end; gap: 2px; height: 12px; }
.fp-sync .eq i { width: 2px; height: 100%; border-radius: 1px; background: currentColor; transform-origin: bottom; transform: scaleY(.35); }
.fp-sync .eq i:nth-child(2) { transform: scaleY(.65); } .fp-sync .eq i:nth-child(3) { transform: scaleY(.45); } .fp-sync .eq i:nth-child(4) { transform: scaleY(.25); }
.fp-sync[aria-pressed="true"] .eq i { background: var(--tour); transform: scaleY(calc(.2 + var(--b, 0) * .8)); }
.fp-sync[aria-pressed="true"] .eq i:nth-child(2) { transform: scaleY(calc(.25 + var(--l, 0) * .75)); }
.fp-sync[aria-pressed="true"] .eq i:nth-child(3) { transform: scaleY(calc(.15 + var(--b, 0) * .55 + var(--l, 0) * .3)); }
.fp-sync[aria-pressed="true"] .eq i:nth-child(4) { transform: scaleY(calc(.2 + var(--l, 0) * .5)); }
.fp-count svg { width: 10px; height: 10px; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; }
.stage--fp3d .frame figcaption { left: auto; right: 0; text-align: right; max-width: calc(100% - 360px); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }   /* after the button */
.frame--void.still ~ .fp-tools { display: none; }      /* no live renderer: nothing to move to the beat */
@media (min-width: 961px) { #fieldplay3d.big .fp-tools { left: auto; right: 18px; bottom: 12px; } }
.frame--void canvas.live { position: absolute; inset: 0; width: 100%; height: 100%; display: block; border-radius: inherit; }
.frame--void .poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: inherit; transition: opacity .6s; }
.frame--void.running .poster { opacity: 0; pointer-events: none; }
.tour { margin-top: 22px; border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px 10px; background: color-mix(in srgb, #05040a 70%, transparent);
  backdrop-filter: blur(6px); --tour: var(--accent); }
.tour-head { display: flex; justify-content: space-between; align-items: baseline; margin: 0 0 8px; font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .12em; text-transform: uppercase; }
.tour-head .name { color: var(--tour); transition: color .4s; }
.tour-head .count { color: var(--muted); }
.tour pre { margin: 0; height: calc(10 * 1.5em); overflow: hidden; font-family: var(--font-mono); font-size: 12px; line-height: 1.5; color: rgba(255, 242, 224, .86); white-space: pre-wrap; }
.tour pre b { font-weight: 400; } .tour pre .k { color: var(--tour); } .tour pre .t { color: #9fd6ff; } .tour pre .n { color: #ffd27a; } .tour pre i { color: rgba(255, 242, 224, .42); font-style: normal; }
.tour .caret { display: inline-block; width: .55em; height: 1.1em; vertical-align: -.2em; background: var(--tour); margin-left: 1px; animation: caret 1s steps(1) infinite; }
@keyframes caret { 50% { opacity: 0 } }
.tour .dots { list-style: none; display: flex; gap: 6px; padding: 0; margin: 10px 0 0; }
.tour .dots li { width: 18px; height: 3px; border-radius: 2px; background: var(--line); transition: background .3s; }
.tour .dots li.on { background: var(--tour); }

/* ---------- Fret Not, on a phone: the demo stage */
.world.long .inner { align-items: center; }
/* ---------- Fret Not (world 06): the app, then "At one phone press" (js/worlds/fretnot.js). The words of the two halves
   share one place and cross-fade (--swap, 0..1); the app's sheet lies back on the desk as the phone rises (--morph) */
/* the app's half keeps the original Fret Not page's 5/7 split; the phone half widens to 4/8 as the words swap */
#fretnot .inner { --g: clamp(28px, 5vw, 80px); grid-template-columns: calc((100% - var(--g)) * (5 - var(--swap, 0)) / 12) minmax(0, 1fr); }
#fretnot, #fretnot .eyebrow { transition: color .5s; }
.fn-swap { display: grid; }
.fn-swap > * { grid-area: 1 / 1; min-width: 0; }
.fn-about { opacity: clamp(0, 1 - var(--swap, 0) * 2.2, 1); }
.fn-phone { opacity: clamp(0, var(--swap, 0) * 2.2 - 1.2, 1); }
#fretnot:not(.night) .fn-phone, #fretnot.night .fn-about { pointer-events: none; }
.fn-phone h3 { font-family: var(--font-display); font-weight: 500; font-size: clamp(20px, 1.7vw, 26px); letter-spacing: -.01em; margin: 0 0 10px; }
.stage--demo .fn-app { position: absolute; left: 50%; top: 50%; width: min(100%, calc(var(--sh) * 1.21)); margin: 0; z-index: 1; transform-origin: 50% 85%;
  transform: translate(-50%, -50%) translateY(calc((1 - var(--app, 0)) * 3vh)) scale(calc(.97 + var(--app, 0) * .03))
    perspective(1500px) translateY(calc(var(--morph) * 10%)) rotateX(calc(var(--morph) * 54deg)) rotateZ(calc(var(--morph) * 6deg)) scale(calc(1 - var(--morph) * .34));
  opacity: clamp(0, (1 - var(--morph)) * 2.6, 1); }
.stage--demo .fn-app[data-off] { visibility: hidden; }
.chapters { list-style: none; padding: 0; margin: 4px 0 0; }
.chapters li { position: relative; padding: 9px 0 9px 30px; border-top: 1px solid var(--line); color: var(--muted); font-size: 14.5px; line-height: 1.45; opacity: .4; transition: color .3s, opacity .35s; }
.chapters li::before { content: attr(data-n); position: absolute; left: 2px; top: 9px; font-family: var(--font-mono); font-size: 13px; color: var(--muted); opacity: 0; transition: opacity .3s; }
.chapters li::after { content: ''; position: absolute; left: 0; top: -1px; height: 1px; width: calc(var(--p, 0) * 100%); background: var(--accent); opacity: 0; }   /* how far through this step */
.chapters li.on { opacity: 1; }
.chapters li.on::before, .chapters li.on::after { opacity: 1; }
.chapters li b { color: var(--ink); font-weight: 600; }
.chapters li span { display: block; max-height: 0; overflow: hidden; opacity: 0; transition: max-height .45s, opacity .35s; }
.chapters li.on { color: var(--ink); }
.chapters li.on::before { color: var(--accent); }
.chapters li.on b { color: var(--accent); }
.chapters li.on span { max-height: 5em; opacity: 1; }
.counts { font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--accent); min-height: 1.4em; margin: 14px 0 0; }
.credit { font-size: 11.5px; color: var(--muted); margin: 10px 0 0; line-height: 1.5; }
.credit a { text-decoration: none; border-bottom: 1px solid var(--line); } .credit a:hover { color: var(--accent); }

.stage--demo { --sh: min(68svh, 640px); position: relative; height: var(--sh); --lift: 0; --draw: 0; --flash: 0; --sheet: 0; --sx: 0px; --sy: 0px; --sr: 0deg;
  --morph: 0; --rise: 0; }
.stage--demo .slot { position: absolute; left: 50%; top: 50%; width: min(100%, calc(var(--sh) * 1.3)); aspect-ratio: 1974 / 1517; transform: translate(-50%, -50%); z-index: 4; }
.stage--demo .slot img { position: absolute; inset: 0; width: 100%; height: 100%; display: block; border-radius: 4px; opacity: var(--lift); object-fit: cover; object-position: top; }
.stage--demo.gl .slot img { visibility: hidden; }
.stage--demo .scan { position: absolute; display: none; background: linear-gradient(90deg, rgba(242, 163, 58, 0), rgba(242, 163, 58, .28)); border-right: 2px solid var(--accent);
  box-shadow: 6px 0 18px rgba(242, 163, 58, .35); }
.stage--demo .phone { position: absolute; left: 50%; top: 50%; width: min(100%, calc(var(--sh) * 1.55)); aspect-ratio: 2.05; z-index: 2;
  transform: translate(-50%, -50%) translateY(calc((1 - var(--rise)) * 72%)) translate(var(--sx), var(--sy)) rotate(var(--sr)) translateY(calc(var(--lift) * 16%)) scale(calc(1 - var(--lift) * .3));
  opacity: calc(var(--rise) - var(--lift) * 1.7); border-radius: 9% / 19%; background: linear-gradient(160deg, #3a3633, #121110 60%);
  box-shadow: 0 0 0 1.5px #57514b, 0 40px 90px rgba(0, 0, 0, .7), inset 0 1px 0 rgba(255, 255, 255, .12); }
.stage--demo .screen { position: absolute; inset: 3.4% 2.4%; border-radius: 7% / 15%; background: #000; overflow: hidden; display: flex; align-items: center; justify-content: center; }
.stage--demo .view { position: relative; height: 100%; aspect-ratio: 4 / 3; transform: scale(calc(1 + var(--shot, 0) * .045)); }   /* the shot locks: a slight zoom across the snap */
.stage--demo .view img { position: absolute; inset: 0; width: 100%; height: 100%; display: block; opacity: calc(1 - var(--lift) * 2); }
.stage--demo .view svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.stage--demo .view polygon { fill: rgba(242, 163, 58, .1); fill-opacity: var(--draw); stroke: #ffb347; stroke-width: 1.6; vector-effect: non-scaling-stroke;
  stroke-dasharray: 1; stroke-dashoffset: calc(1 - var(--draw)); stroke-linejoin: round; filter: drop-shadow(0 0 3px rgba(255, 170, 60, .8)); opacity: calc(1 - var(--lift) * 3); }
.stage--demo .flash { position: absolute; inset: 0; background: #fff; opacity: var(--flash); pointer-events: none; }
.stage--demo .shutter { position: absolute; right: 3.2%; top: 50%; width: 9%; aspect-ratio: 1; transform: translateY(-50%); border-radius: 50%; background: #f4f1ea;
  box-shadow: 0 0 0 3px #000, 0 0 0 5px rgba(244, 241, 234, .85); border: 0; padding: 0; cursor: pointer; transition: transform .15s, box-shadow .2s; }
.stage--demo .shutter:hover { box-shadow: 0 0 0 3px #000, 0 0 0 5px #fff, 0 0 18px rgba(255, 255, 255, .35); }
.stage--demo .shutter:active { transform: translateY(-50%) scale(.92); }
.stage--demo .shutter:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.stage--demo .shutter:disabled { cursor: default; }
.stage--demo .slot, .stage--demo .sheet { pointer-events: none; }   /* overlays: the phone's shutter under them takes the click */
.stage--demo canvas.warp { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 3; pointer-events: none; }
.stage--demo .sheet { position: absolute; inset: 0; z-index: 5; overflow: hidden; border-radius: 6px; background: #fbf7ee; color: #2b2b2b; --bg: #fbf7ee; --zx: 2;
  opacity: var(--sheet); transform: translateY(calc((1 - var(--sheet)) * 3vh)); box-shadow: 0 30px 80px rgba(0, 0, 0, .55); }
.stage--demo .roll { padding: 18px 22px; will-change: transform; }
.stage--demo .ln { margin: 0 0 26px; opacity: .5; transition: opacity .35s; --play: 0; --write: 0; }
.stage--demo .ln.cur { opacity: 1; }
.stage--demo .ln .bars { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: #8a6a3e; margin: 0 0 6px; }
.stage--demo .ln .ph { position: relative; }
.stage--demo .ln .ph img { width: 100%; display: block; border-radius: 3px; }
.stage--demo .ln .win { position: absolute; top: 0; bottom: 0; width: 22%; left: calc(var(--play) * 78%); background: rgba(242, 163, 58, .16); box-shadow: inset 0 0 0 1.5px rgba(196, 106, 18, .55);
  border-radius: 3px; opacity: var(--write); }
.stage--demo .ln .tab { position: relative; overflow: hidden; margin-top: 8px; }
.stage--demo .ln .strip { width: calc(var(--zx) * 100%); transform: translateX(calc(var(--play) * (1 - 1 / var(--zx)) * -100%)); }
.stage--demo .ln .strip svg { display: block; width: 100%; height: auto; clip-path: inset(0 calc((1 - var(--write)) * 100%) 0 0); }
.stage--demo .ln .head { position: absolute; top: 0; bottom: 0; left: calc(var(--play) * 100%); width: 2px; background: #c46a12; box-shadow: 0 0 10px rgba(196, 106, 18, .7); opacity: 0; }
.stage--demo .ln g.note.lit text { fill: #c46a12; font-weight: 700; }

/* ---------- Couchplay (world 01): Couchplay's own room (js/vendor/couchplay/roomart.js), its panel holding the copy
   (and, in the station demo, the library), the "on the TV" caption; and #tv, the picture that leaves the TV. Sizes
   follow Couchplay's app.css: --u is one design pixel of a 1440-tall picture, so the lyric numbers are the boards'. */
.couch .pin { display: block; padding: 0; overflow: hidden; }
.cp-room { position: absolute; left: 0; top: 0; width: 100%; height: 100%; transform-origin: 0 0;
  background: linear-gradient(to bottom, #2d2536 0, #2d2536 var(--top, 0px), #211a29 var(--floor, 60%), #241a14 var(--floor, 60%), #180f0b var(--bot, 100%), #180f0b 100%); }
.cp-room svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.cp-room #cat-grey .cat-grey { transform-box: fill-box; transform-origin: 50% 100%; animation: cpbreathe 4s ease-in-out infinite; }
@keyframes cpbreathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.02, 1.025); } }
.cp-panel { position: absolute; left: var(--gutter); top: 50%; width: min(500px, 36vw); max-height: calc(100svh - 170px); transform: translate(calc(var(--zp, 0) * -60px), -50%);
  opacity: calc(1 - var(--zp, 0)); display: grid; padding: 30px 32px; border-radius: 22px; background: rgba(16, 14, 12, .8); border: 1px solid rgba(244, 239, 230, .14);
  box-shadow: 0 24px 70px rgba(0, 0, 0, .5); color: #f4efe6; overflow: hidden; }
.cp-panel > * { grid-area: 1 / 1; min-width: 0; transition: opacity .4s cubic-bezier(.22, .61, .36, 1), transform .4s cubic-bezier(.22, .61, .36, 1); }
.cp-panel .copy { padding: 0; }
.cp-lib { opacity: 0; transform: translateX(-24px); pointer-events: none; display: flex; flex-direction: column; gap: 14px; font-family: 'Atkinson Hyperlegible', 'Segoe UI', system-ui, sans-serif; }
.couch[data-mode="lib"] .cp-copy { opacity: 0; transform: translateX(24px); pointer-events: none; }
.couch[data-mode="lib"] .cp-lib { opacity: 1; transform: none; }
.couch[data-mode="lib"] .cp-panel { width: min(560px, 40vw); }
.cp-search { display: flex; align-items: center; gap: 12px; height: 52px; padding: 0 16px; border-radius: 12px; background: #100e0c; border: 1px solid rgba(244, 239, 230, .16); color: #9a8f82; position: relative;
  transition: border-color .2s; }
.cp-search.focus { border-color: #f2b45f; }
.cp-search svg { width: 19px; height: 19px; flex-shrink: 0; }
.cp-q { font-size: 21px; color: #f4efe6; white-space: pre; }
.cp-caret { display: none; width: 2px; height: 24px; background: #f2b45f; margin-left: -10px; animation: caret 1s steps(1) infinite; }
.cp-search.focus .cp-caret { display: block; }
.cp-ph { position: absolute; left: 47px; font-size: 21px; color: #6f665c; pointer-events: none; }
.cp-search.typed .cp-ph { display: none; }
.cp-tabs { display: flex; gap: 22px; border-bottom: 1px solid rgba(244, 239, 230, .1); }
.cp-tabs b { font-size: 16px; font-weight: 700; padding: 4px 0 9px; color: #9a8f82; border-bottom: 3px solid transparent; margin-bottom: -1px; }
.cp-tabs b.on { color: #f2b45f; border-bottom-color: #f2b45f; }
.cp-rows { display: flex; flex-direction: column; margin: 0 -10px; min-height: 0; overflow: hidden; }
.cp-row { display: flex; align-items: center; gap: 13px; padding: 8px 10px; border-radius: 10px; flex-shrink: 0; transition: background .18s; animation: cprow .22s cubic-bezier(.22, .61, .36, 1) both; }
@keyframes cprow { from { opacity: 0; transform: translateY(6px); } }
.cp-row.seen { animation: none; }
.cp-row.sel { background: rgba(244, 239, 230, .07); }
.cp-row.go { background: rgba(242, 180, 95, .22); }
.cp-row img, .cp-row .noart { width: 70px; height: 39px; border-radius: 6px; object-fit: cover; flex-shrink: 0; background: #2b2420; }
.cp-row .col { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.cp-row .name { font-size: 18px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: #f4efe6; }
.cp-row .who { font-size: 14px; color: #9a8f82; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cp-row .dur { font-size: 14px; color: #9a8f82; font-variant-numeric: tabular-nums; }
.cp-more { margin: 0; font-size: 14px; color: #9a8f82; min-height: 1.2em; }
.cp-ontv { position: absolute; margin: 0; display: flex; justify-content: flex-end; align-items: baseline; gap: 12px; white-space: nowrap; color: #9a8f82; opacity: calc(1 - var(--zp, 0) * 2);
  font: 400 16px/1.2 'Atkinson Hyperlegible', 'Segoe UI', system-ui, sans-serif; pointer-events: none; }
.cp-ontv .label { letter-spacing: .1em; text-transform: uppercase; font-size: 12px; }
.cp-ontv b { color: #f4efe6; font-weight: 400; }

/* #tv: one element from the TV to fullscreen to the mini radio. JS sets its box (left/top/width/height by transform
   and size), --u (px per design unit of a 1440-tall picture), --fs (1 at fullscreen), --dk (1 docked), --r (radius). */
.tv { position: fixed; left: 0; top: 0; z-index: 7; width: 0; height: 0; --u: .5px; --fs: 0; --dk: 0; --r: 0px; --ox: 0px; --ot: 0px; --ob: 0px; --cpa: #f2b45f; pointer-events: none; }
.tv[hidden] { display: none; }
.tv-pic { position: absolute; inset: 0; overflow: hidden; background: #000; border-radius: var(--r); pointer-events: auto;
  box-shadow: 0 calc(var(--dk) * 18px) calc(var(--dk) * 50px) rgba(0, 0, 0, calc(var(--dk) * .55)), 0 0 0 calc(var(--dk) * 1px) rgba(244, 239, 230, .14); }
.tv-v { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; opacity: 0; transition: opacity .45s ease; }
.tv-v.on { opacity: 1; }
/* #tv-hud: the words of the fullscreen picture. JS lays it out once over the part of the fullscreen picture that is on
   screen (its box, --u) and moves it with the page; the zoom only fades it (--fs), it never scales or slides with it.
   The scrim is an eased gradient (stops along a smooth curve), so it rises with no visible edge. */
.tv-hud { position: fixed; left: 0; top: 0; z-index: 8; pointer-events: none; overflow: hidden; visibility: hidden; color: #f4efe6;
  --u: .6px; --fs: 0; --cpa: #f2b45f; opacity: var(--fs); }
.tv-hud[data-nolocal] .tv-now { display: none; }
.tv-scrim { position: absolute; left: 0; right: 0; bottom: 0; height: 68%;
  background: linear-gradient(to bottom, rgba(12, 10, 9, 0) 0%, rgba(12, 10, 9, .011) 8%, rgba(12, 10, 9, .042) 15%, rgba(12, 10, 9, .09) 22%,
    rgba(12, 10, 9, .152) 29%, rgba(12, 10, 9, .226) 35%, rgba(12, 10, 9, .307) 41%, rgba(12, 10, 9, .392) 47%, rgba(12, 10, 9, .478) 53%,
    rgba(12, 10, 9, .561) 59%, rgba(12, 10, 9, .638) 65%, rgba(12, 10, 9, .706) 71%, rgba(12, 10, 9, .762) 78%, rgba(12, 10, 9, .803) 85%,
    rgba(12, 10, 9, .828) 92%, rgba(12, 10, 9, .84) 100%); }
.tv-now { position: absolute; left: calc(120 * var(--u)); right: calc(120 * var(--u)); bottom: calc(110 * var(--u)); opacity: calc(1 - var(--lyr, 0)); transition: opacity .4s;
  text-shadow: 0 2px 4px rgba(16, 14, 12, .5), 0 12px 44px rgba(16, 14, 12, .55); }
.tv-now p { margin: 0; }
.tv-now .k { font: 400 calc(30 * var(--u)) 'Atkinson Hyperlegible', system-ui, sans-serif; letter-spacing: .14em; text-transform: uppercase; color: var(--cpa); }
.tv-now .t { font: 700 calc(116 * var(--u))/1.04 'Bricolage Grotesque', system-ui, sans-serif; letter-spacing: -.015em; margin-top: calc(14 * var(--u)); }
.tv-now .s { font: 400 calc(40 * var(--u)) 'Atkinson Hyperlegible', system-ui, sans-serif; color: rgba(244, 239, 230, .7); margin-top: calc(16 * var(--u)); }
/* Couchplay's lower third, verbatim but scoped (app.css #lyrics, .ly): previous dim, current bold, next ready */
.tv-lyrics { --lyric-scale: 1; --lp: 64; --lc: 116; --ln: 80; --cc: 68; --cn: 48; --band: 720; --band-pad: 120; --band-bot: 76; --band-gap: 30; --band-max: 2320; --accent: var(--cpa);
  position: absolute; left: 0; right: 0; bottom: 0; height: calc(var(--band) * var(--u));
  display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: calc(var(--band-gap) * var(--u));
  padding: 0 calc(var(--band-pad) * var(--u)) calc(var(--band-bot) * var(--u)); }
.tv-lyrics[hidden] { display: none; }
.tv-lyrics .ly { font-family: 'Bricolage Grotesque', system-ui, sans-serif; font-optical-sizing: auto; text-align: center; max-width: calc(var(--band-max) * var(--u)); line-height: 1.15;
  text-shadow: 0 calc(2 * var(--u)) calc(4 * var(--u)) rgba(16, 14, 12, .5), 0 calc(12 * var(--u)) calc(44 * var(--u)) rgba(16, 14, 12, .55); }
.tv-lyrics .ly.prev, .tv-lyrics .ly.gone { font-size: calc(var(--lp) * var(--u) * var(--lyric-scale)); font-weight: 400; opacity: .36; }
.tv-lyrics .ly.cur { font-size: calc(var(--lc) * var(--u) * var(--lyric-scale)); font-weight: 700; line-height: 1.06; letter-spacing: -.015em; }
.tv-lyrics .ly.next { font-size: calc(var(--ln) * var(--u) * var(--lyric-scale)); font-weight: 500; opacity: .6; }
.tv-lyrics .ly.gone { pointer-events: none; }
.tv-lyrics .ly:empty { display: none; }
.tv-lyrics.unsynced .ly.cur { font-weight: 400; }
.tv-lyrics .ly .w { display: inline-flex; flex-direction: column; align-items: flex-start; vertical-align: bottom; margin-right: .26em; }
.tv-lyrics .ly .w:last-child { margin-right: 0; }
.tv-lyrics .ly .ch { font-weight: 700; color: var(--accent); line-height: 1.1; white-space: nowrap; }
.tv-lyrics .ly .ch:empty::before { content: '\00a0'; }
.tv-lyrics .ly.cur .ch { font-size: calc(var(--cc) * var(--u) * var(--lyric-scale)); }
.tv-lyrics .ly.next .ch { font-size: calc(var(--cn) * var(--u) * var(--lyric-scale)); }
/* Couchplay's hairline: 3 px of progress along the bottom; the skip glides it and names where it went */
.tv-hair { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: rgba(244, 239, 230, .12); opacity: var(--song, 0); }
.tv-hair i { position: absolute; left: 0; top: 0; bottom: 0; width: calc(var(--pos, 0) * 100%); background: var(--cpa); }
.tv-hair.glide i { transition: width .42s cubic-bezier(.22, .61, .36, 1); }
.tv-skip { position: absolute; bottom: 12px; left: calc(var(--pos, 0) * 100%); transform: translateX(-50%); font: 700 14px 'Atkinson Hyperlegible', system-ui, sans-serif; color: #171310;
  background: var(--cpa); padding: 4px 10px; border-radius: 999px; white-space: nowrap; opacity: 0; transition: opacity .25s, left .42s cubic-bezier(.22, .61, .36, 1); }
.tv-hair.skipping .tv-skip { opacity: 1; }
/* the mini radio: a strip on the picture, buttons on its corner, the cat on its roof */
.tv-mini { position: absolute; left: 0; right: 0; bottom: 0; display: flex; align-items: center; gap: 9px; padding: 22px 12px 9px; color: #f4efe6; opacity: var(--dk); pointer-events: none;
  background: linear-gradient(to bottom, rgba(16, 14, 12, 0), rgba(16, 14, 12, .82)); font: 400 13px/1.25 'Atkinson Hyperlegible', system-ui, sans-serif; }
.tv-mt { display: flex; flex-direction: column; min-width: 0; }
.tv-mt b { font-family: 'Bricolage Grotesque', system-ui, sans-serif; font-weight: 700; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tv-mt em { font-style: normal; color: rgba(244, 239, 230, .7); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-height: 1.25em; }
.tv-mt em .c { color: var(--cpa); font-weight: 700; margin-right: .35em; }
.eq { display: flex; align-items: flex-end; gap: 2px; height: 14px; flex-shrink: 0; }
.eq i { width: 3px; height: 30%; background: var(--cpa); border-radius: 1px; }
.tv.playing .eq i { animation: eq .9s ease-in-out infinite; }
.tv.playing .eq i:nth-child(2) { animation-delay: -.3s; } .tv.playing .eq i:nth-child(3) { animation-delay: -.6s; }
@keyframes eq { 0%, 100% { height: 25%; } 50% { height: 100%; } }
.tv-ctl { position: absolute; top: calc(10px + var(--fs) * 54px + var(--ot)); right: calc(10px + var(--ox)); display: flex; gap: 6px; opacity: max(var(--fs), var(--dk)); pointer-events: none; }
.tv[data-fs="1"] .tv-ctl, .tv[data-dk="1"] .tv-ctl { pointer-events: auto; }   /* never a click on something unseen */
.tv-btn { display: inline-flex; align-items: center; gap: 6px; height: 32px; min-width: 32px; padding: 0 8px; border: 0; border-radius: 999px; cursor: pointer; color: #f4efe6;
  background: rgba(16, 14, 12, .62); backdrop-filter: blur(6px); box-shadow: 0 0 0 1px rgba(244, 239, 230, .16); font: 700 13px 'Atkinson Hyperlegible', system-ui, sans-serif; transition: background .2s, color .2s, box-shadow .3s; }
.tv-btn svg { width: 16px; height: 16px; flex-shrink: 0; }
.tv-btn:hover { color: var(--cpa); }
.tv-btn:focus-visible { outline: 2px solid var(--cpa); outline-offset: 2px; }
.tv-station span, .tv-snd .lbl { max-width: 0; overflow: hidden; white-space: nowrap; transition: max-width .45s cubic-bezier(.22, .61, .36, 1); }
.tv[data-fs="1"] .snd:not(.on) .lbl { max-width: 90px; }   /* a browser starts sound only on a click: say so at fullscreen */
.tv .snd-vol::-webkit-slider-runnable-track { background: linear-gradient(to right, var(--cpa) calc(var(--vol, .7) * 100%), rgba(244, 239, 230, .25) 0); }
.tv-station:hover span, .tv.hl .tv-station span, .tv[data-fs="1"] .tv-station span { max-width: 140px; }
.tv.hl .tv-station { background: var(--cpa); color: #171310; animation: hl 1.4s ease-in-out infinite; }
@keyframes hl { 0%, 100% { box-shadow: 0 0 0 1px rgba(244, 239, 230, .16), 0 0 0 0 rgba(242, 180, 95, .55); } 50% { box-shadow: 0 0 0 1px rgba(244, 239, 230, .16), 0 0 0 9px rgba(242, 180, 95, 0); } }
.tv-close { display: none; } .tv[data-dk="1"] .tv-close { display: inline-flex; }
.tv[data-nostation] .tv-station { display: none; }
.tv[data-nolocal] .tv-snd { display: none; }   /* no local media: the recording of Couchplay speaks for itself, and there is no sound */
/* the cat (js/worlds/cat.js): its box is 200 x 150 with the roof at y = 80, so it is 64% of the radio wide and lifted by
   0.64 x 80/200 of that width (a margin percentage is of the width) */
.tv-cat { position: absolute; left: 1%; top: 0; width: 64%; margin-top: -25.6%; opacity: var(--dk); pointer-events: none; }
.tv-cat svg { display: block; width: 100%; height: auto; overflow: visible; }
.tv-cat.in svg { animation: khop .55s cubic-bezier(.22, .61, .36, 1) both; }
@keyframes khop { 0% { transform: translateY(-18%); opacity: 0; } 70% { transform: translateY(1.5%); opacity: 1; } 100% { transform: none; } }
.tv-cat g { transform-box: view-box; }
.tv-cat .k-body { transform-origin: 110px 80px; animation: kbreathe 3.6s ease-in-out infinite; }
@keyframes kbreathe { 50% { transform: scale(1.012, 1.04); } }
.tv-cat .k-tail { transform-origin: 168px 72px; animation: ktail 3.4s ease-in-out infinite; }
.tv-cat .k-tail2 { transform-origin: 182px 86px; animation: ktail2 3.4s ease-in-out -.3s infinite; }
.tv-cat .k-tail3 { transform-origin: 183px 112px; animation: ktail3 3.4s ease-in-out -.6s infinite; }
@keyframes ktail { 0%, 100% { transform: rotate(-3deg); } 50% { transform: rotate(4deg); } }
@keyframes ktail2 { 0%, 100% { transform: rotate(-9deg); } 50% { transform: rotate(10deg); } }
@keyframes ktail3 { 0%, 100% { transform: rotate(-15deg); } 50% { transform: rotate(16deg); } }
.tv-cat .k-head { transform-origin: 62px 74px; transition: transform .6s cubic-bezier(.22, .61, .36, 1); }
.tv-cat.look .k-head { transform: rotate(-9deg) translateY(-2px); }
.tv-cat .k-earL { transform-origin: 36px 40px; } .tv-cat .k-earR { transform-origin: 60px 36px; }
.tv-cat .k-ear.flick { animation: kflick .34s ease-in-out; }
@keyframes kflick { 40% { transform: rotate(-16deg); } }
.tv-cat .k-open { opacity: 0; transition: opacity .2s; } .tv-cat .k-shut { transition: opacity .2s; }
.tv-cat.look .k-open { opacity: 1; } .tv-cat.look .k-shut { opacity: 0; }
/* Pet the body above the roof; the dangling tail never blocks the player's controls. */
.cat-pet { position: absolute; left: 8%; top: 7%; width: 87%; height: 47%; min-height: 44px; padding: 0; border: 0; border-radius: 50% 50% 22% 22%; background: transparent; pointer-events: none; cursor: pointer; touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
.tv-cat.in .cat-pet:not(:disabled) { pointer-events: auto; }
.cat-pet:focus-visible { outline: 2px solid var(--cpa, #f2b45f); outline-offset: 3px; background: rgba(242, 180, 95, .08); }
.tv-cat.petting .k-open { opacity: 0; } .tv-cat.petting .k-shut { opacity: 1; }
.tv-cat.pet-nuzzle .k-head { animation: knuzzle 2.2s ease-in-out; }
.tv-cat.pet-stretch .k-body { animation: kstretch 2.2s ease-in-out; }
.tv-cat.pet-stretch .k-head { animation: knuzzle 2.2s ease-in-out reverse; }
.tv-cat.petting .k-tail { animation: kpet-tail .55s ease-in-out 4; }
.cat-hearts { position: absolute; left: 64%; top: 5%; color: #f4ad9b; opacity: 0; pointer-events: none; filter: drop-shadow(0 1px 2px #2a1a1070); }
.cat-hearts i { position: absolute; font: normal 18px/1 system-ui, sans-serif; opacity: 0; }
.cat-hearts i:nth-child(2) { left: 18px; top: 7px; font-size: 13px; }
.cat-hearts i:nth-child(3) { left: -15px; top: 10px; font-size: 11px; }
.tv-cat.petting .cat-hearts { opacity: 1; }
.tv-cat.petting .cat-hearts i { animation: kheart 1.6s ease-out both; }
.tv-cat.petting .cat-hearts i:nth-child(2) { animation-delay: .25s; }
.tv-cat.petting .cat-hearts i:nth-child(3) { animation-delay: .5s; }
@keyframes knuzzle { 0%, 100% { transform: rotate(0) translateY(0); } 25%, 65% { transform: rotate(10deg) translateY(-4px); } 45% { transform: rotate(4deg) translateY(-2px); } }
@keyframes kstretch { 0%, 100% { transform: scale(1); } 35%, 65% { transform: scale(1.05, 1.13); } }
@keyframes kpet-tail { 0%, 100% { transform: rotate(-5deg); } 50% { transform: rotate(9deg); } }
@keyframes kheart { 0% { opacity: 0; transform: translateY(0) scale(.65); } 20%, 55% { opacity: 1; } 100% { opacity: 0; transform: translateY(-34px) scale(1.15); } }
@media (prefers-reduced-motion: reduce) {
  .tv-cat .k-head, .tv-cat .k-open, .tv-cat .k-shut { transition: none; }
  .tv-cat.petting .cat-hearts i { animation: none; opacity: 1; }
}
body.idle .tv:not(.playing) *, body.idle .cp-room * { animation-play-state: paused !important; }   /* a playing radio stays alive */
@media (prefers-reduced-motion: reduce) {
  .cp-room #cat-grey .cat-grey, .tv.playing .eq i, .tv.hl .tv-station, .cp-caret, .tv-cat svg, .tv-cat g { animation: none !important; }
}
@media (max-width: 960px) {
  .cp-room { height: auto; top: 56px; }
  .cp-panel { left: 12px; right: 12px; width: auto; top: auto; bottom: 74px; max-height: none; transform: translateY(calc(var(--zp, 0) * 30px)); padding: 18px 18px; }
  .couch[data-mode="lib"] .cp-panel { width: auto; }
  .cp-panel .copy { display: block; }             /* the site's one-column phone rule unwraps .copy; this one stays in its panel */
  .cp-panel .copy > .hard, .cp-panel .copy > .chips { display: none; }
  .couch .pin { background: linear-gradient(#2d2536, #211a29 45%, #180f0b); }   /* the room is the screen's top: its wall and floor go on behind */
  .cp-ontv { font-size: 12px; } .cp-ontv .label { font-size: 10px; }
  .tv-btn { height: 30px; min-width: 30px; }
  .tv-mini { padding: 16px 9px 7px; }
}

/* ---------- choreography (desktop: on a phone the ordinary worlds simply scroll past; none under reduced motion) */
@media (min-width: 961px) and (prefers-reduced-motion: no-preference) {
  .inner .copy { transform: translate3d(0, calc((1 - var(--e, 1)) * 12vh - var(--x, 0) * 8vh), 0); }
  .inner .stage { transform: translate3d(0, calc((1 - var(--e, 1)) * -3vh + var(--x, 0) * 5vh), 0); }
  /* the tagline sinks and blurs into the rain as the letters crash */
  #field .hero { transform: translate3d(0, calc(var(--x, 0) * 8svh), 0); filter: blur(calc(var(--x, 0) * 8px)); }
  #field .hint { opacity: calc(1 - var(--x, 0) * 8); }
  /* the acts come and go on the parchment; the eye-height view slides in under it */
  #slay4k { --k: clamp(0, (var(--t, 0) - .12) / .3, 1); }
  .stage--slay4k > .frame:first-child { transform: rotate(-1.4deg) scale(calc(.96 + var(--t, 0) * .06)); }
  .stage--slay4k .frame--second { transform: translate(calc((1 - var(--k)) * 26%), calc((1 - var(--k)) * 34%)) rotate(2.2deg); }
  /* the Theater screen settles in; the radar card is dealt out from under it */
  #counterintelligence { --k: clamp(0, (var(--t, 0) - .1) / .35, 1); }
  .stage--ci .frame--screen { transform: scale(calc(.95 + var(--t, 0) * .05)); }
  .stage--ci .frame--dossier { transform: translate(calc((1 - var(--k)) * 60%), calc((1 - var(--k)) * -55%)) rotate(-2deg); }
  /* behind the scenes first, then the board rises beside it */
  #ledger { --k: clamp(0, (var(--t, 0) - .08) / .35, 1); }
  .stage--ledger .board { transform: translateY(calc((1 - var(--k)) * 16vh)); }
  .stage--ledger .labels { transform: translateY(calc(var(--k) * 2.5vh)); }
  /* the voice card first, then the crayon page slides in beside it */
  #learning { --k: clamp(0, (var(--t, 0) - .05) / .35, 1); }
  .stage--learning .frame--ruled { transform: translateX(calc((1 - var(--k)) * 40%)) rotate(1.6deg); }
}

/* ---------- motion & phones */
@media (prefers-reduced-motion: reduce) {
  .copy > * { transition: none; clip-path: none; opacity: 1; }
  .hint svg, .map .node.on .halo, .frame--screen .bar i, .tour .caret { animation: none; }
  html { scroll-behavior: auto; }
}
@media (max-width: 960px) {
  .inner, .world.flip .inner { grid-template-columns: 1fr; gap: 22px; }
  /* one column: the eyebrow and title first, then the stage, then the words */
  .copy { display: contents; }
  .copy > .eyebrow { order: -3; margin-bottom: 0; } .copy > h2 { order: -2; margin-bottom: 6px; }
  .stage { order: -1; }
  /* a phone: an ordinary world is one tall screen that scrolls past (no pin); a world that plays keeps its pin */
  section.world:not(.long) { height: auto; }
  .world:not(.long) .pin { position: relative; height: auto; min-height: 100svh; padding: 84px var(--gutter) 110px; align-content: center; }
  .world.long .pin { padding: 64px var(--gutter) 84px; }
  .stage--ledger, .stage--learning { grid-template-columns: 1fr; }
  .stage--slay4k .frame--second, .stage--ci .frame--dossier { display: none; }
  .frame--parchment { transform: none; padding: 14px 14px 18px; }
  .trailer-go { left: 9px; bottom: 9px; height: 30px; gap: 7px; padding: 0 11px 0 10px; font-size: 12px; }
  .stage--ci .trailer-go { left: auto; right: 9px; }
  .hero .name { font-size: clamp(40px, 13vw, 120px); }
  .hint { bottom: 72px; }
}
/* ---------- phones: the worlds that play keep their pin, so everything on them fits one screen */
@media (max-width: 960px) {
  /* the words that fit: no paragraph two, and of the chips only a link (fieldplay3D's live site) */
  .world.long .copy > .hard, .world.long .copy > .chips li:not(:has(a)), .world.long .fn-about .hard, .world.long .fn-about .chips { display: none; }
  .world.long h2 { font-size: clamp(30px, 8vw, 44px); }
  .world.long .what { font-size: 14.5px; margin: 0; }
  .stage--fp3d .frame--void { aspect-ratio: 16 / 10; }
  .stage--fp3d figcaption { display: none; }
  .fp-tools { left: auto; right: 8px; bottom: 8px; gap: 6px; }
  .fp-sync, .fp-count { height: 26px; padding: 0 10px 0 9px; font-size: 10px; }
  .fp-scroll { left: auto; right: -10px; width: 4px; }      /* one column: the player's right edge, in the gutter */
  .tour { margin-top: 0; padding: 9px 11px 8px; }
  .tour pre { font-size: 10.5px; height: calc(11 * 1.5em); }
  .tour .dots { display: none; }
  #fretnot .inner { grid-template-columns: 1fr; }
  .stage--demo { --sh: min(40svh, 320px); width: 100%; }
  .stage--demo .sheet { --zx: 3.4; }
  .stage--demo .roll { padding: 10px 12px; }
  .chapters li { display: none; border-top: 0; padding-top: 0; }
  .chapters li.on { display: block; }
  .chapters li span { max-height: none; opacity: 1; }
  .counts { margin-top: 4px; }
  .credit { font-size: 10.5px; margin-top: 4px; }
}
@media (max-width: 720px) {
  .top { font-size: 10.5px; }
  .top-r { gap: 14px; }
  .top-snd .lbl { display: none; }                   /* the speaker alone: room for the achievements tab */
  .ach-tab { height: 24px; padding: 0 9px; letter-spacing: .08em; }
  .ach-toasts { top: 52px; }
  .map { width: 96vw; bottom: 8px; }
  /* where you are, said over the map (no hover on a phone), and stops a finger can hit */
  .maplabel { top: -17px; font-size: 9.5px; letter-spacing: .14em; }
  .mapbtns button { width: 40px; height: 40px; margin: -20px 0 0 -20px; }
}
