/* fumble '98 — the same page, dressed the way the web looked in Internet
   Explorer's first years: bevelled window chrome, system fonts, blue links,
   dotted focus rectangles, no rounded corners and no translucency. The world
   behind it stays; a black page with a moving star field was as 1998 as it
   gets. The colour scheme is a dark Windows one (think Eggplant) so the blue
   and violet mood survives.

   Every bevel is one of two box-shadow recipes, raised or sunken, in four
   tones: outer highlight, inner highlight, inner shadow, outer shadow. */

/* The wordmark's face, served from here; block for the instant it takes. */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 700;
  font-display: block;
  src: url('./fonts/space-grotesk-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --ink: #efeaf9;
  --ink-2: #cfc8e2;
  --ink-3: #aaa6c0;
  --ink-4: #8d89a4;
  --ink-5: #675c80;
  --face: #1f1c33;
  --face-2: #282443;
  --field: #0d0b19;
  --paper: #ffffff;
  --hi-outer: #a59cc8;
  --hi-inner: #6e6690;
  --sh-inner: #3a3452;
  --sh-outer: #08060f;
  --title-a: #2a1a5c;
  --title-b: #6b47b8;
  --link: #8fc2ff;
  --visited: #c69cf5;
  --accent: #c9b7f2;
  --accent-face: #b9a6e0;
  --accent-ink: #19172b;
  --accent-hi-outer: #efe6ff;
  --accent-hi-inner: #d8ccf3;
  --accent-sh-inner: #7a6a9a;
  --select: #3b2a7a;
  --tip: #ffffe1;
  --raised: inset -1px -1px var(--sh-outer), inset 1px 1px var(--hi-outer), inset -2px -2px var(--sh-inner), inset 2px 2px var(--hi-inner);
  --sunken: inset -1px -1px var(--hi-outer), inset 1px 1px var(--sh-outer), inset -2px -2px var(--hi-inner), inset 2px 2px var(--sh-inner);
  --thin-raised: inset -1px -1px var(--sh-outer), inset 1px 1px var(--hi-outer);
  --thin-sunken: inset -1px -1px var(--hi-outer), inset 1px 1px var(--sh-outer);
  --ui: Tahoma, Verdana, 'MS Sans Serif', Arial, sans-serif;
  --mono: 'Courier New', Courier, monospace;
  --display: 'Space Grotesk', 'Arial Black', Arial, sans-serif;
  /* The screen's height budget; the page column is cut to fit a 16:9 picture
     of exactly this height, so a desktop never sees a pillarboxed player and
     the window sits centred on the wide backdrop like a window on a desktop. */
  --screen-h: clamp(300px, 53dvh, 620px);
  font: 11px/1.45 var(--ui);
  color: var(--ink);
  color-scheme: dark;
  background: #111629;
  scrollbar-color: var(--hi-inner) var(--face);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100dvh;
  background: #111629;
  isolation: isolate;
}
::selection { background: var(--select); color: #fff; }

button {
  font: inherit;
  color: inherit;
  cursor: pointer;
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
}
button, a, input { -webkit-tap-highlight-color: transparent; }
button, a { touch-action: manipulation; }
/* Disabled text is etched: shadow-tone glyphs over a highlight one pixel down and right. */
button:disabled { color: var(--ink-5); cursor: default; text-shadow: 1px 1px 0 var(--hi-inner); }
button:disabled .icon { filter: drop-shadow(1px 1px 0 var(--hi-inner)); }
button:focus-visible, a:focus-visible, input:focus-visible { outline: 1px dotted var(--ink); outline-offset: -4px; }
.text-button:focus-visible, .saved-open:focus-visible { outline-offset: 1px; }
a { color: var(--link); text-decoration: underline; }
a:visited { color: var(--visited); }
a:hover { color: #fff; }
a:focus-visible { outline-offset: 1px; }
[hidden] { display: none !important; }

/* The two materials. */
.bevel {
  background: var(--face);
  box-shadow: var(--raised);
  padding: 4px 10px;
}
.bevel:active:not(:disabled), .bevel[aria-pressed=true] { box-shadow: var(--sunken); background: var(--face-2); }
.bevel:active:not(:disabled) > * { transform: translate(1px, 1px); }

.icon-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
/* Sixteen-pixel bitmaps: solid, never anti-aliased. */
.icon {
  width: 16px;
  height: 16px;
  fill: currentColor;
  stroke: none;
  shape-rendering: crispEdges;
  flex-shrink: 0;
}
.sr-only { position: absolute; top: 0; left: 0; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
kbd {
  font: 10px var(--mono);
  padding: 1px 4px;
  background: var(--field);
  box-shadow: var(--thin-sunken);
  color: var(--ink-3);
}

/* ---------------------------------------------------------------- the page */

.page-shell {
  position: relative;
  max-width: min(1296px, calc(var(--screen-h) * 16 / 9 + 134px));
  margin: auto;
  padding: 0 64px;
}

/* ------------------------------------------------------------- the masthead */

/* The brand on the left. On the right, two rows set against its two lines:
   the friends' links level with "it's okay to" in the top right corner, and
   Topics and Favorites level with the wordmark, both ending on the window's
   right edge at every width. */
.masthead {
  min-height: 148px;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas: "brand partners sticker" "brand nav sticker";
  align-content: center;
  column-gap: 20px;
  row-gap: 6px;
}
.brand-heading { grid-area: brand; align-self: center; margin: 0; font-weight: 700; }
.partners { margin-top: -8px; }
.brand { text-decoration: none; display: flex; align-items: flex-start; gap: 14px; width: max-content; color: var(--ink); }
.brand:hover { color: var(--ink); }
/* The mark stands 1.3 times as tall as the ink beside it (the span from the
   top of “it's okay to” to the baseline of “fumble”), centred on that span.
   app.js measures the span from the fonts that actually rendered and sets
   --mark-h and --mark-top; these are the values for the fonts named here,
   used until it does. */
.mark-wrap { position: relative; display: block; flex-shrink: 0; margin-top: var(--mark-top, -5px); }
.brand-mark { height: var(--mark-h, 82px); width: auto; display: block; }
/* The logo's stars catch the light now and then, and all three at once when
   fumble is pressed: small, big, small, gone, the four frames of a 1998
   animated GIF. app.js adds .on; reduced motion never sees it. */
.twinkle { position: absolute; left: var(--x); top: var(--y); width: 16px; height: 16px; margin: -8px 0 0 -8px; pointer-events: none; }
.twinkle svg { position: absolute; inset: 0; width: 16px; height: 16px; shape-rendering: crispEdges; opacity: 0; }
.twinkle.on .glint-small { animation: glint-small .9s steps(1, end) both; }
.twinkle.on .glint-big { animation: glint-big .9s steps(1, end) both; }
@keyframes glint-small { 0% { opacity: 1; } 22% { opacity: 0; } 66% { opacity: 1; } 88%, 100% { opacity: 0; } }
@keyframes glint-big { 0% { opacity: 0; } 22% { opacity: 1; } 66%, 100% { opacity: 0; } }
.brand-text { display: block; }
.brand-whisper {
  display: block;
  margin: 0 0 1px;
  font: italic 14px Georgia, 'Times New Roman', serif;
  letter-spacing: .02em;
  color: var(--ink-3);
}
.brand-line {
  display: flex;
  align-items: center;
  gap: 13px;
  font: 700 53px/1.06 var(--display);
  letter-spacing: -3.4px;
  text-shadow: 3px 3px 0 var(--select);
}
.brand-period { color: var(--accent-face); }
/* Each press of fumble turns the word a new pale colour (yellow, then green,
   then pink, and round again); thirty seconds without a press turns it back.
   The button itself never changes. */
#brand-word { transition: color .4s steps(4, end); }
body[data-word="1"] #brand-word { color: #f3e7a1; }
body[data-word="2"] #brand-word { color: #bfe6b4; }
body[data-word="3"] #brand-word { color: #f4c3d6; }
.brand small {
  font: 11px var(--mono);
  letter-spacing: -.2px;
  color: var(--ink-3);
  align-self: flex-end;
  margin: 0 0 7px 5px;
  text-shadow: none;
}
/* The header controls are an IE4 coolbar: flat until you reach them. The
   friends of the house sit above them the way IE's Links bar sat above its
   toolbar, each behind a little globe. */
.site-nav { grid-area: nav; justify-self: end; display: flex; align-items: center; gap: 4px; }
.partners { grid-area: partners; justify-self: end; display: flex; align-items: center; gap: 2px; font-size: 11px; white-space: nowrap; }
.partner-label { font: 11px var(--mono); color: var(--ink-4); margin-right: 5px; }
.partner { display: flex; align-items: center; gap: 5px; padding: 5px 9px; color: var(--link); text-decoration: none; }
.partner:visited { color: var(--link); }
.partner:hover { box-shadow: var(--thin-raised); color: #fff; }
.partner:active { box-shadow: var(--thin-sunken); }
.partner:focus-visible { outline-offset: -3px; }
/* The maker's line, in the footer and in About; in the footer it shares the
   last row with "last updated", the line every 1998 homepage ended on. */
.credit { grid-column: 1 / -1; margin: 6px 0 0; font-size: 11px; color: var(--ink-3); }
footer .footer-credit { grid-column: 1 / 3; align-self: baseline; }
.updated { grid-column: 3 / -1; justify-self: end; align-self: baseline; margin: 6px 0 0; font: 11px var(--mono); color: var(--ink-4); }
.credit .heart { display: inline-block; color: #e5423a; vertical-align: -3px; }
.about-dialog .credit { margin: 0 0 14px; }
.plain-button {
  font-size: 11px;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 9px;
  color: var(--ink-2);
  white-space: nowrap;
}
.plain-button:hover { box-shadow: var(--thin-raised); color: var(--ink); }
.plain-button:active { box-shadow: var(--thin-sunken); }
.nav-count, .count { font: 11px var(--mono); color: var(--ink-3); }
.count { background: var(--field); box-shadow: var(--thin-sunken); padding: 1px 5px; }

/* -------------------------------------------------------------- the window */

.console {
  position: relative;
  container-type: inline-size;
  background: var(--face);
  box-shadow: var(--raised);
  padding: 3px;
}
/* The title bar shows the page title, the way a browser did. */
.console-bar {
  height: 22px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 0 3px 0 6px;
  background: linear-gradient(90deg, var(--title-a), var(--title-b));
  color: #fff;
  font: bold 11px var(--ui);
}
.station { display: flex; gap: 6px; align-items: center; min-width: 0; }
.station .icon { width: 16px; height: 16px; }
.station > span:first-of-type { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.station-divider { color: #d9cffb; }
.title-buttons { display: flex; gap: 4px; flex-shrink: 0; }
.title-button {
  position: relative;
  width: 20px;
  height: 17px;
  display: grid;
  place-items: center;
  background: var(--face);
  box-shadow: var(--raised);
  font: bold 11px/1 var(--ui);
  color: var(--ink);
}
/* The hit zone grows above and below, never sideways into a neighbour. */
.title-button::before { content: ''; position: absolute; inset: -6px -1px; }
.title-button:active, .title-button[aria-pressed=true] { box-shadow: var(--sunken); }
.title-button:focus-visible { outline-offset: -2px; }
/* While the window is maximised its middle button shows the restore glyph. */
.title-button .glyph-restore, .title-button[aria-pressed=true] .glyph-max { display: none; }
.title-button[aria-pressed=true] .glyph-restore { display: block; }

/* The screen is 16:9 whenever the window is narrow enough to allow it, and
   capped by the viewport otherwise, so the fumble button stays above the fold
   on a laptop while a tablet never letterboxes a wide picture. 56.25cqw is the
   window's own width times nine sixteenths. */
.screen {
  position: relative;
  margin-top: 3px;
  height: min(var(--screen-h), 56.25cqw);
  min-height: 250px;
  overflow: hidden;
  background: #000;
  box-shadow: var(--sunken);
}
/* The player, whole. Nothing is ever drawn over it or cut from it (YouTube's
   rules for embedded players), and it answers the pointer the way YouTube
   made it to. A portrait build's player is exactly its own column, 9:16 at
   the screen's height, between the two bands; a wide build's fills the
   screen. app.js measures the bands. */
.deck { position: absolute; inset: 2px; contain: paint; }
.slot { position: absolute; inset: 0; }
.slot iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; }
.screen[data-frame=portrait] .slot { left: var(--band-w, 0); right: var(--band-w, 0); }
/* The bands either side of a portrait build: the light at the edges of its
   own frame, dithered the way a 1998 screen blended its colours. They sit
   beside the player, never over it. */
.band { position: absolute; top: 2px; bottom: 2px; width: var(--band-w, 0px); height: calc(100% - 4px); display: block; image-rendering: pixelated; pointer-events: none; background: #0d0b19 no-repeat 0 0 / 100% 100%; }
.band-left { left: 2px; }
.band-right { right: 2px; }
.screen[data-frame=wide] .band { display: none; }
.poster {
  position: absolute;
  inset: 2px;
  display: block;
  width: auto;
  height: auto;
  padding: 0;
  background: #000;
  cursor: pointer;
  overflow: hidden;
}
.poster img { width: 100%; height: 100%; object-fit: contain; display: block; }
/* A portrait build's still stands exactly where its player will, between the bands. */
.screen[data-frame=portrait] .poster { background: transparent; }
.screen[data-frame=portrait] .poster img { position: absolute; top: 0; left: var(--band-w, 0); width: calc(100% - 2 * var(--band-w, 0px)); height: 100%; object-fit: cover; object-position: 50% 50%; }
/* While the player is being made ready, out of sight, the still holds the
   screen without its Play button. */
.screen.loading .play-disc { display: none; }
.screen.loading .poster { cursor: progress; }
/* The reveal between builds (screen-art.js): the last picture breaking into
   blocks, the next one resolving out of them, while the player is away. */
.reveal { position: absolute; inset: 2px; width: calc(100% - 4px); height: calc(100% - 4px); display: block; image-rendering: pixelated; pointer-events: none; }
/* Mystify, when the screen has been idle a while (screen-art.js). */
.saver { position: absolute; inset: 2px; width: calc(100% - 4px); height: calc(100% - 4px); display: block; image-rendering: pixelated; pointer-events: none; background: #000; }
/* The first time a visitor sees the window, the screen stays dark until it
   comes on like a CRT (index.html sets the class; app.js runs it once). */
.crt-pending .screen .poster, .crt-pending .screen .band { opacity: 0; }
/* A media-player play button, not a disc. */
.play-disc {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 16px 7px 12px;
  background: var(--face);
  box-shadow: var(--raised);
  color: var(--ink);
  font: bold 12px var(--ui);
}
.play-disc svg { width: 14px; height: 14px; fill: currentColor; }
/* CC in the toolbar: the letters a 1998 VCR's caption button wore. */
.cc-button span { font: bold 11px/1 var(--ui); letter-spacing: .5px; padding: 1px 3px; box-shadow: var(--thin-sunken); background: var(--field); }
.cc-button[aria-pressed=true] span { background: var(--accent-face); color: var(--accent-ink); box-shadow: var(--thin-raised); }
.poster:active .play-disc { box-shadow: var(--sunken); }
.noscript, .opening {
  position: absolute;
  inset: 2px;
  margin: 0;
  display: grid;
  place-items: center;
  background: #000;
  color: var(--ink-3);
  font-size: 12px;
}
.opening p { margin: 0; }

/* ------------------------------------------------------------ the toolbar */

.transport {
  display: flex;
  align-items: center;
  gap: 18px;
  min-height: 58px;
  padding: 8px 6px 6px;
}
.playback-tools { display: flex; align-items: center; gap: 4px; }
.icon-button {
  display: grid;
  place-items: center;
  min-width: 30px;
  height: 26px;
  background: var(--face);
  box-shadow: var(--raised);
  color: var(--ink);
}
.icon-button:active:not(:disabled), .icon-button[aria-pressed=true] { box-shadow: var(--sunken); background: var(--face-2); }
.icon-button:disabled { box-shadow: var(--raised); }
.sound-button {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 26px;
  padding: 0 10px 0 8px;
  background: var(--face);
  box-shadow: var(--raised);
  font-size: 11px;
  color: var(--ink);
}
.sound-button:active { box-shadow: var(--sunken); }
.sound-button[aria-pressed=false] { color: var(--ink-3); }
/* Keep rolling is a checkbox, because it is 1998. */
.autoplay-control {
  margin-left: auto;
  display: flex;
  align-items: center;
  position: relative;
  gap: 7px;
  color: var(--ink-2);
  font-size: 11px;
  cursor: pointer;
}
.autoplay-control input {
  position: absolute;
  right: 0;
  opacity: 0;
  width: 30px;
  height: 30px;
  cursor: pointer;
  margin: 0;
}
.switch-track {
  order: -1;
  width: 13px;
  height: 13px;
  background: var(--paper);
  box-shadow: var(--sunken);
  position: relative;
  pointer-events: none;
}
.switch-track:before {
  content: '';
  position: absolute;
  left: 4px;
  top: 1px;
  width: 3px;
  height: 6px;
  border: solid #000;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
  opacity: 0;
}
.autoplay-control input:checked + .switch-track:before, .option input:checked + .switch-track:before { opacity: 1; }
.autoplay-control input:focus-visible + .switch-track { outline: 1px dotted var(--ink); outline-offset: 2px; }
.fumble-button {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-width: 176px;
  padding: 9px 16px;
  background: var(--accent-face);
  box-shadow: inset -1px -1px var(--sh-outer), inset 1px 1px var(--accent-hi-outer), inset -2px -2px var(--accent-sh-inner), inset 2px 2px var(--accent-hi-inner);
  color: var(--accent-ink);
  font: 700 22px var(--display);
  letter-spacing: -1px;
}
.fumble-button .icon { width: 16px; height: 16px; }
.fumble-button kbd { color: var(--accent-ink); background: #a292cc; box-shadow: inset 1px 1px var(--accent-sh-inner), inset -1px -1px var(--accent-hi-inner); font-size: 10px; margin-left: 4px; }
.fumble-button:focus-visible { outline-color: var(--accent-ink); }
.fumble-button:active:not(:disabled) { box-shadow: inset 1px 1px var(--sh-outer), inset -1px -1px var(--accent-hi-outer), inset 2px 2px var(--accent-sh-inner), inset -2px -2px var(--accent-hi-inner); }
.fumble-button:active:not(:disabled) > * { transform: translate(1px, 1px); }
.fumble-button:disabled { background: var(--face); color: var(--ink-4); box-shadow: var(--raised); }
.fumble-button:disabled kbd { background: var(--field); color: var(--ink-4); box-shadow: var(--thin-sunken); }
.fumble-button.fumbling .icon { animation: fumble .4s ease-out; }
@keyframes fumble { to { transform: rotate(180deg); } }
/* The balloon Windows 95 bobbed beside its Start button, here beside fumble:
   a yellow tooltip with a tail, two frames of bob, and a click puts it away. */
.transport { position: relative; }
.balloon {
  position: absolute;
  right: 8px;
  bottom: calc(100% + 11px);
  z-index: 4;
  max-width: 240px;
  padding: 6px 10px 7px;
  background: var(--tip);
  color: #000;
  border: 1px solid #000;
  font: 11px/1.4 var(--ui);
  cursor: pointer;
  animation: balloon-in .3s steps(3, end) both, balloon-bob 1.6s linear .3s 2;
}
.balloon::before, .balloon::after { content: ''; position: absolute; top: 100%; border-style: solid; border-color: transparent; }
.balloon::before { right: 80px; border-width: 10px 8px 0; border-top-color: #000; }
.balloon::after { right: 81px; margin-top: -1px; border-width: 9px 7px 0; border-top-color: var(--tip); }
@keyframes balloon-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.balloon.hint { animation: balloon-in .2s steps(2, end) both; }
.balloon .icon { width: 16px; height: 16px; }
#balloon-text { display: flex; align-items: center; gap: 6px; }
@keyframes balloon-bob { 0%, 49.9% { transform: none; } 50%, 100% { transform: translateY(-3px); } }

/* The status bar: a sunken cell for the state, a zone cell for the topic. */
.status-bar { display: flex; gap: 3px; padding: 0 0 0; margin-top: 2px; }
.status-cell {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 20px;
  padding: 0 6px;
  box-shadow: var(--thin-sunken);
  font-size: 11px;
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.status-cell.signal { flex: 1; }
.status-cell.zone { min-width: 140px; color: var(--ink-3); }
.status-cell.zone .icon { width: 16px; height: 16px; }
/* While a build loads, Internet Explorer's progress bar: blocks, not a
   smooth fill, stepping along until the picture moves. */
.status-cell.progress { flex: 0 0 auto; padding: 0 3px; }
.progress-track { display: block; width: 116px; height: 12px; }
.progress-fill { display: block; height: 100%; width: 0; background: repeating-linear-gradient(90deg, var(--accent-face) 0 6px, transparent 6px 8px); }
/* What this device has found of the library, counted up as you go. */
.status-cell.found { flex: 0 0 auto; color: var(--ink-3); font: inherit; font-size: 11px; font-variant-numeric: tabular-nums; cursor: pointer; }
.status-cell.found:hover { color: var(--ink); text-decoration: underline; }
.status-cell.found:active { box-shadow: var(--sunken); }
#found-count { color: var(--ink); }
/* How far into the build: the page's own clock, since YouTube's is hidden. */
.status-cell.time { flex: 0 0 auto; font: 11px var(--mono); color: var(--ink-3); font-variant-numeric: tabular-nums; }
.signal > span:first-child { width: 7px; height: 7px; background: var(--ink-4); box-shadow: var(--thin-sunken); flex-shrink: 0; }
.signal.playing > span:first-child { background: #7cff7c; }

/* ---------------------------------------------------------- the caption row */

.now-playing {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 36px;
  margin-top: 6px;
  padding: 14px 16px 16px;
  background: var(--face);
  box-shadow: var(--raised);
}
.video-copy { min-width: 0; max-width: 850px; }
.now-eyebrow { display: flex; gap: 8px; align-items: center; font: 11px var(--mono); color: var(--ink-3); }
.meta-dot { color: var(--ink-5); }
/* The NEW sign that sat beside every fresh link in 1998, in the amber of the
   logo's stars: for a build that arrived in the last two weeks. */
.new-tag { font: bold 9px/1 var(--ui); text-transform: uppercase; letter-spacing: .5px; color: #3a1e00; background: #ffd84a; padding: 2px 4px 1px; box-shadow: inset -1px -1px #b8861c, inset 1px 1px #fff4b8; }
.now-playing h2 {
  font: bold 15px/1.4 var(--ui);
  margin: 6px 0 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.video-description {
  font-size: 11px;
  line-height: 1.55;
  margin: 6px 0 0;
  color: var(--ink-3);
  max-width: 760px;
}
.maker-block {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  align-self: stretch;
  justify-content: space-between;
  gap: 10px;
  flex-shrink: 0;
  max-width: 28%;
}
.maker-block a { display: flex; align-items: center; gap: 5px; font-size: 11px; }
.maker-block .icon { width: 12px; height: 12px; }
/* The maker, and in a line beneath, how many of their builds are here and
   what they mostly make; the line lines one of them up next. */
.maker-id { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; min-width: 0; }
.made-by { font-size: 11px; color: var(--ink-3); overflow-wrap: anywhere; text-align: right; }
.maker-more { min-height: 24px; padding: 0; background: none; font: 10px var(--ui); color: var(--ink-4); text-align: right; cursor: pointer; }
.maker-more:hover { color: var(--ink-2); text-decoration: underline; }
.maker-more:focus-visible { outline-offset: 2px; }
.maker-more:active { color: var(--ink); }
/* Parts like the ones in the build, the ones Axiometa makes linked to them. */
.parts { display: flex; flex-wrap: wrap; align-items: center; gap: 3px 6px; margin: 9px 0 0; font-size: 11px; line-height: 1.4; color: var(--ink-3); }
.parts .icon { width: 16px; height: 16px; flex-shrink: 0; }
.parts-list { display: contents; }
.parts-list a { color: var(--link); }
.parts-list a:visited { color: var(--visited); }
.parts-dot { color: var(--ink-5); }
.parts-where { color: var(--ink-4); font-size: 10px; }
.parts-where::before { content: '\2014\00a0'; }
.maker-actions { display: flex; align-items: center; gap: 6px; }
.save-current, .share-current {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 9px 0 7px;
  background: var(--face);
  box-shadow: var(--raised);
  font-size: 11px;
  color: var(--ink);
}
.save-current:active, .share-current:active { box-shadow: var(--sunken); }
.save-current kbd, .share-current kbd { margin-left: 2px; }
.save-current[aria-pressed=true] { box-shadow: var(--sunken); background: var(--face-2); }
.save-current[aria-pressed=true] .icon { fill: #ffd84a; }

/* --------------------------------------------------- the tuning: a tab control */

.tuning { margin-top: 18px; scroll-margin-top: 18px; }
/* Lights down: while a build plays, what sits below the picture steps back,
   and comes forward again the moment a pointer or the keyboard goes to it. */
.tuning, footer { transition: filter .6s steps(4, end); }
body.playing .tuning, body.playing footer { filter: brightness(.85) saturate(.85); transition-duration: 1.4s; transition-timing-function: steps(6, end); }
body.playing .tuning:hover, body.playing .tuning:focus-within, body.playing footer:hover, body.playing footer:focus-within { filter: none; transition-duration: .2s; }
.tuning-heading { display: flex; justify-content: space-between; align-items: flex-end; gap: 15px; padding: 0 2px; }
.browse-tabs, .dialog-tabs { display: flex; align-items: flex-end; }
.browse-tabs button, .dialog-tabs button {
  position: relative;
  padding: 5px 12px 4px;
  margin-right: -2px;
  background: var(--face);
  box-shadow: inset 1px 1px var(--hi-outer), inset -1px 0 var(--sh-outer), inset 2px 2px var(--hi-inner), inset -2px 0 var(--sh-inner);
  color: var(--ink-3);
  font-size: 11px;
}
.browse-tabs button:hover, .dialog-tabs button:hover { color: var(--ink); }
.browse-tabs button[aria-selected=true], .dialog-tabs button[aria-selected=true] {
  padding: 7px 14px 6px;
  margin-bottom: -2px;
  z-index: 1;
  color: var(--ink);
  background: var(--face);
}
.tuning-heading > span { font: 11px var(--mono); color: var(--ink-3); padding-bottom: 6px; }
#topics-panel, #moods-panel { background: var(--face); box-shadow: var(--raised); padding: 16px 14px 14px; }
.topic-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 14px;
  margin: 0 0 12px;
}
.topic-toolbar p, .mood-note { font-size: 11px; color: var(--ink-3); margin: 0; }
.topic-toolbar > div { white-space: nowrap; font-size: 11px; color: var(--ink-4); display: flex; align-items: center; gap: 6px; }
.text-button { padding: 2px 0; color: var(--link); text-decoration: underline; font-size: 11px; }
.text-button:hover { color: #fff; }
.category-list { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.category-choice {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 32px;
  padding: 6px 9px;
  background: var(--face);
  box-shadow: var(--raised);
  color: var(--ink-2);
  font-size: 11px;
  cursor: pointer;
  line-height: 1.3;
}
.category-choice input {
  appearance: none;
  width: 13px;
  height: 13px;
  margin: 0;
  flex-shrink: 0;
  background: var(--paper);
  box-shadow: var(--sunken);
  position: relative;
  cursor: pointer;
}
.category-choice input:checked::after {
  content: '';
  position: absolute;
  left: 4px;
  top: 1px;
  width: 3px;
  height: 6px;
  border: solid #000;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
/* Each topic carries its Control Panel icon and how many builds it holds.
   The tick carries the state; a topic left out also greys its icon, the way
   an IE toolbar icon waited in grey until you reached for it. */
.category-choice .icon { width: 16px; height: 16px; }
.topic-glyph { position: relative; display: grid; flex-shrink: 0; }
.category-choice input:not(:checked) ~ .topic-glyph .icon { filter: grayscale(1) opacity(.45); }
.category-name { flex: 1; min-width: 0; }
.category-count { font: 11px var(--mono); color: var(--ink-4); font-variant-numeric: tabular-nums; }
/* For a returning visitor the three busiest topics wear a small sparkle on
   the icon's corner, the logo's stars catching the light again. */
.category-new { position: absolute; top: -4px; right: -4px; width: 16px; height: 16px; pointer-events: none; }
.category-new .icon { width: 16px; height: 16px; }
.topics-news { margin: -4px 0 12px; font: 11px var(--mono); color: #ffd84a; }
.category-choice:has(input:checked) { color: var(--ink); }
.category-choice:hover { color: var(--ink); }
.category-choice:has(input:focus-visible) { outline: 1px dotted var(--ink); outline-offset: -5px; }
.category-choice input:focus-visible { outline: none; }
.mood-note { margin: 0 0 12px; }
.topic-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.topic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  font-size: 11px;
  padding: 6px 12px 6px 9px;
  background: var(--face);
  box-shadow: var(--raised);
  color: var(--ink-2);
}
.topic:hover { color: var(--ink); }
.topic.active { box-shadow: var(--sunken); background: var(--face-2); color: var(--ink); }
.mood-detail { font-size: 11px; line-height: 1.6; color: var(--ink-3); margin: 12px 0 0; }

/* --------------------------------------------------------------- the footer */

footer {
  margin-top: 22px;
  padding: 16px 2px 30px;
  border-top: 1px solid var(--sh-inner);
  box-shadow: inset 0 1px 0 var(--hi-inner);
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: 14px 20px;
  color: var(--ink-4);
}
.footer-whisper { font: italic 15px Georgia, 'Times New Roman', serif; color: var(--ink-4); }
.footer-controls { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
footer .text-button:disabled { color: var(--ink-4); text-decoration: none; text-shadow: none; cursor: default; }
/* An honest hit counter: the number of builds in the library. */
.counter { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--ink-3); }
.counter span {
  font: bold 12px/1 var(--mono);
  color: #7cff7c;
  background: #000;
  box-shadow: var(--thin-sunken);
  padding: 4px 5px 3px;
  letter-spacing: 2px;
}
/* The 88x31 badge, a "link to us" button the way a 1998 homepage had one. */
.badge {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  width: 88px;
  height: 31px;
  padding: 0 6px;
  background: var(--field);
  box-shadow: var(--raised);
  line-height: 1.15;
  text-align: center;
  cursor: pointer;
}
.badge:active { box-shadow: var(--sunken); }
.badge:active > * { transform: translate(1px, 1px); }
.badge:focus-visible { outline-offset: -4px; }
.badge b { font: bold 10px var(--ui); color: var(--accent); }
.badge i { font: 9px var(--ui); color: var(--ink-3); font-style: normal; }
.badges { display: flex; gap: 8px; align-items: center; }
/* The coffee: a second 88x31, a mug on the left the way the old ones had a logo. */
.coffee-badge { flex-direction: row; align-items: center; justify-content: flex-start; gap: 6px; padding: 0 6px 0 7px; text-align: left; text-decoration: none; color: inherit; }
.coffee-badge .icon { width: 16px; height: 16px; flex-shrink: 0; }
.coffee-badge span { display: flex; flex-direction: column; }
.coffee-badge b { color: #f5a83a; font-size: 11px; }
.coffee-badge:hover b { color: #ffd84a; }

/* ---------------------------------------------- the screen's other two faces */

.video-error, .empty-state {
  position: absolute;
  inset: 2px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: var(--field);
  padding: 25px;
  text-align: center;
}
.video-error h2, .empty-state h2 { font: bold 14px var(--ui); margin: 12px 0 0; }
.video-error p, .empty-state p { font-size: 11px; line-height: 1.7; color: var(--ink-3); max-width: 340px; margin: 6px 0 14px; }
.empty-mark { width: 32px; height: 32px; color: var(--accent); fill: currentColor; shape-rendering: crispEdges; }
.empty-state > div, .video-error > div { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; justify-content: center; }
.small-accent {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 75px;
  height: 23px;
  padding: 0 12px;
  background: var(--face);
  box-shadow: var(--raised);
  color: var(--ink);
  font-size: 11px;
  text-decoration: none;
}
.small-accent:hover { color: var(--ink); }
.small-accent:active { box-shadow: var(--sunken); }

/* -------------------------------------------------------------- the dialogs */

dialog {
  color: var(--ink);
  background: var(--face);
  box-shadow: var(--raised);
  border: 0;
  padding: 3px;
  width: min(560px, calc(100vw - 32px));
  max-height: 85dvh;
}
/* The page behind a dialog is dithered, not dimmed: a one-pixel checker of
   black, the way 1998 greyed things out. */
dialog::backdrop { background: repeating-conic-gradient(#000 0 25%, transparent 0 50%); background-size: 2px 2px; }
.dialog-titlebar {
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 0 3px 0 6px;
  background: linear-gradient(90deg, var(--title-a), var(--title-b));
}
.dialog-titlebar h2, .dialog-titlebar span { margin: 0; font: bold 11px var(--ui); color: #fff; }
.dialog-body { padding: 18px 14px 14px; }
.dialog-body h2 { font: bold 16px var(--ui); margin: 4px 0 8px; }
.dialog-note { font-size: 11px; color: var(--ink-3); line-height: 1.5; margin: 0 0 12px; }
.dialog-tabs { padding: 0 2px; }
.tab-frame { background: var(--face); box-shadow: var(--raised); padding: 10px; }
.list-box { background: var(--field); box-shadow: var(--sunken); padding: 3px; max-height: 50dvh; overflow: auto; }
.list-group { font: bold 11px var(--ui); color: var(--ink-2); padding: 8px 6px 3px; }
.list-group:first-child { padding-top: 4px; }
.saved-row {
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr) 24px;
  gap: 10px;
  align-items: center;
  padding: 6px;
}
.saved-row:hover { background: var(--select); }
.history-row { grid-template-columns: 88px minmax(0, 1fr); }
.saved-thumb { width: 100%; height: 50px; object-fit: cover; background: #000; box-shadow: var(--thin-sunken); }
.saved-thumb.portrait { width: 28px; justify-self: center; }
.saved-open { padding: 0; text-align: left; font-size: 11px; line-height: 1.4; color: var(--link); text-decoration: underline; }
.saved-open:hover { color: #fff; }
.saved-meta { display: block; font-size: 10px; color: var(--ink-3); margin-top: 3px; }
.saved-remove { width: 26px; height: 22px; display: grid; place-items: center; background: var(--face); box-shadow: var(--raised); color: var(--ink); }
.saved-remove:active { box-shadow: var(--sunken); }
.saved-remove .icon { width: 16px; height: 16px; }
.saved-empty { padding: 26px 10px; text-align: center; }
.saved-empty svg { width: 28px; height: 28px; color: #ffd84a; }
.saved-empty p { font: bold 12px var(--ui); margin: 8px 0 4px; }
.saved-empty span { font-size: 11px; color: var(--ink-3); line-height: 1.7; }
.about-dialog { width: min(460px, calc(100vw - 32px)); }
.dialog-eyebrow { font: 11px var(--mono); color: var(--ink-3); display: block; margin-bottom: 12px; }
/* About opens the way a 1998 About box did: the product's picture beside its name. */
.about-head { display: flex; align-items: center; gap: 14px; margin: 0 0 12px; }
.about-mark { width: 76px; height: auto; flex-shrink: 0; }
.about-head .dialog-eyebrow { margin-bottom: 4px; }
.about-head h2 { margin: 0; }
.about-dialog .about-found { font: 11px var(--mono); color: var(--ink-3); margin: 5px 0 0; line-height: 1.4; }
.dialog-title { display: flex; align-items: center; gap: 5px; }
.dialog-title .icon { color: #ffd84a; }
/* The Favorites window ends in a status line, as an Explorer window did. */
.dialog-buttons { align-items: center; }
.dialog-status { margin-right: auto; padding: 3px 7px; box-shadow: var(--thin-sunken); font-size: 11px; color: var(--ink-3); }
.about-dialog p { font-size: 12px; line-height: 1.7; color: var(--ink-2); margin: 0 0 10px; }
.about-dialog small { font-size: 10px; color: var(--ink-3); line-height: 1.6; display: block; margin-bottom: 10px; }
.shortcut-list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px 12px;
  margin: 14px 0 16px;
  padding: 12px;
  background: var(--field);
  box-shadow: var(--sunken);
  font-size: 11px;
  color: var(--ink-2);
}
.shortcut-list kbd { margin-right: 5px; }
.touch-note { display: none; }
/* A checkbox line in a dialog, drawn like Keep rolling. */
.option { display: flex; align-items: center; gap: 7px; position: relative; font-size: 11px; color: var(--ink-2); cursor: pointer; margin: 0 0 14px; }
.option input { position: absolute; left: 0; opacity: 0; width: 20px; height: 20px; margin: 0; cursor: pointer; }
.option .switch-track { order: 0; }
.option input:focus-visible + .switch-track { outline: 1px dotted var(--ink); outline-offset: 2px; }
.dialog-buttons { display: flex; justify-content: flex-end; gap: 6px; margin-top: 16px; }
.ok-dialog {
  min-width: 75px;
  height: 23px;
  padding: 0 12px;
  background: var(--face);
  box-shadow: var(--raised), 0 0 0 1px var(--sh-outer);
  font-size: 11px;
  color: var(--ink);
}
.ok-dialog:active { box-shadow: var(--sunken), 0 0 0 1px var(--sh-outer); }
/* A tooltip, the yellow kind. */
.toast {
  position: fixed;
  bottom: 25px;
  left: 50%;
  transform: translate(-50%, 0);
  padding: 4px 7px;
  background: var(--tip);
  color: #000;
  border: 1px solid #000;
  font-size: 11px;
  opacity: 0;
  pointer-events: none;
  z-index: 5;
  max-width: calc(100vw - 35px);
  text-align: center;
}
.toast.visible { opacity: 1; }
.toast.top { bottom: auto; top: 25px; }

/* ------------------------------------------------------------- the 404 page */

.lost { max-width: 560px; margin: 8vh auto 0; }
.lost-body { padding: 26px 18px 18px; }
.lost h1 { font: bold 16px var(--ui); margin: 0 0 8px; }
.lost p { font-size: 12px; color: var(--ink-2); margin: 0; line-height: 1.6; }
.lost .about-head { margin-bottom: 18px; }
.lost .ok-dialog { text-decoration: none; display: inline-flex; align-items: center; justify-content: center; }

/* ------------------------------------------------------------ the focus view
   Everything but the picture steps back. The shell becomes one viewport-high
   column and the screen takes what is left; the calc is the target, and flex
   shrink is the guarantee that nothing ever spills off the bottom. */

body.focus-mode .tuning, body.focus-mode footer, body.focus-mode .video-description, body.focus-mode .parts, body.focus-mode .maker-more, body.focus-mode .partners, body.focus-mode .balloon { display: none; }
body.focus-mode .page-shell {
  max-width: none;
  padding: 0 24px 8px;
  height: 100dvh;
  display: flex;
  flex-direction: column;
}
body.focus-mode .masthead { min-height: 100px; flex-shrink: 0; }
/* The screen takes the height the chrome leaves (--focus-h, measured by
   app.js from the rows that rendered; the calc stands in until it does), and
   the column is cut to a 16:9 picture of that height, so the window never
   widens into a pillarbox. The masthead shares the same edges. */
body.focus-mode main, body.focus-mode .masthead { width: 100%; max-width: calc(var(--focus-h, calc(100dvh - 264px)) * 16 / 9 + 6px); margin: 0 auto; }
body.focus-mode main { flex: 0 1 auto; min-height: 0; display: flex; flex-direction: column; }
body.focus-mode .console { flex: 0 1 auto; min-height: 0; display: flex; flex-direction: column; }
body.focus-mode .console-bar, body.focus-mode .transport, body.focus-mode .status-bar, body.focus-mode .now-playing { flex-shrink: 0; }
body.focus-mode .console .screen { flex: 0 1 auto; min-height: 160px; height: var(--focus-h, calc(100dvh - 264px)); }
body.focus-mode .now-playing { padding: 10px 12px; }
body.focus-mode .now-playing h2 { -webkit-line-clamp: 1; }
body.focus-mode .maker-block { flex-direction: row; align-items: center; gap: 14px; max-width: none; }

/* ------------------------------------------------------------- the viewports */

@media (max-width: 1100px) {
  .page-shell { padding: 0 54px; max-width: min(1296px, calc(var(--screen-h) * 16 / 9 + 114px)); }
  .category-list { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .video-description { max-width: 640px; }
  .now-playing { gap: 25px; }
  .brand-line { font-size: 49px; }
}

/* Fingers, at any width: a tablet in landscape gets the same finger-sized
   targets a phone does, and the layout rules for narrow screens below still
   have the last word on a phone. */
@media (pointer: coarse) {
  .icon-button { min-width: 44px; height: 40px; }
  .sound-button { height: 40px; padding: 0 12px 0 10px; }
  .save-current, .share-current { height: 40px; padding: 0 12px 0 10px; }
  .plain-button, .partner { min-height: 40px; }
  .console-bar, .dialog-titlebar { height: 26px; }
  .title-button { width: 26px; height: 22px; }
  .category-choice { min-height: 44px; }
  .topic { padding: 12px 14px; }
.browse-tabs button, .dialog-tabs button { padding: 11px 14px 10px; }
.browse-tabs button[aria-selected=true], .dialog-tabs button[aria-selected=true] { padding: 13px 16px 12px; }
  .text-button { padding: 12px 6px; margin: -12px -6px; }
  .ok-dialog { height: 36px; min-width: 88px; }
  .fumble-button { min-height: 48px; }
  .saved-remove { width: 36px; height: 32px; }
}

@media (max-width: 760px) {
  .page-shell { padding: 0 20px; }
  /* On a phone Topics and Favorites stay beside the brand, and the friends'
     links take a row of their own beneath, still at the right. Should the
     two ever not fit side by side, the controls wrap under the brand too. */
  .masthead { min-height: 0; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 2px 12px; padding: 12px 0 2px; }
  .brand { gap: 10px; }
  .brand-line { font-size: 41px; gap: 8px; letter-spacing: -2.7px; text-shadow: 2px 2px 0 var(--select); }
  .mark-wrap { margin-top: var(--mark-top, -3px); }
  .brand-mark { height: var(--mark-h, 60px); }
  .brand-whisper { font-size: 12px; }
  .brand small { display: none; }
  .site-nav { gap: 2px; margin-left: auto; }
  .partners { order: 3; flex-basis: 100%; justify-content: flex-end; margin: 0 -2px 0 0; }
  .plain-button { padding: 6px 7px; min-height: 40px; }
  .nav-count { display: none; }
  .console-bar, .dialog-titlebar { height: 26px; }
  .title-buttons { gap: 4px; }
  .title-button { width: 26px; height: 22px; }
  .title-button::before { inset: -6px -2px; }
  .now-eyebrow, .tuning-heading > span, .saved-meta { font-size: 11px; }
  /* The screen takes the shape of the build: a wide one is 16:9 across the
     window, a vertical one is tall. Either way the still is framed exactly
     the way the player will frame the video: a portrait still standing in
     the middle, a wide one lying across, black either side. */
  .screen { height: clamp(300px, 48dvh, 540px); min-height: 0; }
  .console[data-aspect=wide] .screen { height: 56.25cqw; }
  .poster img { object-fit: contain; }
  .transport { gap: 10px; padding: 8px 4px 6px; flex-wrap: wrap; min-height: 54px; }
  .playback-tools { gap: 4px; }
  .icon-button, .sound-button { min-width: 44px; height: 40px; }
  .sound-button { padding: 0; justify-content: center; }
  .sound-button span { display: none; }
  .autoplay-control { font-size: 11px; }
  .fumble-button { min-width: 125px; font-size: 21px; padding: 8px 12px; gap: 8px; margin-left: auto; }
  .fumble-button kbd { display: none; }
  .balloon { right: 4px; }
  .balloon::before { right: 54px; }
  .balloon::after { right: 55px; }
  .status-cell.zone { min-width: 0; max-width: 45%; }
  .now-playing { padding: 12px 10px 12px; align-items: flex-start; gap: 12px; flex-wrap: wrap; }
  .video-copy { width: 100%; }
  .now-playing h2 { font-size: 14px; margin-top: 5px; -webkit-line-clamp: 3; }
  .now-eyebrow { font-size: 10px; }
  .video-description { margin-top: 5px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .maker-block {
    width: 100%;
    max-width: none;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
  }
  /* Finger-sized targets without moving anything: the hit area grows into
     negative margins, so the row keeps its height and the focus maths holds. */
  .maker-block a { padding: 12px 0; margin: -12px 0; }
  .maker-id { align-items: flex-start; }
  .maker-more, .made-by { text-align: left; }
  .save-current, .share-current { height: 40px; padding: 0 12px 0 10px; }
  .save-current kbd, .share-current kbd { display: none; }
  .small-accent { height: 40px; padding: 0 16px; }
  .tuning { margin-top: 14px; }
.browse-tabs button, .dialog-tabs button { padding: 12px 12px 11px; }
.browse-tabs button[aria-selected=true], .dialog-tabs button[aria-selected=true] { padding: 14px 14px 13px; }
  .tuning-heading > span { font-size: 10px; }
  #topics-panel, #moods-panel { padding: 14px 10px 12px; }
  .topic-toolbar p { line-height: 1.5; }
  .text-button { padding: 12px 6px; margin: -12px -6px; }
  .category-list { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
  .topic-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .history-row { grid-template-columns: 72px minmax(0, 1fr); }
  .category-choice { min-height: 40px; }
  .topic { padding: 12px 14px; }
  /* The footer keeps the badge beside the whisper; the rest sits beneath. */
  footer { margin-top: 16px; padding: 14px 2px 26px; grid-template-columns: 1fr auto; gap: 12px; }
  footer .badges { order: 0; }
  .footer-controls { grid-column: 1 / -1; gap: 14px; }
  footer .footer-credit, .updated { grid-column: 1 / -1; justify-self: start; }
  .updated { margin-top: -6px; }
  .footer-whisper { font-size: 14px; }
  .about-dialog .dialog-body { padding: 14px 12px 12px; }
  .shortcut-list { grid-template-columns: 1fr 1fr; }
  .saved-row { grid-template-columns: 72px minmax(0, 1fr) 36px; gap: 8px; }
  .saved-thumb { height: 42px; }
  .saved-remove { width: 36px; height: 32px; }
  .ok-dialog { height: 36px; min-width: 88px; }
  body.focus-mode .page-shell { padding: 0 10px 6px; }
  body.focus-mode .masthead { min-height: 90px; }
  body.focus-mode .console .screen { height: var(--focus-h, calc(100dvh - 258px)); }
  /* A wide build in focus on a phone is as big as the width allows; a taller frame would only be black. */
  body.focus-mode .console[data-aspect=wide] .screen { height: 56.25cqw; }
  body.focus-mode .now-playing { padding: 10px 8px; gap: 10px; }
  body.focus-mode .now-playing h2 { font-size: 13px; margin-top: 4px; }
}

@media (max-width: 900px) {
  footer { grid-template-columns: 1fr auto; gap: 12px; }
  footer .badges { order: 0; }
  .footer-controls { grid-column: 1 / -1; gap: 14px; }
  footer .footer-credit, .updated { grid-column: 1 / -1; justify-self: start; }
  .updated { margin-top: -6px; }
}
@media (min-width: 761px) and (max-width: 900px) {
  .partners { margin-top: -4px; }
}

/* Below 480px the row of tools and the fumble button fill the width, so the
   Keep rolling checkbox takes a quiet full-width row of its own beneath them. */
@media (max-width: 480px) {
  .transport { row-gap: 4px; }
  .autoplay-control {
    order: 3;
    width: 100%;
    justify-content: flex-start;
    margin: 4px 0 0;
    padding: 8px 4px 2px;
    box-shadow: inset 0 1px 0 var(--sh-inner), inset 0 2px 0 var(--hi-inner);
  }
  .autoplay-control input { right: auto; left: 0; }
  body.focus-mode .console .screen { height: var(--focus-h, calc(100dvh - 298px)); }
  /* The found tally says only how many; the footer's counter holds the total. */
  .found-of { display: none; }
  /* Topics and Favorites keep their words and drop their icons, so they stay
     beside the brand on a phone of any common width. */
  .plain-button .icon { display: none; }
  .status-cell.zone { max-width: 40%; }
  .status-bar:has(.time:not([hidden])) .progress { display: none; }
}

@media (max-width: 390px) {
  .page-shell { padding: 0 14px; }
  .masthead { gap: 8px; }
  .brand-line { font-size: 36px; }
  .brand-mark { height: var(--mark-h, 56px); }
  .plain-button .icon { display: none; }
  .tuning-heading { gap: 8px; }
.browse-tabs button, .dialog-tabs button { padding: 7px 8px 6px; }
.browse-tabs button[aria-selected=true], .dialog-tabs button[aria-selected=true] { padding: 9px 10px 8px; }
  .category-choice { padding: 6px 7px; }
}

/* Finger-sized targets for the small links, and a centred focus column when a
   wide build leaves room beneath the caption. */
@media (max-width: 760px) {
  .credit a { display: inline-block; padding: 6px 0; margin: -6px 0; }
  .saved-open { padding: 5px 0; margin: -5px 0; }
  .option input { width: 24px; height: 24px; }
  body.focus-mode main { flex: 1 1 auto; justify-content: center; }
}

@media (max-width: 1100px) and (orientation: portrait) {
  body.focus-mode .console[data-aspect=wide] .screen { height: 56.25cqw; }
}

/* Keyboard hints are for keyboards. */
@media (pointer: coarse) {
  .fumble-button kbd, .save-current kbd, .share-current kbd, .shortcut-list, .keys-option { display: none; }
  .status-cell.found { position: relative; }
  .status-cell.found::before { content: ''; position: absolute; inset: -12px -2px; }
  .parts-list a { display: inline-block; padding: 12px 2px; margin: -12px -2px; }
  .maker-more { padding: 12px 0; margin: -12px 0; }
  .touch-note { display: block; }
}

@media (prefers-reduced-motion: reduce) {
  *, *:before, *:after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
}

/* The narrowest phones: the four tools give up four pixels each, so fumble
   stays on their row instead of taking one of its own. */
@media (max-width: 380px) {
  .icon-button, .sound-button { min-width: 40px; }
  .transport { gap: 8px; }
}

/* ------------------------------------------------------------ the machine */
/* The computer the window lives in: the owner's render of a clear home
   computer on the dusk sky, with fumble's window in its screen (machine.js
   frames it and places everything in whole pixels; make-computer.py cuts the
   render and measures the screen). The stage is the first screen of the page
   under the masthead, the full width of the viewport. */
.stage { position: relative; height: calc(100svh - 150px); overflow: clip; }
.machine { position: absolute; left: 0; top: 0; transform-origin: 0 0; }
.machine-art {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  pointer-events: none; user-select: none; -webkit-user-drag: none;
  filter: drop-shadow(0 28px 40px rgba(4, 3, 16, .5));
  transition: filter 1.4s steps(6, end);
}
/* Lights down: while a build plays the computer steps back a little and its
   screen is the brightest thing in the room. */
body.playing .machine-art { filter: drop-shadow(0 28px 40px rgba(4, 3, 16, .5)) brightness(.8) saturate(.9); }
/* The screen: dark glass over the render's "hello.", with the window inset
   from its rounded corners. A first visit sees "hello." until the screen
   comes on. */
.crt { position: absolute; background: #07060e; box-shadow: 0 0 0 1px rgba(0, 0, 0, .4), 0 0 26px rgba(130, 120, 255, .16); }
.crt-pending .crt { background: transparent; box-shadow: none; }
.crt-pending #crt .console { opacity: 0; }
#crt .console { position: absolute; inset: var(--crt-pad, 4px); display: flex; flex-direction: column; min-height: 0; margin: 0; }
#crt .screen { flex: 1 1 auto; height: auto; min-height: 0; }
#crt .transport, #crt .status-bar { flex: none; }
/* The keyboard's space bar presses fumble. */
.spacebar { position: absolute; padding: 0; border: 0; background: transparent; cursor: pointer; }
.spacebar:active { background: rgba(30, 22, 70, .16); box-shadow: inset 0 2px 8px rgba(0, 0, 0, .28); }
/* A phone: the window's controls in a dock under the computer's screen. */
.dock { display: none; }
body.docked .dock { display: block; position: relative; z-index: 1; margin: 6px 0 0; padding: 3px; background: var(--face); box-shadow: var(--raised); }
body.docked .dock .transport { padding: 6px 4px 4px; }
/* Maximised: the stage takes the whole viewport, the camera closes in, and
   the page behind waits. */
body.machine-focus { overflow: hidden; }
body.machine-focus .stage { position: fixed; inset: 0; z-index: 40; margin: 0 !important; width: 100vw !important; height: 100svh !important; }
body.machine-focus.docked .dock { position: fixed; left: 0; right: 0; bottom: 0; z-index: 41; margin: 0; }
/* On a desktop the stage's lower edge fades into the sky rather than slicing
   the keyboard (the screen is always well above it). */
body:not(.phone-machine) .stage { -webkit-mask-image: linear-gradient(to bottom, transparent, #000 40px, #000 calc(100% - 110px), transparent); mask-image: linear-gradient(to bottom, transparent, #000 40px, #000 calc(100% - 110px), transparent); }
/* A short desktop screen gives the computer the masthead's spare height. */
@media (min-width: 900px) and (max-height: 820px) { .masthead { min-height: 112px; } }
body.machine-focus .stage { -webkit-mask-image: none; mask-image: none; }
/* The narrowest phones: the window without its title bar. */
body.bare-window #crt .console-bar { display: none; }
/* A wide desktop: the caption beside the computer, level with its screen. */
main { position: relative; }
body.side-caption .now-playing { position: absolute; z-index: 2; flex-direction: column; align-items: stretch; gap: 14px; }
body.side-caption .now-playing { margin: 0; }
body.side-caption .now-playing .maker-block { max-width: none; align-items: flex-start; gap: 12px; padding-top: 10px; border-top: 1px solid var(--line, rgba(255, 255, 255, .08)); }
body.side-caption .now-playing .maker-id { align-items: flex-start; }
body.side-caption .now-playing .maker-more, body.side-caption .now-playing .made-by { text-align: left; }

/* ------------------------------------------------------- the water (trial) */
/* The owner's night water behind everything in place of the dusk sky
   (water.js): softly blurred and dimmed so the computer and the words stay in
   front, a little larger than the viewport so the blur's soft edge stays off
   screen. The lights still go down while a build plays. */
.water { position: fixed; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -3; pointer-events: none; display: none; transform: scale(1.08); filter: blur(var(--water-blur, 11px)) brightness(var(--water-dim, .55)) saturate(.9); }
html[data-bg=water] .water { display: block; }
html[data-bg=water] #atmosphere { background: #0a0c1c; }
html[data-bg=water] #atmosphere-motion { display: none; }
/* Maximised, the water dims further rather than going black. */
html[data-bg=water] body.focus-mode .reality-fade, html[data-bg=water] body.playing.focus-mode .reality-fade { opacity: .6; }

/* ----------------------------------------------------------------- landing */
/* What this place is, in a few lines, above the computer; the computer's top
   half shows under it until the first scroll brings it in (machine.js). */
/* The column sits centred over the computer; its lines run flush left, broken
   so that no word is left on a line by itself. */
.intro { max-width: 640px; margin: 4px auto 22px; padding: 0 12px; text-align: left; text-wrap: pretty; color: var(--ink-2); font: 17px/1.6 Georgia, "Times New Roman", serif; }
.intro p { margin: 0; }
.intro b { color: var(--ink); }
.intro .intro-small { margin-top: 10px; font: 13px/1.55 var(--ui); color: var(--ink-3); }
body.phone-machine .intro { margin: 0 auto 12px; font-size: 15px; }
body.phone-machine .intro .intro-small { font-size: 12px; }
/* While landing, the caption waits for the computer to come in. */
body.side-caption .now-playing { transition: opacity .3s; }
body.landing.side-caption .now-playing { opacity: 0; pointer-events: none; }
/* The window fills the computer's screen to its edges, its corners
   following the glass. */
#crt .console { inset: 0; padding: 0; box-shadow: none; border-radius: var(--crt-r, 8px); overflow: hidden; }
/* The maker on the window's bottom bar, one press from their videos. */
.status-cell.maker { flex: 0 1 auto; min-width: 0; max-width: 36%; color: var(--link); text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.status-cell.maker:hover #status-maker-name, .status-cell.maker:focus-visible #status-maker-name { text-decoration: underline; }
.maker-arrow { margin-left: 4px; font-size: 10px; color: var(--ink-3); }
/* A narrow window gives the maker the found tally's room. */
@container (max-width: 600px) { .status-cell.found { display: none; } }

/* ------------------------------------------------------------- the friends */
/* Physical AI Builders: the mascot as a die-cut sticker, the height of
   fumble's own mark, stuck on a little crooked in the top right. On hover (or
   focus) it straightens and the logo slides out from behind it to the right,
   into the margin and clear of the welcome, in the four frames of a 1998 GIF.
   app.js sizes the logo to the room between the sticker and the window's edge;
   where that is too narrow to read it stays tucked away, and a touch screen,
   which has no hover, never shows it. A press opens their site. */
.sticker { grid-area: sticker; align-self: center; position: relative; display: block; margin-left: 10px; transform: rotate(5deg); transition: transform .2s steps(3, end); filter: drop-shadow(0 3px 3px rgba(4, 3, 16, .55)); }
.sticker-art { display: block; height: calc(var(--mark-h, 82px) * 1.08); width: auto; }
/* At rest the logo is small and hidden behind the mascot; it grows out to the
   right from there, so no frame of the slide reaches left. */
.sticker-logo { position: absolute; z-index: -1; left: calc(100% - 22px); top: 18%; width: var(--logo-w, 230px); height: auto; max-width: none; opacity: 0; transform: translate(-46px, 10px) rotate(0deg) scale(.3); transform-origin: 0 0; pointer-events: none; transition: opacity .15s steps(3, end), transform .2s steps(4, end); filter: drop-shadow(0 8px 10px rgba(4, 3, 16, .5)); }
.sticker:hover, .sticker:focus-visible { transform: rotate(0deg) scale(1.04); }
.sticker:focus-visible .sticker-logo { opacity: 1; transform: translate(0, 0) rotate(7deg) scale(1); }
@media (hover: hover) { .sticker:hover .sticker-logo { opacity: 1; transform: translate(0, 0) rotate(7deg) scale(1); } }
.sticker[data-room=none] .sticker-logo { display: none; }
.sticker:focus-visible { outline: 1px dotted var(--ink); outline-offset: 4px; }
/* The essay the welcome quotes, its picture on hover as a card above the link
   (never below: the computer's screen is there). app.js fits the card to the
   room between the link and the window's top, and leaves it out where there
   is too little. The link's words stay on one line, so the card has one place
   to sit above. */
.intro a.essay-link { position: relative; white-space: nowrap; color: var(--ink); text-decoration: underline; text-decoration-color: var(--link); text-underline-offset: 3px; }
.intro a.essay-link:hover { color: #fff; }
.essay-card { position: absolute; z-index: 30; left: 50%; bottom: calc(100% + 12px); width: 260px; transform: translateX(-50%) translateY(6px); display: block; padding: 3px; background: #2a2440; box-shadow: var(--raised), 0 12px 28px rgba(4, 3, 16, .6); opacity: 0; pointer-events: none; transition: opacity .15s steps(3, end), transform .2s steps(3, end); text-align: left; white-space: normal; font: 12px/1.35 var(--ui); color: var(--ink-2); }
/* The picture in a bevelled frame, its caption laid over the glow below the
   keyboard, so the card is only as tall as the picture. */
.essay-card img { display: block; width: 100%; height: auto; }
.essay-caption { position: absolute; left: 3px; right: 3px; bottom: 3px; padding: 4px 8px 5px; background: rgba(20, 16, 38, .84); }
.essay-from { display: block; color: var(--ink-3); font-size: 11px; line-height: 1.25; }
.essay-title { display: block; font-weight: bold; color: #fff; font-size: 11px; line-height: 1.25; }
.intro a.essay-link:focus-visible .essay-card { opacity: 1; transform: translateX(-50%) translateY(0); }
@media (hover: hover) { .intro a.essay-link:hover .essay-card { opacity: 1; transform: translateX(-50%) translateY(0); } }
.intro a.essay-link[data-room=none] .essay-card { display: none; }
/* No hover, nothing to hover for: a touch screen goes straight to the link. */
@media (hover: none) { .sticker-logo, .essay-card { display: none; } }
/* A phone: the sticker smaller, beside the brand's second row; the window's
   edge is too close for the logo or the card. */
@media (max-width: 760px) {
  .sticker-art { height: 64px; }
  .sticker-logo, .essay-card { display: none; }
}

