/* SITE-006 "Darkroom Line" (her pick v3al, 2026-10-28). Grown from comps/al (AE + AC).
   Desktop: a big pinned print on the left changes with the block you are reading; under it a drying line
   of pegged, hand-labelled prints IS the nav. Phones: each block starts with its own pegged print, and the
   drying line sits at the bottom of the screen.
   Performance: transform/opacity only, no blur, no backdrop-filter, scroll work is one IntersectionObserver. */

/* Fonts, her pick 2026-10-28 03:35 (alg1 + Aclonica): Averia Libre page headings, Karla text,
   Coming Soon tape labels, Caveat Brush taglines (her 03:38), Aclonica subheadings and table keys. font-size-adjust keeps the measured
   Fraunces/Atkinson sizes so the layout holds (values from comps/fontround/g1 and g5). */
@font-face { font-family: "Averia Libre"; font-weight: 400; font-display: swap; src: url(fonts/averia-libre-400-normal.woff2) format("woff2"); }
@font-face { font-family: "Averia Libre"; font-style: italic; font-weight: 400; font-display: swap; src: url(fonts/averia-libre-400-italic.woff2) format("woff2"); }
@font-face { font-family: "Averia Libre"; font-weight: 700; font-display: swap; src: url(fonts/averia-libre-700-normal.woff2) format("woff2"); }
@font-face { font-family: "Averia Libre"; font-style: italic; font-weight: 700; font-display: swap; src: url(fonts/averia-libre-700-italic.woff2) format("woff2"); }
@font-face { font-family: "Karla"; font-weight: 200 800; font-display: swap; src: url(fonts/karla-vf-wght-normal.woff2) format("woff2"); }
@font-face { font-family: "Karla"; font-style: italic; font-weight: 200 800; font-display: swap; src: url(fonts/karla-vf-wght-italic.woff2) format("woff2"); }
@font-face { font-family: "Coming Soon"; font-display: swap; src: url(fonts/coming-soon-400.woff2) format("woff2"); }
@font-face { font-family: "Caveat Brush"; font-display: swap; src: url(fonts/caveat-brush-400.woff2) format("woff2"); }
@font-face { font-family: "Aclonica"; font-display: swap; src: url(fonts/aclonica-400.woff2) format("woff2"); }
/* OpenDyslexic 1.0.3 for the reading text, her call 2026-10-28 03:43 ("open dyslexic is just so much nicer on the eyes").
   npm open-dyslexic woff, Bitstream Vera licence alongside. Was the /al-od/ comp. */
@font-face { font-family: "OpenDyslexic"; font-display: swap; src: url(fonts/opendyslexic-regular.woff) format("woff"); }
@font-face { font-family: "OpenDyslexic"; font-style: italic; font-display: swap; src: url(fonts/opendyslexic-italic.woff) format("woff"); }
@font-face { font-family: "OpenDyslexic"; font-weight: 700; font-display: swap; src: url(fonts/opendyslexic-bold.woff) format("woff"); }
@font-face { font-family: "OpenDyslexic"; font-style: italic; font-weight: 700; font-display: swap; src: url(fonts/opendyslexic-bolditalic.woff) format("woff"); }
@font-face { font-family: "JetBrains Mono"; font-weight: 400 600; font-display: swap; src: url(fonts/jetbrainsmono-400-600-latin.woff2) format("woff2"); }

:root {
  /* P1 "Oil & Copper", her pick 2026-10-28 04:40 (no purple: her 03:47 "purple is like ai-default").
     Neutral warm black, copper type, her red eyes mark the current print. From comps/make_palettes.py PAL["p1"]. */
  --ground: #11100f; --dark: #0a0a09; --bar-bg: #11100ff0;
  --acc: #d0915a; --hi: #ecb07c; --text: #e6ded4; --dim: #a39a8f; --faint: #5f5850; --rule: #2c2824;
  --paper: #1e1b18; --paper-edge: #3b342c;          /* print borders: dark, never a white flash */
  --tape: #d9c7a2; --ink: #231a12;                   /* the hand-written labels */
  --focus: #6fc3d6;
  --line-edge: #26221f; --games-rule: #36312c; --intro: #ece3d8; --cap: #d8cfc4; --quote: #d6ccc0; --lb: #090908;
  --cord: #b39a7c88; --cur: #cf3a3f;       /* --cur marks the current stop on the line */
  --bar: 0px; --dl: 182px; --mini: min(5.2vw, 68px); --slot: calc(46vw / 8);   /* 8 stops: links is 2nd */
}
*, *::before, *::after { box-sizing: border-box; }
html { scroll-padding-top: calc(var(--bar) + 14px); }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
body { margin: 0; background: var(--ground); color: var(--text); font: 18px/1.65 "OpenDyslexic", sans-serif; font-size-adjust: ex-height 0.51; }
img { display: block; max-width: 100%; height: auto; }
figure { margin: 0; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
.skip { position: fixed; left: 12px; top: -60px; z-index: 60; padding: 8px 14px; background: var(--hi); color: var(--ink); text-decoration: none; }
.skip:focus { top: 10px; }

/* the hand-written photo-book label: tape strip, ink handwriting */
.tag {
  display: inline-block; padding: 1px 7px 2px; font: 17px/1.15 "Coming Soon", cursive; font-size-adjust: cap-height 0.62; color: var(--ink);
  background: var(--tape); box-shadow: 0 1px 2px #0007; transform: rotate(-2deg);
}

/* ---------- no top bar (her 03:43 "Do we even really need the header?") ----------
   The pegged prints are the nav and the hero h1 is the title. A small Glompy + name badge sits in the print's
   top-left corner (back to the top), and under it the showcase stubs (Y3, her 04:13/04:40): visible at the top,
   hidden once you have scrolled past the links block, back while the badge is hovered, focused or tapped. */
.top { position: fixed; top: 14px; left: 16px; z-index: 30; }
.mark { display: flex; align-items: center; gap: 12px; width: fit-content; padding: 4px 12px 4px 5px; border-radius: 20px; text-decoration: none;
        background: color-mix(in srgb, var(--dark) 70%, transparent); }
.mark svg { filter: drop-shadow(0 0 1px var(--acc)) drop-shadow(0 0 1px var(--acc)); }
.mark span { font: 700 15px "Averia Libre"; font-size-adjust: cap-height 0.71; color: var(--hi); }
.stubs { position: absolute; top: 100%; left: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
         width: max-content; margin: 0; padding: 16px 0 0; list-style: none;
         transition: opacity .25s, translate .25s, visibility 0s 0s; }
.stubs .head { margin: 0 0 -2px 4px; font: 500 11px "JetBrains Mono"; letter-spacing: .12em; text-transform: uppercase; color: var(--hi);
               text-shadow: 0 1px 3px #000, 0 0 8px #000; }
.stubs a { display: flex; align-items: center; gap: 8px; padding: 4px 12px 5px 5px; text-decoration: none; color: var(--ink);
           background: var(--tape); box-shadow: 0 2px 6px #000a; font: 16px/1.1 "Coming Soon", cursive; }
.stubs li:nth-child(even) a { transform: rotate(-2deg); } .stubs li:nth-child(odd) a { transform: rotate(1.5deg); }
.stubs img { width: 34px; height: 34px; object-fit: cover; }
.stubs .play { display: grid; place-items: center; width: 34px; height: 34px; background: var(--ink); color: var(--tape); }
.stubs a:hover, .stubs a:focus-visible { background: var(--hi); }
/* past the links block: tucked away (not focusable while hidden), back on hover / keyboard focus / tap (.open) */
.top.past .stubs { opacity: 0; translate: 0 -6px; visibility: hidden; pointer-events: none;
                   transition: opacity .25s, translate .25s, visibility 0s .25s; }
.top.past:focus-within .stubs, .top.past.open .stubs { opacity: 1; translate: 0 0; visibility: visible; pointer-events: auto; transition-delay: 0s; }
.top.past:hover .stubs { opacity: 1; translate: 0 0; visibility: visible; pointer-events: auto; transition-delay: 0s; }

/* ---------- the pinned print (desktop) ---------- */
.print { position: fixed; left: 0; top: var(--bar); bottom: var(--dl); width: 46vw; overflow: hidden; background: var(--dark); }
.pin { position: absolute; inset: 0; }
.pin figure { position: absolute; inset: 0; opacity: 0; transition: opacity .6s; }
.pin figure.on { opacity: 1; }
.pin img { width: 100%; height: 100%; object-fit: cover; }
.pin::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, transparent 62%, var(--ground) 100%), linear-gradient(0deg, color-mix(in srgb, var(--ground) 95%, transparent) 0, transparent 30%); pointer-events: none; }
/* The big print is display only (her 10-28 19:45: "shouldn't click into the modal, because it's too easy to accidentally
   click"). No click target, no zoom cursor, nothing focusable; the MV print on the links stop is inert too (the MV stays
   on its Watch card and the showcase stub). Phone prints, strips and the wall still open the zoom view. */
.caption { position: absolute; left: 32px; right: 60px; bottom: 18px; z-index: 2; display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: baseline; margin: 0; pointer-events: none; }
.caption .tag { font-size: 24px; padding: 2px 12px 3px; }
.cap-num { font: 500 12px "JetBrains Mono"; color: var(--acc); }
.cap-alt { flex-basis: 100%; font: italic 15px/1.45 "OpenDyslexic"; font-size-adjust: ex-height 0.51; color: var(--cap); }

/* ---------- the drying line = the nav ---------- */
.dl { position: fixed; left: 0; bottom: 0; z-index: 20; width: 46vw; height: var(--dl); }
/* The panel's dark is a backdrop BEHIND the prints (z-index -1 inside the nav's own stacking context), faded out on its
   top and right so the line melts into the ground and the oil instead of cutting a box with a hard corner (her 05:10
   "this border ... looks harsh"). The mask is on this layer only: prints, tape labels and focus rings are untouched. */
.dl::before {
  content: ""; position: absolute; z-index: -1; inset: 0 -64px 0 0; pointer-events: none; background: var(--dark);
  mask-image: linear-gradient(to bottom, transparent, #000 44px), linear-gradient(to left, transparent, #000 128px);
  mask-composite: intersect;
}
.dl .cord { position: absolute; left: 16px; top: 16px; width: calc(100% - 32px); height: 32px; overflow: visible; }
.dl .cord path { fill: none; stroke: var(--cord); stroke-width: 1.2; }
.dl a {
  position: absolute; left: calc(16px + (100% - 32px) * var(--xf)); top: calc(18px + var(--y));
  display: flex; flex-direction: column; align-items: center; width: var(--slot);
  text-decoration: none; transform: translateX(-50%) rotate(var(--rot)); transform-origin: 50% 0;
}
.dl a:focus-visible { outline: none; }
.dl a:focus-visible .mini { outline: 2px solid var(--focus); outline-offset: 3px; }
.mini { position: relative; display: block; width: var(--mini); padding: 4px; background: var(--paper); box-shadow: 0 0 0 1px var(--paper-edge), 0 10px 18px #000b; opacity: .6; transition: opacity .25s; }
.mini img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; }
.dl .tag { position: relative; z-index: 1; max-width: calc(var(--slot) - 4px); margin-top: -7px; text-align: center; font-size: 15px; transform: rotate(calc(var(--rot) * -1.3)); }
.dl a:hover .mini, .dl a:focus-visible .mini, .dl a[aria-current] .mini { opacity: 1; }
.dl a[aria-current] .mini { box-shadow: 0 0 0 1px var(--cur), 0 10px 18px #000b; }
.dl a[aria-current] { animation: nod .9s ease-out; }
@keyframes nod {
  0% { transform: translateX(-50%) rotate(var(--rot)); }
  30% { transform: translateX(-50%) rotate(calc(var(--rot) + 3deg)); }
  65% { transform: translateX(-50%) rotate(calc(var(--rot) - 1.2deg)); }
  100% { transform: translateX(-50%) rotate(var(--rot)); }
}
.peg { position: absolute; left: 50%; top: -9px; z-index: 2; width: 7px; height: 18px; margin-left: -3.5px; border-radius: 2px; background: linear-gradient(90deg, #7a5c40, #a07a54 50%, #6d5139); }
.dl a .peg { top: -9px; }
.dl a[aria-current] .peg { background: var(--cur); }

/* ---------- the reading column ---------- */
.text { margin-left: 46vw; padding: 0 56px 30vh; }
/* Blocks size to their content (her 10-28 19:49 "not have as huge of a null space"): was min-height 72vh + 12vh padding,
   which left up to ~590px of empty dark between blocks. The gap between two blocks is now just this padding (well under a
   fifth of the screen). The hero is no longer a full centred screen either, but stays tall enough to hold the reading
   band (45% down) at the top of the page, so the first print is still "it's me". */
.block { max-width: calc(720px - 2 * var(--oil-a-gutter)); min-height: 0; padding-top: clamp(56px, 9vh, 110px); }   /* reading width unchanged (was .text max-width 720) */
.hero { min-height: 0; display: flex; flex-direction: column; padding-top: calc(var(--bar) + clamp(64px, 13vh, 150px)); }
.inline { display: none; }
h1 { margin: 0 0 28px; font: 700 108px/.9 "Averia Libre"; font-size-adjust: cap-height 0.71; letter-spacing: -.01em; color: var(--hi); }
h2 { margin: 0 0 20px; font: 64px/1 "Aclonica"; font-size-adjust: cap-height 0.611; color: var(--hi); }
h3 { margin: 0 0 12px; font: 34px "Aclonica"; font-size-adjust: cap-height 0.611; color: var(--hi); }
.intro { margin: 0 0 28px; font: 400 21px/1.55 "OpenDyslexic"; font-size-adjust: ex-height 0.51; color: var(--intro); }
.games { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 0 0 30px; padding: 12px 0 0; list-style: none; border-top: 1px solid var(--games-rule); font: 13px "JetBrains Mono"; color: var(--dim); }
.games-more { width: 100%; font: italic 14px "OpenDyslexic"; font-size-adjust: ex-height 0.51; }
.quotes blockquote { margin: 0 0 14px; padding-left: 16px; border-left: 2px solid var(--hi); font: 22px/1.3 "Caveat Brush", cursive; color: var(--quote); }
.quotes p, .prose { margin: 0; }
.para { display: block; margin-bottom: 8px; font: 500 12px "JetBrains Mono"; letter-spacing: .1em; color: var(--acc); }

.spec { width: 100%; border-collapse: collapse; }
.spec th { text-align: left; padding-bottom: 10px; font: 34px "Aclonica"; font-size-adjust: cap-height 0.611; color: var(--hi); }
.spec td { padding: 10px 0; border-bottom: 1px solid var(--rule); }
.spec td:first-child { width: 40%; padding-right: 12px; font: 15px/1.35 "Aclonica"; letter-spacing: .02em; color: var(--dim); }

.abilities { width: 100%; margin-top: 40px; border-collapse: collapse; }
.abilities th { text-align: left; padding-bottom: 10px; font: 34px "Aclonica"; font-size-adjust: cap-height 0.611; color: var(--hi); }
.abilities td { padding: 14px 0; vertical-align: top; border-bottom: 1px solid var(--rule); font-size: 16px; line-height: 1.55; }
.abilities td:first-child { width: 32%; padding-right: 18px; font: 17px/1.3 "Aclonica"; color: var(--hi); }

/* strips and the wall: prints at their own shape, never cropped */
.strip, .wall { margin: 0; padding: 0; list-style: none; }
.strip { display: flex; gap: 12px; margin-top: 30px; }
.strip li { flex: var(--r) 1 0; min-width: 0; }
.strip li:nth-child(odd) a { transform: rotate(-.7deg); }
.strip li:nth-child(even) a { transform: rotate(.6deg); }
.strip a, .wall a { display: block; padding: 4px; background: var(--paper); box-shadow: 0 0 0 1px var(--paper-edge), 0 8px 14px #0009; cursor: zoom-in; }
.strip img, .wall img { width: 100%; }
/* world pictures under each story part (her 20:01): big enough to see, natural aspect, never cropped. Wide ones take a
   full row, squares pair up. */
.strip.world { flex-wrap: wrap; gap: 14px; margin-top: 26px; }
.strip.world li { flex: var(--r) 1 calc(var(--r) * 260px); }
.wall { columns: 3; column-gap: 14px; }
.wall li { break-inside: avoid; margin-bottom: 14px; }
.pixel img { image-rendering: pixelated; }
.wall .pixel a { padding: 18px; }
.endmark { display: block; margin: 50px auto 0; opacity: .7; }
/* her 10-28 05:26: a small "made with love by Glompy" under the bottom Glompy mark */
.madeby { margin: 8px 0 0; text-align: center; font: 14px/1.3 "Coming Soon", cursive; font-size-adjust: cap-height 0.62; color: var(--dim); }

/* ---------- her lore (approved 10-28 20:10, from the /al-lore/ draft) ----------
   personality line + tape asides, world-slipping line, "her Tharron kit" heading, signature marks, and the scrapbook
   notes on the big prints (build_al.py renders them from the note lines in al/art.txt). Notes never move. */
.habits { margin-top: 18px !important; padding-top: 2px; }
.aside { display: table; margin: 26px 0 0 4px; padding: 5px 14px 7px; max-width: 30em; font: 18px/1.35 "Coming Soon", cursive;
         font-size-adjust: cap-height 0.62; color: var(--ink); background: var(--tape); box-shadow: 0 2px 6px #000a;
         transform: rotate(-1.2deg); }
.aside + .aside { margin-top: 18px; transform: rotate(.9deg); }
@media (max-width: 760px) { .aside { font-size: 16px; } }
.worlds { margin-top: 16px !important; }
.kit-sub { display: block; margin-top: 4px; font: 400 18px "Coming Soon", cursive; color: var(--cap); }
.kit-lead { display: block; margin: 8px 0 6px; font: 400 16px/1.55 "OpenDyslexic", sans-serif; font-size-adjust: ex-height 0.51; color: var(--cap); }
.abilities .sig { display: block; margin-top: 4px; font: 11px "JetBrains Mono", monospace; letter-spacing: .06em; text-transform: uppercase; }
.abilities .sig { color: var(--acc); }
/* scrapbook notes: paper and tape from the P1 page, Coming Soon hand, still (no idle motion) */
.pin figure .note, .inline .note { position: absolute; z-index: 3; pointer-events: none; transform: rotate(var(--r));
  font: 400 clamp(13px, 1.05vw, 18px)/1.2 "Coming Soon", cursive; font-size-adjust: cap-height 0.62; color: var(--ink); }
.inline a { position: relative; }
.inline .note { font-size: 13px; }
.note.sticky { width: 8.6em; padding: .9em .8em 1.1em; background: #cdbb8f; box-shadow: 0 8px 16px #000b, inset 0 -10px 14px -12px #0006; }
.note.sticky::before { content: ""; position: absolute; left: 50%; top: -.55em; width: 3.4em; height: 1.1em; translate: -50% 0; rotate: 3deg;
  background: color-mix(in srgb, var(--tape) 60%, transparent); box-shadow: 0 1px 3px #0005; }
.note.sticky.sage { background: #a3ab8e; }
.note.tape { padding: .3em 1em .45em; white-space: nowrap; background: color-mix(in srgb, var(--tape) 88%, transparent);
  box-shadow: 0 3px 8px #0009;
  clip-path: polygon(0 8%, 3% 0, 6% 10%, 9% 0, 91% 0, 94% 9%, 97% 0, 100% 8%, 100% 92%, 97% 100%, 94% 90%, 91% 100%, 9% 100%, 6% 91%, 3% 100%, 0 92%); }
.note.heart { width: clamp(30px, 2.8vw, 46px); filter: drop-shadow(0 4px 6px #000b); }
.note.heart svg { display: block; fill: #8c3a35; stroke: #d9c7a2; stroke-width: 1.2; stroke-dasharray: 2.5 2.5; }
.note.doodle { width: clamp(44px, 4.4vw, 70px); color: #eadfcb; opacity: .85; filter: drop-shadow(0 1px 2px #000c); }
.note.doodle svg { display: block; width: 100%; height: auto; }

/* ---------- lightbox ----------
   Her 16:32 (on her phone): closing wasn't obvious and the big prints opened with no description. So: a solid close
   button with an X in the top-right corner (always on screen, 52px tall), a tap on the dark around the picture closes,
   Escape closes, and her phone's back button closes it (site.js pushes a history entry while it is open). No swipes.
   Every picture shows its description under it (the alt text from al/art.txt; prints add their tape label). */
.lightbox { position: fixed; inset: 0; z-index: 100; display: grid; grid-template-rows: auto minmax(0, 1fr) auto auto; background: var(--lb); color: var(--text); }
.lightbox[hidden] { display: none; }
.lightbox-top { display: flex; justify-content: flex-end; padding: 12px 12px 0; }
.lightbox-close { display: inline-flex; align-items: center; gap: 10px; min-height: 52px; min-width: 52px; padding: 0 18px 0 14px; font: 600 16px "JetBrains Mono"; letter-spacing: .04em;
                  color: var(--hi); background: var(--paper); border: 2px solid var(--acc); border-radius: 26px; box-shadow: 0 4px 14px #000c; cursor: pointer; }
.lightbox-close .x { font-size: 22px; line-height: 1; }
.lightbox-close:hover { color: var(--ground); background: var(--hi); }
.lightbox-stage { display: flex; align-items: center; justify-content: center; min-height: 0; padding: 12px 16px; }
.lightbox-stage img { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; }
.lightbox-cap { max-width: 64ch; margin: 0 auto; padding: 2px 18px 0; font-size: 15px; line-height: 1.55; text-align: center; color: var(--cap); }
.lightbox-cap .tag { margin: 0 10px 4px 0; transform: rotate(-1.5deg); vertical-align: 1px; }
.lightbox-cap .tag:empty { display: none; }
.lightbox-bar { display: flex; justify-content: center; align-items: center; gap: 10px; padding: 12px 16px 20px; }
.lightbox-bar button { min-width: 104px; min-height: 48px; padding: 0 16px; font: 600 13px "JetBrains Mono"; text-transform: uppercase; letter-spacing: .06em; color: var(--text); background: transparent; border: 1px solid var(--rule); cursor: pointer; }
.lightbox-bar button:hover { color: var(--ground); background: var(--text); }
.lightbox-bar button:disabled { opacity: .3; cursor: default; }
.lightbox-bar button:disabled:hover { color: var(--text); background: transparent; }
.lightbox-count { min-width: 60px; text-align: center; font: 12px "JetBrains Mono"; color: var(--dim); }
body.lightbox-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .pin figure, .mini { transition: none; }
  .dl a[aria-current] { animation: none; }
}

/* ---------- narrower desktops ---------- */
@media (max-width: 1100px) and (min-width: 761px) {
  .text { padding: 0 32px 30vh; }
  h1 { font-size: 84px; }
  h2 { font-size: 52px; }
  .wall { columns: 2; }
  .dl .tag { font-size: 14px; }
}

/* ---------- phones ---------- */
@media (max-width: 760px) {
  :root { --dl: 112px; --mini: 30px; --slot: calc((100vw - 16px) / 8); }
  body { font-size: 16px; }
  .print { display: none; }
  .dl { width: auto; right: 0; height: calc(var(--dl) + env(safe-area-inset-bottom)); }
  .dl::before { inset: 0; mask-image: none; }   /* phones: the line spans the screen over the scrolling text, so it stays a solid strip (no line on top) */
  .dl .cord { left: 8px; width: calc(100% - 16px); top: 10px; height: 16px; }
  .dl a { left: calc(8px + (100% - 16px) * var(--xf)); top: calc(11px + var(--y) / 2); }
  .mini { padding: 3px; }
  .dl .tag { max-width: calc(var(--slot) + 6px); margin-top: -5px; padding: 1px 4px 2px; font-size: 13px; line-height: 1.05; }
  .text { margin: 0; padding: 0 18px calc(var(--dl) + 40px); }
  .block { min-height: 0; padding-top: 56px; }
  .hero { min-height: 0; padding-top: calc(var(--bar) + 20px); }
  .inline { display: block; position: relative; margin: 0 0 30px; }
  .inline a { display: block; padding: 6px; background: var(--paper); box-shadow: 0 0 0 1px var(--paper-edge), 0 10px 20px #000b; transform: rotate(-.6deg); }
  .block:nth-child(even) .inline a { transform: rotate(.5deg); }
  .inline img { width: 100%; aspect-ratio: var(--pr); object-fit: cover; }
  .inline .peg { top: -10px; }
  .inline .tag { position: absolute; right: 14px; bottom: -14px; z-index: 2; font-size: 21px; padding: 1px 10px 3px; }
  h1 { font-size: 68px; }
  h2 { font-size: 48px; }
  h3 { font-size: 30px; }
  .intro { font-size: 19px; }
  .spec th, .abilities th { font-size: 30px; }
  .abilities td { display: block; width: auto !important; padding: 0; border: 0; }
  .abilities tr { display: block; padding: 12px 0; border-bottom: 1px solid var(--rule); }
  .abilities td:first-child { padding-bottom: 4px; }
  .strip { flex-wrap: wrap; gap: 10px; margin-top: 22px; }
  .strip li { flex: var(--r) 1 calc(var(--r) * 130px); }
  .strip.world li { flex-basis: calc(var(--r) * 200px); }
  .wall { columns: 2; column-gap: 10px; }
  .wall li { margin-bottom: 10px; }
  .lightbox-top { padding: 10px 10px 0; }
  .lightbox-stage { padding: 10px 10px; }
  .lightbox-cap { font-size: 14px; padding: 0 14px; }
  .lightbox-bar { gap: 8px; padding: 10px 10px calc(14px + env(safe-area-inset-bottom)); }
  .lightbox-bar button { min-width: 0; padding: 0 12px; }
  .lightbox-count { min-width: 40px; }
}

/* phones: no badge at the top (the h1 is the title); the stubs are a row above her first print (Y3's phone layout).
   Once they scroll away the badge comes back, fixed in the corner, and a tap on it brings the stubs down under it. */
@media (max-width: 760px) {
  .top { position: absolute; top: 0; left: 18px; right: 18px; }
  .top .mark { display: none; }
  .stubs { position: static; flex-direction: row; flex-wrap: wrap; align-items: center; width: auto; padding: 20px 0 0; }
  .stubs .head { width: 100%; margin: 0 0 -2px 2px; }
  .stubs a { font-size: 15px; max-width: calc(100vw - 36px); }
  .hero { padding-top: calc(var(--sch, 92px) + 14px); }   /* --sch: the stubs' height, measured by site.js */
  .top.past { position: fixed; top: 10px; left: 10px; right: auto; }
  .top.past .mark { display: flex; }
  .top.past .stubs { position: absolute; top: 100%; left: 0; flex-direction: column; align-items: flex-start; width: max-content; padding-top: 12px; }
}

/* ---------- links: "elsewhere", the 2nd print on the line (Y1, her 04:04 + 04:40) ----------
   Grouped Watch / Mods / Games, one short cord per group. A row holds (columns - 1) cards and the last column is a
   "+N more" peg that unfolds the rest (site.js), so a group stays one row however many links it gets. */
.lsub { margin: -8px 0 26px; font: 13px "JetBrains Mono"; color: var(--dim); }
.lgroup { position: relative; margin: 0 0 30px; padding-top: 6px; }
.lgroup[hidden] { display: none; }
.lgroup > .tag { position: relative; z-index: 3; margin: 0 0 0 -4px; font-size: 18px; }
.lgroup .n { font: 12px "JetBrains Mono"; color: var(--acc); margin-left: 10px; }
.lcord { display: block; width: 100%; height: 18px; margin-top: -6px; overflow: visible; }
.lcord path { fill: none; stroke: var(--cord); stroke-width: 1.2; }
.lrow { --cols: 5; display: grid; grid-template-columns: repeat(var(--cols), minmax(0, 1fr)); gap: 18px 14px; margin: -6px 0 0; padding: 0; list-style: none; }
.lrow li { min-width: 0; }
.lrow li[hidden] { display: none !important; }
.lrow li.feat { grid-column: span 2; }
.lcard { position: relative; display: flex; flex-direction: column; align-items: center; width: 100%; padding: 0; border: 0; background: none; color: inherit; font: inherit; text-decoration: none; cursor: pointer; }
.lrow li:nth-child(odd) .lcard { transform: rotate(-1.4deg); } .lrow li:nth-child(even) .lcard { transform: rotate(1.1deg); margin-top: 5px; }
.lcard .pic { position: relative; display: block; width: 100%; padding: 4px; background: var(--paper); box-shadow: 0 0 0 1px var(--paper-edge), 0 8px 14px #000b; }
.lcard img, .lcard .ph { width: 100%; aspect-ratio: 1; object-fit: cover; }
.feat .lcard img { aspect-ratio: 2.06; }
.lcard .ph { display: grid; place-items: center; border: 1px dashed var(--faint); color: var(--dim); font: 20px "Aclonica"; }
.lcard .tag { max-width: 100%; margin-top: -9px; font-size: 14px; text-align: center; overflow-wrap: anywhere; }
.lcard small { margin-top: 4px; font: 11px/1.3 "JetBrains Mono"; color: var(--dim); text-align: center; }
.lcard .play { position: absolute; left: 12px; bottom: 12px; display: grid; place-items: center; width: 46px; height: 46px; border-radius: 50%; background: var(--acc); color: var(--ink); font-size: 19px; box-shadow: 0 4px 12px #000a; }
.lcard:hover .pic, .lcard:focus-visible .pic { box-shadow: 0 0 0 1px var(--acc), 0 8px 14px #000b; }
.lcard:focus-visible { outline: none; } .lcard:focus-visible .pic { outline: 2px solid var(--focus); outline-offset: 3px; }
.more .pic { display: grid; place-items: center; aspect-ratio: 1; background: var(--dark); border: 1px dashed var(--faint); box-shadow: none; }
.more .pic b { font: 22px "Aclonica"; color: var(--hi); }
.lrow li.more { display: none; }
.lrow li.more.show { display: block; }
@media (max-width: 1100px) and (min-width: 761px) { .lrow { --cols: 4; } }
@media (max-width: 760px) {
  #b-links .inline { display: none; }
  .lrow { --cols: 4; gap: 16px 10px; }
  .lcard .tag { font-size: 12px; padding: 1px 4px 2px; }
  .lcard small { display: none; }
  .lcard .play { width: 34px; height: 34px; font-size: 14px; }
  .more .pic b { font-size: 17px; }
}

/* ---------- the oil (her pick alo3 = Codex's C1 "Still Oil", 2026-10-28 04:40: "just something to fill the void") ----------
   Verbatim from comps/oilround/codex-a.css (Codex gpt-6.1-sol, drawn blind from the brief). */
/* Still oil. Broad, overlapping pools make the reading side feel like a dark liquid surface,
   with a faint pewter reflection confined to the curved edges. P1's copper, paper, red current
   print and fonts stay intact; this is a static background, never a coating over the artwork. */

/* The gutter follows the existing column padding, so the texture ends at the print boundary.
   The SVG fades at its perimeter to avoid rectangular joins. Each surface scrolls with its block; there are no fixed effect layers or SVG filters. */
/* Right edge (her 05:10 "take up all the page if there is space on the right"): the column spans to the viewport's
   right edge (no max-width) while .block keeps the reading width, and the oil reaches past the block to the column's
   edge: 100cqw is the column's content width, 100% the block's. Container units, not vw, so a desktop scrollbar never
   pushes it past the edge; overflow-x: clip is the backstop for the drift's transform. */
.text { --oil-a-gutter: 56px; container-type: inline-size; overflow-x: clip; }
.block { position: relative; isolation: isolate; }
.block::before {
  content: "";
  position: absolute;
  z-index: -1;
  pointer-events: none;
  inset: 0 calc(100% - 100cqw - var(--oil-a-gutter)) 0 calc(0px - var(--oil-a-gutter));
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22960%22%20height%3D%221100%22%20viewBox%3D%220%200%20960%201100%22%20preserveAspectRatio%3D%22none%22%3E%0A%3Cdefs%3E%0A%20%3CradialGradient%20id%3D%22surface%22%20cx%3D%22.88%22%20cy%3D%22.18%22%20r%3D%22.88%22%3E%3Cstop%20stop-color%3D%22%2320221e%22%2F%3E%3Cstop%20offset%3D%22.38%22%20stop-color%3D%22%23101310%22%2F%3E%3Cstop%20offset%3D%22.78%22%20stop-color%3D%22%23090b0a%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2311100f%22%2F%3E%3C%2FradialGradient%3E%0A%20%3ClinearGradient%20id%3D%22edge%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%221%22%20y2%3D%22.6%22%3E%3Cstop%20stop-color%3D%22%2311100f%22%20stop-opacity%3D%220%22%2F%3E%3Cstop%20offset%3D%22.43%22%20stop-color%3D%22%2344483f%22%20stop-opacity%3D%22.4%22%2F%3E%3Cstop%20offset%3D%22.72%22%20stop-color%3D%22%2334403c%22%20stop-opacity%3D%22.52%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2311100f%22%20stop-opacity%3D%220%22%2F%3E%3C%2FlinearGradient%3E%0A%20%3ClinearGradient%20id%3D%22fold%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%22.8%22%20y2%3D%221%22%3E%3Cstop%20stop-color%3D%22%23292a23%22%2F%3E%3Cstop%20offset%3D%22.22%22%20stop-color%3D%22%23151814%22%2F%3E%3Cstop%20offset%3D%22.7%22%20stop-color%3D%22%230a0c0b%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2311100f%22%20stop-opacity%3D%220%22%2F%3E%3C%2FlinearGradient%3E%0A%3ClinearGradient%20id%3D%22fade-x%22%3E%3Cstop%20stop-color%3D%22white%22%20stop-opacity%3D%220%22%2F%3E%3Cstop%20offset%3D%22.06%22%20stop-color%3D%22white%22%2F%3E%3Cstop%20offset%3D%22.94%22%20stop-color%3D%22white%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22white%22%20stop-opacity%3D%220%22%2F%3E%3C%2FlinearGradient%3E%0A%3ClinearGradient%20id%3D%22fade-y%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20stop-color%3D%22white%22%20stop-opacity%3D%220%22%2F%3E%3Cstop%20offset%3D%22.06%22%20stop-color%3D%22white%22%2F%3E%3Cstop%20offset%3D%22.9%22%20stop-color%3D%22white%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22white%22%20stop-opacity%3D%220%22%2F%3E%3C%2FlinearGradient%3E%0A%3Cmask%20id%3D%22mx%22%3E%3Crect%20width%3D%22960%22%20height%3D%221100%22%20fill%3D%22url%28%23fade-x%29%22%2F%3E%3C%2Fmask%3E%0A%3Cmask%20id%3D%22my%22%3E%3Crect%20width%3D%22960%22%20height%3D%221100%22%20fill%3D%22url%28%23fade-y%29%22%2F%3E%3C%2Fmask%3E%0A%3C%2Fdefs%3E%3Cg%20mask%3D%22url%28%23mx%29%22%3E%3Cg%20mask%3D%22url%28%23my%29%22%3E%0A%3Cpath%20fill%3D%22url%28%23surface%29%22%20d%3D%22M960%200H488C637%2026%20699%2089%20655%20174C605%20272%20397%20256%20425%20374C449%20476%20784%20394%20823%20533C863%20677%20676%20725%20596%20820C535%20893%20671%201022%20960%201100Z%22%2F%3E%0A%3Cpath%20fill%3D%22url%28%23fold%29%22%20opacity%3D%22.65%22%20d%3D%22M960%2030C693%202%20785%20175%20614%20260C453%20340%20602%20447%20749%20426C622%20406%20539%20354%20659%20286C852%20177%20741%2097%20960%20110Z%22%2F%3E%0A%3Cpath%20fill%3D%22none%22%20stroke%3D%22url%28%23edge%29%22%20stroke-width%3D%222.5%22%20d%3D%22M488%200C637%2026%20699%2089%20655%20174C605%20272%20397%20256%20425%20374C449%20476%20784%20394%20823%20533C863%20677%20676%20725%20596%20820C535%20893%20671%201022%20960%201100%22%2F%3E%0A%3Cpath%20fill%3D%22none%22%20stroke%3D%22url%28%23edge%29%22%20stroke-width%3D%221.2%22%20opacity%3D%22.65%22%20d%3D%22M637%201C753%2061%20724%20136%20674%20199C593%20303%20487%20291%20487%20359C489%20408%20625%20421%20732%20407%22%2F%3E%0A%3Cpath%20fill%3D%22none%22%20stroke%3D%22%2344483f%22%20stroke-opacity%3D%22.23%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20d%3D%22M435%20330C423%20365%20449%20394%20497%20401M798%20511C826%20551%20805%20606%20779%20634M599%20843C586%20877%20608%20909%20647%20936%22%2F%3E%0A%3Cpath%20fill%3D%22%230b0c0a%22%20d%3D%22M960%20554C912%20563%20870%20612%20885%20654C897%20686%20939%20687%20960%20668Z%22%2F%3E%0A%3Cpath%20fill%3D%22none%22%20stroke%3D%22%23404338%22%20stroke-opacity%3D%22.26%22%20stroke-width%3D%221.5%22%20d%3D%22M960%20554C912%20563%20870%20612%20885%20654%22%2F%3E%0A%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E");
  background-repeat: no-repeat;
  background-position: right top;
  background-size: 100% 100%;
  max-height: 1100px;
}
/* Reverse alternate pools rather than repeating a visible wallpaper tile. */
.block:nth-child(even)::before { transform: scaleX(-1); opacity: .72; }
.hero::before { opacity: 1; }

/* (Codex's C1 also stopped the line's nod here. Removed 10-28 06:3x: she missed it, "jiggled SLIGHTLY" is the nod
   above, not AC's big swing. Reduced motion still turns it off.) */

/* desktop: push the SVG's own 6% edge fade past the window edge (clipped by .text), so the oil runs right up to it
   instead of darkening in its last ~50px. 7% of the layer's width covers the 6% fade with room for the drift. */
@media (min-width: 761px) {
  .block::before { right: calc(100% - 100cqw - var(--oil-a-gutter) - .07 * (100cqw + 2 * var(--oil-a-gutter))); }
}
@media (max-width: 1100px) and (min-width: 761px) {
  .text { --oil-a-gutter: 32px; }
}
@media (max-width: 760px) {
  .text { --oil-a-gutter: 18px; }
  .block::before { background-size: 100% 760px; max-height: none; }
  /* Put the hero reflection alongside the title, below the phone's pegged print. */
  .hero::before { background-position: right calc((100vw - 48px) / .8 + 20px); }
}

/* ---------- /al-flow/: the same oil, drifting VERY slowly (her 04:40 "slowly enough to not be distracting") ----------
   Only the oil layer moves, and only by transform, so the compositor does it: no repaint, no filters, no script per
   frame. Text and photos stay put. Off with prefers-reduced-motion; site.js pauses it while the tab is hidden. */
@media (prefers-reduced-motion: no-preference) {
  .flow .block::before { will-change: transform; animation: oil-drift 96s ease-in-out infinite alternate; }
  .flow .block:nth-child(even)::before { animation-name: oil-drift-r; animation-duration: 118s; }
  .flow .block:nth-child(3n)::before { animation-duration: 134s; animation-delay: -40s; }
  .flow.paused .block::before { animation-play-state: paused; }
}
@keyframes oil-drift {
  from { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); }
  to   { transform: translate3d(-4%, 3%, 0) rotate(-1.5deg) scale(1.07); }
}
/* the even blocks are C1's mirrored pools, so the mirror stays in the transform */
@keyframes oil-drift-r {
  from { transform: scaleX(-1) translate3d(0, 0, 0) rotate(0deg) scale(1); }
  to   { transform: scaleX(-1) translate3d(-4%, -3%, 0) rotate(1.5deg) scale(1.07); }
}
@media (max-width: 760px) {
  .flow .block::before { max-height: 760px; }   /* the texture only covers the top 760px on phones; keep the moving layer that small */
}
