/* Margin — token layer, base type, and canvas chrome.
   The five canonical colours are law (see DESIGN.md). Every other value is a
   named derivation declared below with a reason. Replaces the "Classical"
   styles.css, which was a different system entirely: Cormorant Garamond + Lora
   on grey with a gold accent, no monospace face, and a .plate class that
   applied sepia() to the photograph.

   Layered so a component can never accidentally out-rank a token, and so
   growth doesn't turn into a specificity argument. Order is the cascade order:
   later layers win, regardless of selector weight.

     tokens      :root only
     base        elements and type roles
     components  things you can name and reuse
     layout      structure, the reader grid, the breakpoints
     utilities   preview chrome — mockups and the dev index, never the product */

@import url('https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=DM+Mono:ital,wght@0,400;0,500;1,400&display=swap');

@layer tokens, base, components, layout, utilities;

@layer tokens {
  :root {
    /* the five. law. */
    --paper:  #F6F1E7;
    --ink:    #221D15;
    --muted:  #6F6759;  /* A75: darkened from #8A8171 so grey text reads (4.9:1 on paper) */
    --rule:   #E3DBCC;
    --rubric: #A8371F;

    /* declared derivations. six (the sixth, --paper-print, by A86). a seventh is a design finding, not a shade. */
    --paper-raised:   #FBF7EE;  /* a sheet sitting on the page */
    --paper-sunk:     #EFE8D8;  /* an inset well: image slot, input trough */
    --ink-pressed:    #332C20;  /* pressed state, filled ink button */
    --rubric-pressed: #8F2C17;  /* pressed state, rubric link */
    --evergreen:      #4F6352;  /* the leaves around the title-page name, and nothing else */
    --paper-print:    #FDFBF6;  /* A86: a Polaroid's face — the brightest paper, never pure white (D3); plates only */

    /* the pigments (A73). Five colours that exist only inside the desk's
       drawings, and only while one is played: the illumination in an
       illuminated margin. At rest every drawing is paper and ink. Never on
       text, a control, or a photograph. Shaded only by mixing with paper or ink. */
    --pigment-ochre:     #E2A64A;
    --pigment-rose:      #E08A78;
    --pigment-verdigris: #5EA892;
    --pigment-lapis:     #5C80C4;
    --pigment-lilac:     #A68AC6;

    --font-read:     'Instrument Serif', Georgia, serif;
    --font-annotate: 'DM Mono', ui-monospace, SFMono-Regular, monospace;

    /* TYPE SCALE — FLUID, ALL OF IT.

       The old scale pinned everything below the two display sizes, on the
       argument that a label which grows with the viewport stops reading as a
       label. The argument is half right and the half it gets wrong is the
       expensive one: a phone is held at 30cm and a laptop sits at 60, so the
       SAME px is half the apparent size on the bigger screen. Holding a 9.5px
       eyebrow constant across that range does not keep it looking like a label
       — it makes it unreadable on the machine most testers open first.

       So every step scales, and the ratio between steps is preserved, which is
       what actually keeps a label reading as a label. Small things grow least
       (about a fifth), the display sizes grow most (about a half). Every value
       is pinned to today's number at 380px, so the phone is untouched.

       Read a row as: min at 380px, max at 1440px, linear between. */
    --text-2xs:  clamp( 8.5px,  7.783px + 0.1887vw, 10.5px);  /* plate caption */
    --text-xs:   clamp( 9.5px,  8.783px + 0.1887vw, 11.5px);  /* eyebrow, colophon */
    --text-sm:   clamp(  10px,  9.104px + 0.2358vw, 12.5px);  /* kicker, margin note */
    --text-base: clamp(  11px, 10.104px + 0.2358vw, 13.5px);  /* note, linkish, toc num */
    --text-lg:   clamp(13.5px, 12.604px + 0.2358vw,   16px);  /* button */
    --text-xl:   clamp(  17px, 15.925px + 0.2830vw,   20px);  /* body */
    --text-2xl:  clamp(  19px, 17.745px + 0.3302vw, 22.5px);  /* prose */
    --text-title:   clamp(34px, 27.547px + 1.6981vw, 52px);
    --text-display: clamp(40px, 33.547px + 1.6981vw, 58px);

    /* THE PAGE ITSELF SCALES TOO, or the type outgrows its margins. Same 380 →
       1440 ramp; --page is the column width and is set at the tablet
       breakpoint, because below it the column is simply the screen. */
    --pad-x: clamp(24px, 15.396px + 2.2642vw, 48px);   /* D6: 24px min at 380 */

    /* FURNITURE — the shelves' own objects.
     *
     * Spines and books are drawn, not typeset, and they were fixed pixel sizes.
     * A spine that is 12% of a phone's width is 6% of an iPad's, so one volume
     * on a tablet read as a lost object on an empty shelf. They obey the same
     * fluid law as the type, and for the same reason the type gives: a phone is
     * held at 30cm and a tablet sits further out, so the same size is not the
     * same apparent size. */
    --spine-w: clamp(48px, 30.792px + 4.5283vw, 96px);  /* a volume spine on the library shelf */
    --spine-h: clamp(190px, 121.887px + 17.9245vw, 380px);  /* a volume spine, standing */
    --book-w: clamp(50px, 32.075px + 4.7170vw, 100px);  /* an open book on the books shelf */
    --book-h: clamp(188px, 120.604px + 17.7358vw, 376px);  /* an open book, standing */
    --edition-w: clamp(34px, 21.811px + 3.2075vw, 68px);  /* one of the three editions */
    --edition-h: clamp(132px, 84.679px + 12.4528vw, 264px);  /* an edition, standing */
    --pad-y: clamp(32px, 17.660px + 3.7736vw, 72px);
    --page:  100%;
    /* The widest a page column ever gets. The running head is pinned to it so
       it never moves between screens, whatever width the page beneath is. */
    --page-max: 1180px;

    --measure: 65ch;
    /* THE DOCUMENT COLUMN, IN REM AND NOT IN CH. `--measure` is 65ch, which is
       the right way to state a reading measure and the wrong way to state a
       page width: `ch` resolves against the font of whatever element it is used
       on, so the same expression gave one width on a serif page and another on
       the mono running head above it — the two were misaligned by the
       difference between the two faces. 37rem is 65ch of the reading face at
       the laptop size, fixed, and the prose inside still caps at --measure. */
    --page-doc: 37rem;
    --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s6: 24px; --s8: 32px;

    --radius-paper: 0;          /* D4: paper is sharp */
    --radius-button: 999px;     /* D4: only the thing you press is round */

    --ease: cubic-bezier(.16,1,.3,1);
    --dur: 170ms;
    --lift: 0 2px 4px rgba(34,29,21,.10);   /* D12: 2px is the ceiling */
    /* A86: the instant print. Offsets never past 2px (D12, A18); blur is softness. */
    --lift-print: 0 0 0 .5px color-mix(in srgb, var(--ink) 9%, transparent),
                  0 1px 1.5px color-mix(in srgb, var(--ink) 16%, transparent),
                  0 2px 10px color-mix(in srgb, var(--ink) 9%, transparent),
                  0 2px 22px color-mix(in srgb, var(--ink) 5%, transparent);
    --recess: inset 0 0 0 .5px color-mix(in srgb, var(--ink) 22%, transparent),
              inset 0 1.5px 2px color-mix(in srgb, var(--ink) 24%, transparent);
    /* A86: the print's matte grain — fractal noise, a few percent of ink, tiled. */
    --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .13 0 0 0 0 .11 0 0 0 0 .08 .07 0 0 0 -.025'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  }
}

@layer base {
  *,*::before,*::after { box-sizing: border-box; }
  body { margin:0; background:var(--paper); color:var(--ink);
         font-family:var(--font-read); font-size:var(--text-xl); line-height:1.62;
         -webkit-font-smoothing:antialiased; }

  /* ── type roles (D2): serif reads, mono annotates. no third family. ── */
  .serif { font-family:var(--font-read); font-weight:400; }
  .mono  { font-family:var(--font-annotate); }
  .kicker { font-family:var(--font-annotate); font-size:var(--text-sm); letter-spacing:.2em;
            text-transform:uppercase; color:var(--muted); }
  .eyebrow { font-family:var(--font-annotate); font-size:var(--text-xs); letter-spacing:.18em;
             text-transform:uppercase; color:var(--muted); }
  /* No orphaned last word in a heading or a short centred block. `balance`
     evens the ragged edge across the few lines a heading has; `pretty` only
     protects the last line, which is what a long paragraph wants. */
  h1.title, h1.display, .titlepg-epigraph { text-wrap:balance; }
  .prose, .note, .margin-note { text-wrap:pretty; }

  h1.title { font-family:var(--font-read); font-weight:400; font-size:var(--text-title);
             line-height:1.06; margin:14px 0 0; }
  h1.display { font-family:var(--font-read); font-weight:400; font-size:var(--text-display);
               line-height:1; margin:var(--s3) 0 var(--s2); }
  .note { font-family:var(--font-annotate); font-size:var(--text-base); line-height:1.6;
          color:var(--muted); }
  /* ── a document ─────────────────────────────────────────────────────────
     Privacy and Terms are the only screens that are pages of running text
     rather than a chapter. They were set in DM Mono at label size and coloured
     --muted — the annotating face, doing the reading, in the colour reserved
     for metadata. At 380px that passes. At 1440px it is 13.5px of monospace in
     a 44ch column hugging the left of an 820px page, which is what "too small
     on the computer" looks like.

     D2 already decided this: Instrument Serif reads. A document body is reading
     text, so it gets the reading face, the reading size and the ink. `.eyebrow`
     above it stays mono — that part really is annotation. */
  .doc-body { font-family:var(--font-read); font-size:var(--text-xl); line-height:1.7;
              color:var(--ink); max-width:var(--measure); margin:var(--s3) 0 0;
              text-wrap:pretty; }

  .prose { font-family:var(--font-read); font-size:var(--text-2xl); line-height:1.5;
           margin:var(--s4) 0 0; max-width:var(--measure); }
  /* A BREAK THAT READS AS ONE (A86, Jimmy's review: "so it doesn't feel so
     blocky"). Two paragraphs of a chapter set 16px apart under a 33px line
     closed up into one slab — the writer's break was there and the page hid
     it. Where a chapter is read, a new paragraph opens a clear gap. Space only. */
  :is(.reader-grid, .doc) .prose + .prose { margin-top:var(--s6); }

  /* ── the archivist speaks in rubric, and only there (D1) ── */
  .drop-cap { float:left; font-size:60px; line-height:.72; color:var(--rubric);
              padding:6px var(--s2) 0 0; }
  .margin-note { font-family:var(--font-annotate); font-size:var(--text-sm); line-height:1.55;
                 color:var(--rubric); border-left:1.5px solid var(--rubric);
                 padding-left:9px; margin-top:20px; }
  .pilcrow { color:var(--rubric); }
  .colophon { font-family:var(--font-annotate); font-size:var(--text-xs); line-height:1.7;
              color:var(--muted); margin:0; }
  .colophon b { color:var(--rubric); letter-spacing:.06em; font-weight:400; }
  a { color:var(--rubric); text-decoration:none; text-underline-offset:3px; }
  a:hover { color:var(--rubric-pressed); text-decoration:underline; }

  /* ── focus is visible and it is rubric (D12: never a browser default) ── */
  :focus { outline:none; }
  :focus-visible { outline:2px solid var(--rubric); outline-offset:2px; }
  /* A heading focused by the router, not by the person. See app.js. */
  .landed:focus, .landed:focus-visible { outline:none; }
  ::selection { background:rgba(168,55,31,.18); }   /* --rubric at 18%; see DESIGN.md open item 5 */

  /* ── motion (D7): 150–200ms ease-out, 4px rise, pulsing pilcrow, no spinner ── */
  @keyframes rise      { from{opacity:0;transform:translateY(4px)} to{opacity:1;transform:none} }
  @keyframes pulse-pil { 0%,100%{opacity:.9;transform:scale(1)} 50%{opacity:.28;transform:scale(.94)} }
  .rise { animation:rise var(--dur) ease-out both; }
  .pilcrow-waiting { animation:pulse-pil 1.5s ease-in-out infinite; }
  /* ── THE MOTION VOCABULARY ──────────────────────────────────────────────
     The same twelve moments the iOS app carries, from the motion study, and
     the same rule: motion that tells you something true you would otherwise
     have to be told in words. Named for what they DO, so a rule saying
     `.arrives` cannot drift into a different feel next month.

     Kept in step with ios/Margin/Design/Motion.swift — two clients feeling
     different is worse than neither feeling like anything.

     IN :root, WHICH THEY WERE NOT. These four sat bare in the layer, outside
     any rule, where a browser drops a custom property without a word — so
     every animation and transition naming one was invalid and did not run:
     .turns, .arrives, .leans-*, and everything else built on them. */
  :root {
    --ease-arriving:cubic-bezier(.2,0,.2,1);
    --ease-turning:cubic-bezier(.4,0,.2,1);
    --ease-settling:cubic-bezier(.35,0,.2,1);
    --beat:.62s;
  }

  @keyframes arrives   { from{opacity:0;transform:translateY(6px)} to{opacity:1;transform:none} }
  @keyframes turns     { from{transform:perspective(900px) rotateY(-88deg);opacity:0}
                         to{transform:perspective(900px) rotateY(0);opacity:1} }
  /* THE PHOTOGRAPH IS NEVER TOUCHED. The first version blurred it, and the
     adherence checker refused it — D5: "no filter on a photograph. Never a
     tint, filter, or restyle." It is right, and the rule is right: a blur is a
     filter even when it resolves to nothing.
     
     So the plate is revealed from UNDER PAPER instead. A sunk-paper leaf lifts
     off it, which is what developing actually looks like on a table and is
     more this product than a darkroom effect was. */
  @keyframes develops  { from{opacity:1} to{opacity:0} }
  @keyframes unrolls   { from{opacity:0;transform:translateY(4px)} to{opacity:1;transform:none} }
  @keyframes stamps    { from{opacity:0;transform:scale(.7)}
                         60%{opacity:1;transform:scale(1.06)} to{transform:scale(1)} }
  @keyframes withdraws { to{height:0;opacity:0} }

  /* A BOOK OPENS. The reader used to appear like a web page; the page turns in
     under the plate now. A rotation, not a paper simulation — page-curl
     skeuomorphism is dated and it fights D1. */
  .turns { animation:turns .62s var(--ease-turning) both; transform-origin:left center; }

  /* Something arriving rather than appearing. `--in` is how many BEATS after
     the thing before it, so changing the tempo is one number. */
  .arrives { animation:arrives .75s var(--ease-arriving) both;
             animation-delay:calc(var(--in,0) * var(--beat)); }

  /* A photograph RESOLVES. Fading says nothing; resolving says it is arriving,
     which is true — it is being fetched. */
  .plate-developing { position:relative; }
  .plate-developing::after {
    content:""; position:absolute; inset:0; background:var(--paper-sunk);
    animation:develops 1.5s cubic-bezier(.3,0,.3,1) both; pointer-events:none;
  }

  /* THE ONLY SPRING. A spring says "this object is springy" and paper is not —
     but a stamp presses and rebounds, and one screen has earned that. */
  .stamps { animation:stamps .42s cubic-bezier(.2,1.4,.4,1) both; }

  /* The ribbon of a volume being bound is drawn back in rather than vanishing. */
  .withdraws { animation:withdraws .45s ease-in both; }

  /* THE GAP CLOSES. Only the immediate neighbours lean — a whole shelf swaying
     is a shelf on a boat. */
  .leans-left  { transform:rotate(5deg);  transition:transform .6s var(--ease-settling); }
  .leans-right { transform:rotate(-3deg); transition:transform .6s var(--ease-settling); }

  /* A word arriving as if written — the title page's unfolding poem
     (A77: the unfolding fades whole stanzas now; the keyframe stays for any word that is written in). */
  @keyframes inks { from{opacity:0;transform:translateY(3px)} to{opacity:1;transform:none} }

  /* THE AIR AROUND THE NAME. "Margin" stands still; the air moves past it.
     Five evergreen leaves weave through its strokes, driven and timed by
     js/epigraph.js (weave), each resting out of sight between passes, and two
     muted wisps of wind are drawn and gone on long CSS cycles. Evergreen and
     muted, never rubric: air, not the archivist (D1). Sized in em, so it
     scales with the name. The one ambient loop; see DESIGN.md Motion. */
  .gust { position:relative; display:inline-block; }
  /* The word on its own layer, so a leaf can pass behind it or in front. */
  .gust-word { position:relative; z-index:1; }
  .gust-air { position:absolute; inset:-.55em -1.5em -.35em; overflow:hidden;
              pointer-events:none; }

  /* A LEAF WEAVES THROUGH THE NAME, stroke by stroke — behind the M's first
     upright, over its second, behind the third, in a pattern chosen fresh
     each pass. The path, the depth and the over/under are measured and
     driven from js/epigraph.js (weave), because only the script knows where
     the strokes are. Three layers, three motions:
       .leaf       the crossing — position, side (z-index), depth, fade
       .leaf-wave  a slow rise and fall on top of it
       .leaf-tilt  the leaf rocking on its own beat */
  .leaf { position:absolute; left:0; top:0; width:.15em; height:.15em;
          opacity:0; z-index:2; }
  .leaf-wave, .leaf-tilt { display:block; width:100%; height:100%; }
  .leaf-tilt { animation:leaf-sway var(--sway,3s) ease-in-out infinite alternate; }
  .leaf svg { display:block; width:100%; height:100%; overflow:visible; }
  .leaf path { fill:var(--evergreen); stroke:var(--evergreen); stroke-width:1;
               vector-effect:non-scaling-stroke; }
  .leaf .vein { fill:none; stroke:var(--paper-raised); }
  @keyframes leaf-sway {
    from { transform:rotate(-24deg); }
    to   { transform:rotate(28deg); }
  }

  /* A wisp: a short stroke that travels along a hairline curve and is gone,
     the way a breath of wind is seen only in what it moves. */
  .wisp { position:absolute; width:1.3em; height:.2em; overflow:visible;
          left:var(--x); top:var(--y); }
  .wisp path { fill:none; stroke:var(--muted); stroke-width:1; stroke-linecap:round;
               vector-effect:non-scaling-stroke;
               stroke-dasharray:28 100; stroke-dashoffset:28; opacity:0;
               animation:wisp var(--dur) ease-in-out infinite;
               animation-delay:var(--at); }
  @keyframes wisp {
    0%        { stroke-dashoffset:28;   opacity:0; }
    6%        { opacity:.55; }
    30%       { opacity:.55; }
    38%, 100% { stroke-dashoffset:-100; opacity:0; }
  }

  /* THE LAUNCH MOMENT: one line on paper, signed by the name and its leaves,
     over everything for a beat; then it lifts off the contents. See
     MarginEpigraph.launch. */
  .launch-veil { position:fixed; inset:0; z-index:100; background:var(--paper);
                 display:grid; place-items:center;
                 transition:opacity .5s var(--ease-settling); }
  .launch-veil.lifting { opacity:0; pointer-events:none; }
  /* The line leads, in the reading face; the name signs it beneath, smaller —
     contributing, not announcing — with its leaves. */
  .launch-inner { text-align:center; padding-inline:var(--pad-x); }
  .launch-quote { font-family:var(--font-read); font-style:italic; font-size:var(--text-2xl);
                  line-height:1.45; color:var(--ink); margin:0 auto; max-width:22ch;
                  text-wrap:balance; animation:arrives .6s var(--ease-arriving) .15s both; }
  .launch-name { font-family:var(--font-read); font-size:calc(var(--text-2xl) * 1.5);
                 line-height:1; color:var(--ink); margin-top:var(--s8);
                 animation:arrives .6s var(--ease-arriving) .5s both; }

  @media (prefers-reduced-motion:reduce){
    *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
    /* Not shortened, removed: a delayed word would sit invisible until its
       delay ran out. And air that does not move is just ornament, so it goes. */
    .titlepg-foot, .launch-quote, .launch-name, .titlepg .stanza, .titlepg-name { animation:none!important; opacity:1!important; }
    .gust-air { display:none; }
  }
}

@layer components {
  /* The "‹ The shelf" back link — verbatim in book, scroll and scrapbook.
     Pins muted through :hover on purpose. The inline style this replaces was
     (incidentally) doing that: without it a:hover wins and the link turns
     rubric-pressed. The underline on hover is unchanged. */
  .back-link, .back-link:hover { color:var(--muted); }

  /* ── plates (D5, as amended by A86). A chapter's photograph is an instant print.
        Jimmy's review, approved by the owner 28 Oct 2026: "Make sure the photos
        look like Polaroids!" — and then, of the first pass, "I don't want lazy
        polaroid. Make it look professional." A coloured border round a picture
        is the lazy version. This is built to the film's own measure:

        PROPORTIONS. An integral instant print is 88 × 107mm with a 79mm square
        window: about 6% of the print's width at the top and sides and 24% at
        the foot. `--pw` is the print's width and every margin is a share of it,
        so the proportions hold at every size. The window is SQUARE and the
        photograph covers it, centred (object-fit:cover) — the owner's call on
        28 Oct, which A86 records against D5's old "never cropped".

        PAPER. The face is --paper-print with a fine matte grain (--grain, an
        inline SVG noise at a few percent of ink; no image file, no gradient),
        so it reads as stock rather than as a fill. No outline: a print's edge
        is its shadow.

        DEPTH. The picture sits a hair below the face of the print — an inset
        shade on the window's upper edge and a hairline all round (::before,
        over the photograph, never on it: the photograph itself is untouched,
        D5/D11). Under the print, --lift-print: a contact shadow plus a soft
        ambient one, every offset ≤ 2px (D12 as decided in A18: offset is the
        limit, blur describes softness).

        THE NOTE. The chapter's line is written in the foot like a note on a
        print: the serif italic (D2 allows no third family, so no script
        face), sized to the print, ink a shade softened, set a fraction off
        level as a hand would. It may run to a second line; a longer one
        deepens the foot rather than being cut.

        LEAN. Static, alternating −0.8° / +0.9°, never animated. At 380px the
        print is the column's width and the lean moves its corners a few
        pixels into the 24px page margin, never past the viewport. ── */
  figure.plate {
    --pw:min(100%, 27rem);
    --lean:-.8deg;
    position:relative; container-type:inline-size;
    width:var(--pw); margin:var(--s8) auto 0;
    padding:calc(var(--pw) * .06) calc(var(--pw) * .06) 0;
    background:var(--grain), var(--paper-print);
    border-radius:var(--radius-paper);
    box-shadow:var(--lift-print); transform:rotate(var(--lean));
  }
  figure.plate:nth-of-type(even) { --lean:.9deg; }
  /* The window's recess: drawn over the picture, sized to it. In the print's
     own container units: 100cqi is the window's width, and the 6% margin is
     6.82cqi of it. */
  figure.plate::before {
    content:""; position:absolute; z-index:1; pointer-events:none;
    top:6.818cqi; left:6.818cqi; width:100cqi; aspect-ratio:1;
    box-shadow:var(--recess);
  }
  figure.plate img, figure.plate .well {
    display:block; width:100%; height:auto; aspect-ratio:1; margin:0;
    border-radius:0; filter:none; background:var(--paper-sunk);
  }
  figure.plate img { object-fit:cover; object-position:center; }
  figure.plate figcaption {
    display:flex; align-items:center; justify-content:center;
    min-height:27.27cqi; padding:2cqi 5cqi 3cqi;
    font-family:var(--font-read); font-style:italic; font-size:clamp(var(--text-lg), 5.4cqi, var(--text-2xl));
    line-height:1.18; letter-spacing:.005em; text-align:center; text-wrap:balance; overflow-wrap:anywhere;
    color:var(--ink-pressed); transform:rotate(-.5deg);
  }

  /* ── mats (D5). Scrapbook mode only. Token-built white border + photo corners.
        Tilt is the user's hand, not a texture. No tape: tape is on the killed list. ── */
  /* EQUAL ON EVERY SIDE. A deeper bottom margin under the photograph with the
     caption set inside it is a Polaroid frame — which, since A86 (28 Oct 2026),
     is what a chapter's plate is. The mat stays even so the Scrapbook's mounted
     page still reads as its own thing beside the book (D5). */
  figure.mat { margin:0 var(--s2); padding:10px; background:var(--paper-raised);
               border:1px solid var(--rule); box-shadow:var(--lift); position:relative; }
  figure.mat .well { height:210px; }

  /* AN EDITION IS A BROWSING SURFACE, so a plate in one is bounded. A portrait
     photograph rendered at its natural aspect filled the entire viewport and
     the page below it was a scroll into the dark — one photograph per screen is
     the reader's idiom, not the shelf's. `contain` because a plate is never
     cropped to fit (D5), and the sunk paper behind it is what shows in the
     letterbox rather than a hole. */
  figure.mat img {
    max-height:min(58vh, 520px); width:100%; object-fit:contain;
    background:var(--paper-sunk); display:block;
  }
  figure.mat figcaption { font-family:var(--font-read); font-style:italic;
    font-size:16px; text-align:center; margin-top:11px; color:var(--ink); }
  .corner { position:absolute; width:var(--s4); height:var(--s4); border:1.5px solid var(--muted);
            opacity:.55; }
  .corner.tl { top:var(--s1); left:var(--s1); border-right:0; border-bottom:0; }
  .corner.tr { top:var(--s1); right:var(--s1); border-left:0; border-bottom:0; }
  .corner.bl { bottom:var(--s1); left:var(--s1); border-right:0; border-top:0; }
  .corner.br { bottom:var(--s1); right:var(--s1); border-left:0; border-top:0; }

  /* ── paper surfaces are sharp (D4) ── */
  .card, .option, .dropzone {
    border:1px solid var(--rule); border-radius:var(--radius-paper);
    background:var(--paper-raised); padding:20px;
  }
  .option { cursor:pointer; transition:border-color var(--dur) var(--ease); }
  .option:hover { border-color:var(--ink); }
  .option[aria-checked="true"] { border:1.5px solid var(--rubric); }
  .well { background:var(--paper-sunk); border-radius:var(--radius-paper);
          display:grid; place-items:center; overflow:hidden; }
  .well span { font-family:var(--font-annotate); font-size:var(--text-sm); letter-spacing:.1em;
               color:var(--muted); text-transform:uppercase; }
  /* Something is being dragged over the drop zone. The rubric edge, because
     this is the reader acting (D1) — and nothing else moves, because nothing
     bounces (D7). */
  .dropzone.dropping .well { outline:1.5px solid var(--rubric); outline-offset:-1.5px; }

  /* Six frames, not one slab. Sunk paper against paper gutters reads as a grid
     of holes cut in a block; a hairline makes each cell a frame you could put
     something in, which is what it is. Sharp, because it is paper (D4). */
  #grid .well:not(.frame-well) { border:1px solid var(--rule); }

  /* Taking a photograph back out of a chapter. Sits on the frame rather than
     beside it, because six frames with six buttons under them is a form and
     this is a contact sheet. Sharp, because it is on paper (D4). */
  /* 11. Was a white square straddling the frame's corner, which read as a hole
     punched in the photograph. Inside the frame, on a translucent ground, and
     large enough to hit. */
  .plate-drop { position:absolute; top:4px; right:4px; z-index:2; width:auto; flex:none;
    padding:0; margin:0; line-height:1; min-width:26px; height:26px;
    border:1px solid var(--rule); border-radius:var(--radius-paper);
    background:color-mix(in srgb, var(--paper) 88%, transparent); color:var(--ink);
    font-family:var(--font-annotate); font-size:13px; cursor:pointer; }
  .plate-drop:hover { color:var(--rubric); border-color:var(--rubric); background:var(--paper); }
  .hr { height:0; border:0; border-top:1px solid var(--rule); margin:var(--s6) 0; }

  /* ── buttons: the one round thing (D4) ── */
  button { border-radius:var(--radius-button); font-family:var(--font-annotate);
    font-size:var(--text-lg); letter-spacing:.04em; padding:var(--s4); width:100%; cursor:pointer;
    transition:background var(--dur) var(--ease); }
  .btn-ink { background:var(--ink); color:var(--paper); border:none; }
  .btn-ink:hover { background:var(--ink-pressed); }
  .btn-quiet { background:transparent; color:var(--ink); border:1px solid var(--ink); }
  .btn-quiet:hover { background:var(--paper-raised); }
  /* A button that cannot be pressed must not look pressable. The consent gate
     on first run is the first place this is load-bearing: the control is there
     from the start and the sentence under it says what is still missing, so the
     state has to read as waiting rather than as broken. Existing tokens only —
     the muted rule and the raised paper, both already declared. */
  button:disabled { background:var(--paper-raised); color:var(--muted);
    border:1px solid var(--rule); cursor:not-allowed; }
  button:disabled:hover { background:var(--paper-raised); }
  /* ── loose pages: chapters waiting on a decision (Task 11) ──
     Apart from the contents, above it, and quieter than it: a sheet on the
     page with a hairline, the same rows the contents uses, and its own small
     heading. It is a list of things to do, not part of the book. */
  .loose { border:1px solid var(--rule); background:var(--paper-raised);
    border-radius:var(--radius-paper); padding:var(--s4) var(--s4) var(--s2); margin:0 0 26px; }
  .loose .loose-say { margin:4px 0 var(--s2); }
  .loose .toc-row { cursor:pointer; }
  .loose .loose-status { white-space:nowrap; }

  /* ── an action group: one decision's buttons, primary first (Task 11) ──
     Buttons are full-width, which is right on a phone and wrong on a laptop:
     a 900px pill is a banner, not a control, and two of them side by side at
     equal weight ask the reader to choose between equals. An action group
     stacks the primary above the alternative and caps at a width a hand and an
     eye can take in, centred under the text it answers. The width is the same
     measure the reading column uses for a short line; nothing new is tuned. */
  .actions { display:flex; flex-direction:column; gap:var(--s3); width:100%;
    max-width:24rem; margin:26px auto 0; }
  .actions .actions-say { text-align:center; margin:0 0 var(--s1); }
  .actions .actions-out { text-align:center; min-height:1.6em; margin:0; }
  .actions .actions-out:empty { min-height:0; }
  /* An inline link in a paragraph is not a tap target and should not pretend to
     be one; a link that is the ONLY way out of a screen is. `.back-link` and the
     shelf link are the second kind, so they get the room. */
  /* A control that happens to be a link still needs a target. `margin` cancels
     the padding so the layout is unchanged and only the hit area grows. */
  .back-link, a.tap { display:inline-block; padding:14px 6px; margin:-14px -6px; }
  .linkish { font-family:var(--font-annotate); font-size:var(--text-base); color:var(--muted);
    text-align:center; margin-top:14px; cursor:pointer; text-decoration:underline;
    text-underline-offset:3px; background:none; border:none; }

  /* A checkbox at 16px is under every target guideline, so it is drawn at
     24px — and its REACH IS ITS LABEL: every .tick sits inside a label that
     wraps the box and the sentence it answers, and that whole label (44px and
     more) is what a thumb lands on and what the tap-target test measures.
     It used to buy reach with padding:10px and margin:-10px, and Chromium drew
     the box at the padded origin: 10px above the first line of its sentence and
     10px outside the column, which is what made the consent box look bolted on.
     WCAG 2.5.8 exempts links inline in a sentence, and those stay inline: a
     link in the middle of a paragraph is not a control, and padding one breaks
     the line it sits in. The exemption is the standard, not a shortcut. */
  /* DRAWN, NOT THE PLATFORM'S. The native box arrives with the platform's
     rounded corners, and a checkbox is paper, not a button (D4 — UI audit).
     Still a real checkbox: keyboard, screen readers and the label's reach are
     unchanged; only its face is ours. */
  .tick { flex:0 0 auto; width:24px; height:24px; margin:0; cursor:pointer;
    appearance:none; -webkit-appearance:none; border:1.5px solid var(--ink); border-radius:0;
    background:var(--paper); display:inline-grid; place-content:center; }
  .tick:checked { background:var(--ink); }
  .tick:checked::after { content:''; width:11px; height:6px; margin-top:-3px;
    border-left:2px solid var(--paper); border-bottom:2px solid var(--paper); transform:rotate(-45deg); }
  .tick:focus-visible { outline:2px solid var(--rubric); outline-offset:2px; }

  /* ── inputs ── */
  .field { width:100%; padding:14px var(--s1); border:none; border-bottom:1.5px solid var(--ink);
    background:transparent; font-family:var(--font-read); font-size:22px;
    color:var(--ink); outline:none; }
  .field::placeholder { color:var(--muted); }
  /* A FIELD WITH `outline:none` AND NOTHING IN ITS PLACE.
     Every other control in the app takes the 2px rubric ring from
     :focus-visible; the inputs opted out of it and put nothing back, so
     tabbing into the email or the passphrase moved focus somewhere invisible.
     The field is a ruled line, so its focus state is that rule going rubric and
     doubling — the reader is acting on it, which is D1's other half. The padding
     gives back exactly what the thicker rule takes, so nothing moves; drawing it
     as a box-shadow instead is a D12 finding, and rightly so — nothing reading
     the file can tell a 0-blur rule from a drop shadow. */
  .field:focus-visible { border-bottom-color:var(--rubric); border-bottom-width:3px;
                         padding-bottom:12.5px; }

  /* The one control that changes what leaves the device. It gets the same shape
     as the consent line on first-run, because it is the same kind of thing: a
     box you tick, with the consequence written next to it rather than behind a
     link. */
  .look { display:flex; gap:10px; align-items:flex-start; cursor:pointer;
          border:1px solid var(--rule); padding:var(--s4); }
  .look:hover { background:var(--paper-raised); }
  .look-t { display:block; font-family:var(--font-read); font-size:var(--text-xl);
            line-height:1.3; color:var(--ink); }
  .look-n { display:block; margin-top:6px; max-width:46ch; }
  .look:has(#look:checked) { border-color:var(--rubric); }

  /* A specimen strip. Quiet enough not to compete with the page it labels,
     loud enough that nobody mistakes the page for their own. */
  .specimen { display:flex; flex-direction:column; gap:2px; margin:0 0 var(--s4);
    padding:var(--s3) var(--s4); border:1px dashed var(--rule);
    border-radius:var(--radius-paper); background:var(--paper-raised);
    font-family:var(--font-annotate); font-size:var(--text-base);
    color:var(--muted); line-height:1.6; }
  .specimen-mark { font-size:var(--text-2xs); letter-spacing:.18em;
    text-transform:uppercase; color:var(--rubric); }
  .specimen .linkish { margin:0; text-align:left; }

  /* ── contents rows ── */
  .toc-row { display:flex; align-items:baseline; gap:var(--s3); padding:13px 0;
             border-top:1px solid var(--rule); cursor:pointer; }
  /* D11 permits a contents-row tint for emotion, but DESIGN.md open item 1 says
     no tint ships until the palette is decided — and the payload no longer
     carries hex, on purpose. Neutral until then: an existing token, not an
     invented shade. `data-emotion` is on every row and ready to key off. */
  .toc-tick { width:3px; height:22px; flex:none; align-self:center;
              background:var(--rule); }
  /* NOT SHOWN UNTIL IT MEANS SOMETHING. The tick is D11's emotion mark and no
     palette is decided (DESIGN.md open item 1); a neutral grey bar on every
     row was a tint that says nothing (UI audit, 2026-09-25). */
  .toc-tick { display:none; }
  /* Muted: a chapter's number is an index, not the archivist speaking and not a
     thing to press (D1 — rubric only for those). */
  .toc-num { font-family:var(--font-annotate); font-size:var(--text-base); color:var(--muted); flex:none; }
  .toc-title { font-family:var(--font-read); font-size:18px; flex:none; max-width:58%; }
  .toc-leader { flex:1; border-bottom:1px dotted var(--rule); transform:translateY(-4px); }
  /* The voice and shape a chapter was written in. Only the specimen carries
     them today — it is the one volume whose job is to show the range — but the
     row renders whatever a chapter declares, so a real one gains it for free
     the day the API returns it. Hidden on a phone, where the leader has no
     room to spare. */
  .toc-voice { font-family:var(--font-annotate); font-size:var(--text-2xs);
               letter-spacing:.1em; text-transform:uppercase; color:var(--muted);
               flex:none; white-space:nowrap; display:none; }
  @media (min-width:900px) { .toc-voice { display:inline; } }

  /* The shelf floor runs edge to edge, which means cancelling exactly the
     gutter the page is padded by — not a hardcoded 26px guessed when the gutter
     was fixed. It has been fluid since the laptop pass, so that guess overhung
     by 2px on a phone and by 22px on a laptop. */
  .shelf-floor { margin-inline:calc(-1 * var(--pad-x)); }

  /* An edition's date and place. On a phone they sit on one line with room
     between them; the laptop rules below lift the whole block into the margin
     beside the prose. Without this they ran together as one inline string —
     "Mar 16 2026Neshanic Station, New Jersey". */
  .ed-meta { display:flex; flex-wrap:wrap; gap:var(--s1) var(--s3);
             align-items:baseline; margin-bottom:var(--s2); }

  /* THE PLACARD, and the spine that is currently in your hand. A shelf where a
     single tap opens the book is a menu; the selected state is what makes it a
     shelf. `taken` lifts the spine and rubricates its head — the same rubric
     the design already uses for "the reader is acting here". */
  [data-edition] { border-top:4px solid transparent;
                   transition:transform var(--dur) var(--ease),
                              box-shadow var(--dur) var(--ease),
                              border-color var(--dur) var(--ease); }
  /* The rubric head marks the one in your hand. It used to be painted on The
     Book permanently, which said "this is the important one" rather than "this
     is the one you have chosen" — and rubric is for where the reader acts. */
  [data-edition].taken { transform:translateY(-22px);
                         border-top-color:var(--rubric);
                         box-shadow:var(--lift); }
  .placard { border-top:1px solid var(--rule); margin-top:22px; padding-top:var(--s6);
             min-height:9rem; }
  .placard-hint { max-width:34ch; }
  .placard-k { color:var(--rubric); }
  .placard-n { font-family:var(--font-read); font-weight:400; font-size:var(--text-title);
               line-height:1; margin:var(--s2) 0 var(--s3); }
  .placard-b { font-family:var(--font-read); font-size:var(--text-xl); line-height:1.6;
               max-width:var(--measure); margin:0; text-wrap:pretty; }
  .placard-note { margin-top:var(--s3); color:var(--rubric); }
  .placard-go { width:auto; min-width:14rem; margin-top:var(--s6); }

  /* The invitation shown to somebody who HAS a volume and has not filled it. */
  .invite { border:1px solid var(--rule); background:var(--paper-raised);
            padding:var(--s8) var(--s6); text-align:center; margin:0 0 var(--s6); }
  .invite-mark { font-size:var(--text-2xl); color:var(--rubric); line-height:1; }
  .invite-t { font-family:var(--font-read); font-size:var(--text-2xl); line-height:1.35;
              margin:var(--s3) auto 0; max-width:26ch; }
  .invite-n { margin:var(--s3) auto 0; max-width:44ch; }
  .invite-go { width:auto; min-width:15rem; margin:var(--s6) auto 0; }

  .toc-month { font-family:var(--font-annotate); font-size:var(--text-sm); letter-spacing:.1em;
               color:var(--muted); flex:none; }

  /* ── turning to another chapter ──
     Apparatus, not a third ending (D10): it sits below the colophon behind a
     rule, quiet, and it is the reader's action so the direction word is rubric
     (D1). Only ever shown INSTEAD of Keep/Regenerate, never beside them, so the
     reader still carries one decision (D9). Ordering follows the contents page
     so the arrow and the list can never disagree. */
  .chapter-turn { display:flex; justify-content:space-between; align-items:flex-start;
                  gap:var(--s4); border-top:1px solid var(--rule);
                  margin-top:26px; padding-top:var(--s4); }
  .chapter-turn .turn { display:flex; flex-direction:column; gap:3px;
                        min-height:44px; max-width:47%; cursor:pointer; }
  .chapter-turn .turn.next { margin-left:auto; text-align:right; align-items:flex-end; }
  .chapter-turn .turn-dir { font-family:var(--font-annotate); font-size:var(--text-xs);
                            letter-spacing:.18em; text-transform:uppercase;
                            color:var(--rubric); }
  .chapter-turn .turn-title { font-family:var(--font-read); font-size:var(--text-xl);
                              line-height:1.2; color:var(--ink); }
  .chapter-turn .turn:hover .turn-title { color:var(--rubric-pressed); }
  /* When one end of the volume is reached, the other side keeps its column so
     the remaining chapter stays on its own edge. */
  .chapter-turn .turn-end { flex:1; }

  /* ── a rule with a word in it ──
     Separates one way of signing in from another. The word sits ON the rule, so
     the rule is two segments rather than one behind a background patch — a
     patch has to match the paper it sits on, and there are three papers. */
  .rule-or { display:flex; align-items:center; gap:var(--s3);
             margin:var(--s6) 0; color:var(--muted);
             font-family:var(--font-annotate); font-size:var(--text-caption);
             letter-spacing:.1em; text-transform:uppercase; }
  .rule-or::before, .rule-or::after {
    content:''; flex:1; height:1px; background:var(--rule); }

  /* ── Google's mark ──
     The SVG lives in the markup (see `gmark()` in open-volume.js) because it is
     a SHAPE, not a style, and because a file would be a network request the CSP
     has to allow and an asset that changes under us. This only sizes it.
     Its four colours are Google's brand and are set on the paths themselves —
     deliberately not tokens. Their guidelines fix those values and forbid
     recolouring, so a rubric-tinted G would break THEIR rule to keep ours, and
     a button that says "Continue with Google" with no mark is the thing people
     scan past. GoogleMark.swift says the same on the phone. */
  .gmark { width:17px; height:17px; flex:none; display:block; }

  /* ── a suggested name ──
     Offered, not applied: pressing one fills the field and the reader still
     presses Save. `.chosen` marks which was taken so the two are visibly the
     same decision rather than two unrelated ones. */
  .suggestion { display:block; width:100%; text-align:left; margin-bottom:8px;
                padding:12px; border:1px solid var(--rule); border-radius:0;
                background:var(--paper-raised); color:var(--ink);
                font-family:var(--font-read); font-size:var(--text-prose);
                cursor:pointer; }
  .suggestion:hover { border-color:var(--muted); }
  .suggestion.chosen { border-color:var(--rubric); }

  /* ── a spine's lettering ──
     It rides the SPINE's scale, not the page's. The spine grew with the
     viewport and the title stayed 17px, so a tall spine had its name at the top,
     its year at the bottom and a hand's width of nothing between them. The
     phone scales the same numbers by the same ratio; this is that, in CSS. */
  /* GENTLER THAN THE SPINE'S OWN RATIO, and never wrapping. At the full ratio
     a doubled spine doubled its title, "Volume I" broke into two columns and
     spilled out of the boards — vertical text wraps on the spine's HEIGHT, and
     two lines at 2× no longer fit between the bands. 0.6 of the growth keeps
     the lettering in proportion without running out of spine. */
  /* SHORTENED WHEN IT DOES NOT FIT, never run out of the boards. `nowrap`
     alone stopped a long name wrapping and let it overflow instead: a
     53-character volume name climbed the full height of the spine, out of the
     top, and straight through the screen's own heading. Vertical text overflows
     on the block axis, so the cap is a max-height and the ellipsis follows it.
     The phone had the same bug, from `fixedSize()`, and the same fix. */
  .spine-title, .spine-note, .book-title {
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-height:100%; }
  .spine-title { font-family:var(--font-read);
                 font-size:calc(17px * (0.6 + 0.4 * (var(--spine-w) / 48px))); }
  .spine-note  { font-family:var(--font-annotate);
                 font-size:var(--text-2xs); letter-spacing:.18em; }
  .book-title  { font-family:var(--font-read);
                 font-size:calc(15px * (0.6 + 0.4 * (var(--book-w) / 50px))); }

  /* A book's heading inside the contents. Sits on the list, not above it —
     the rule under each row already separates them, so this only needs air. */
  .toc-book { margin:var(--s6) 0 var(--s2); }
  .toc-book:first-child { margin-top:var(--s3); }

  /* ── settings rows ── */
  .row { display:flex; justify-content:space-between; align-items:center;
         padding:15px 0; border-top:1px solid var(--rule); gap:var(--s4); }
  .row .k { font-family:var(--font-annotate); font-size:12px; color:var(--ink); flex:none; }
  .row .v { font-family:var(--font-annotate); font-size:var(--text-base); color:var(--muted); text-align:right; }
}

@layer layout {
  /* ═════════════════════════════════════════════════════════════════════════
     LAYOUT — mobile first.

     Base rules are the phone. Two breakpoints widen them. There is no phone
     chassis in the running app; it lives under body.framed for previews only.
     ═══════════════════════════════════════════════════════════════════════ */

  body.app { display:flex; flex-direction:column; min-height:100dvh; }

  .shell { display:flex; flex-direction:column; flex:1; min-height:100dvh; }

  /* Running head — sticky, and it respects the iOS notch. */
  .head {
    position:sticky; top:0; z-index:10; flex:none;
    display:flex; justify-content:space-between; align-items:baseline;
    padding:calc(18px + env(safe-area-inset-top)) var(--s6) 11px;
    border-bottom:1px solid var(--rule); background:var(--paper);
  }
  /* app.js sets head.hidden for chrome:false screens, but display:flex outranks
     the UA's [hidden]{display:none} — so first-run, writing and the three
     onboarding screens were all showing a running head the mockups don't have.
     Restore the attribute's meaning. */
  /* [hidden] LOSES TO ANY display RULE, and this bit twice: the running head
     showed on chrome:false screens, and later "Sign out" showed while signed
     out because .row is display:flex. Fixed once, for everything. */
  [hidden] { display:none !important; }

  /* ── the labelled nav ──
     Was two unlabelled glyphs. Typography rather than chrome: the same mono
     uppercase the eyebrow uses, so it reads as a running head and not as an
     app's tab bar. The current section is inked and underlined; the others are
     muted. No pill, no icon, no bar. */
  /* 44px in BOTH directions. It was 17px wide — the height came from the row,
     not from the control, so it passed a height check and was still a target
     you had to aim at. */
  .head-back { width:auto; flex:none; min-width:44px; padding:0 12px 0 0; margin:0 0 0 -12px;
    background:none; border:none; border-radius:var(--radius-paper); color:var(--muted);
    font-family:var(--font-read); font-size:22px; line-height:1; cursor:pointer;
    text-align:left; }
  .head-back:hover { color:var(--ink); background:none; }
  /* RESERVED, NOT REMOVED. `display:none` on the chevron changed how many
     children the head had, and a `space-between` row with three children puts
     the middle one in the MIDDLE — so the wordmark jumped from the left edge to
     the centre of the screen the moment a screen happened to have a parent.
     The slot is always there and the button inside it is invisible when there
     is nowhere to go back to. */
  .head-back[hidden] { display:block !important; visibility:hidden; pointer-events:none; }

  .tabs { display:flex; gap:var(--s3); align-items:baseline; }
  /* The glyph is 10px wide on a phone and was the whole target. Padding makes
     the target 44px without moving the mark: the underline that shows the
     current section is drawn on an inner span, so it still hugs the glyph. */
  .tab { width:auto; flex:none; padding:12px 8px 10px; margin:0; background:none; border:none;
    border-radius:var(--radius-paper); cursor:pointer; color:var(--muted);
    font-family:var(--font-annotate); font-size:10px; letter-spacing:.11em;
    text-transform:uppercase; min-width:44px; min-height:44px;
    display:inline-flex; align-items:baseline; justify-content:center; }
  .tab > span { border-bottom:1px solid transparent; padding-bottom:3px; }
  .tab[aria-current="page"] > span { border-bottom-color:var(--rubric); }
  .tab:hover { color:var(--ink); background:none; }
  .tab[aria-current="page"] { color:var(--ink); }
  /* The way in is not a section of the book, so it does not sit in the same
     row of weights. Inked rather than muted, and set apart by a hairline. */
  .tab-session { color:var(--ink); margin-left:var(--s2); padding-left:var(--s3);
    border-left:1px solid var(--rule); }

  /* On a phone the four labels plus the wordmark overflow by a couple of
     pixels, and 2px of horizontal scroll is still horizontal scroll. The
     wordmark goes rather than the navigation: the title page and the browser
     tab both say Margin, and nobody is lost about which app they are in — but
     they can be lost about how to get out of a screen. */
  /* The glyphs are the whimsy and they stay. The words are the discoverability
     and they stay too, where there is room — below 560px the glyph carries it
     alone, with a title and an aria-label doing the naming. The wordmark never
     goes: it is the left margin of the page, and a running head with nothing on
     the left is not a running head. */
  /* The marks are drawn (marks/nav.svg), not typed: as characters they came
     from whatever system font had them, at four weights. In rubric, the red of
     every other place the reader acts — "visit the shelf", "Turn to the
     page"; the words beside them keep their ink. */
  .tab-g { width:15px; height:15px; vertical-align:-3px; color:var(--rubric); }
  .tab-t { margin-left:6px; }
  .tab-session .tab-g { display:none; }

  @media (max-width: 560px) {
    .tab-t { display:none; }
    .tabs { gap:var(--s2); }
    .head-inner { column-gap:var(--s2); }
    /* THE WAY IN STEPS ASIDE ON A PHONE. With it, back + wordmark + four 44px
       tabs + "Volume" is ~410px in a 342px column, and the tabs overflowed
       leftward across the wordmark — the ⁂ printed over "in" on every screen
       (overnight UI audit, 2026-09-25). § carries it here: Endpapers is the
       account, and it links to Open another volume. */
    .tab-session { display:none; }
  }

  /* ── the stages of writing a chapter ──
     A list, not a bar. Every line is a real stage the server reports, so the
     order is honest and the position is not interpolated — legacy shipped a
     hardcoded 8.5-second bar and migration 078 exists to undo it. Done is
     struck through and quiet; the one in hand is inked with a rubric mark. */
  .stages { list-style:none; margin:0; padding:0; display:flex; flex-direction:column;
    gap:9px; font-family:var(--font-annotate); font-size:var(--text-sm);
    letter-spacing:.06em; text-align:left;
    /* --rule is a hairline colour and too faint to read as text. A stage still
       ahead should be quiet, not illegible: a person waiting wants to know what
       is coming. */
    color:color-mix(in srgb, var(--muted) 55%, var(--paper)); }
  .stages li { position:relative; padding-left:18px; transition:color var(--dur) var(--ease); }
  .stages li.done { color:var(--muted); text-decoration:line-through;
    text-decoration-color:var(--rule); }
  .stages li.now { color:var(--ink); }
  /* A rule, not an ornament. The floral heart is 11px here and reads as a
     smudge; a short rubric stroke is legible at any size and is the same mark
     the margin notes already use down their left edge. */
  .stages li.now::before { content:''; position:absolute; left:0; top:0.62em;
    width:10px; height:1.5px; background:var(--rubric); }

  /* ── where you are in a sequence ──
     Three marks, the current one inked. The onboarding run and the first
     chapter are the only places a person is mid-process and cannot see it. */
  .steps { display:flex; gap:7px; align-items:center; justify-content:center;
    margin:0 0 var(--s4); }
  .steps i { display:block; width:5px; height:5px; border-radius:var(--radius-button);
    background:var(--rule); }
  /* Ink, not rubric: where you are in a sequence is neither the archivist
     speaking nor a thing to press (D1 — UI audit). */
  .steps i.on { background:var(--ink); }
  .steps i.done { background:var(--muted); }

  /* One row, down to 320px. Below 1024px .head-inner had no display at all, so
     .tools — a div — dropped onto a second line under .brand and the running
     head was two rows tall on every phone. */
  /* THREE FIXED SLOTS: back, wordmark, tabs. A grid rather than a flex row
     because the wordmark's position must not depend on what else is present —
     it is the running head of a book, and a running head does not move. */
  .head-inner { width:100%; display:grid; grid-template-columns:auto auto minmax(0,1fr);
                align-items:baseline; column-gap:var(--s3); }
  /* `auto` for the back slot rather than a fixed rem: the button is 44px of tap
     target and it keeps that width whether it is visible or not, so the column
     is stable either way and nothing has to be guessed. `minmax(0,1fr)` on the
     tabs because a 1fr track refuses to shrink below its content — which is how
     four tabs put five pixels of the running head off the side of a phone. */
  .head-inner .tabs { justify-self:end; min-width:0; }
  .head-inner-flex-unused { display:flex; flex-wrap:nowrap;
                justify-content:space-between; align-items:baseline; gap:var(--s3); }
  .head .brand { font-family:var(--font-read); font-style:italic; font-size:20px; line-height:1;
                 cursor:pointer; flex:none; }
  .head .tools { display:flex; flex:none; align-items:baseline; gap:var(--s4);
                 font-family:var(--font-annotate); font-size:var(--text-base); color:var(--muted); }
  .head .tools .glyph { font-size:var(--text-xl); line-height:1; cursor:pointer;
                        min-width:var(--s6); min-height:var(--s6); text-align:center; }
  .head .tools .glyph[aria-current] { color:var(--rubric); }

  /* A column, so a `.tall` screen can be told to fill it. `min-height:0` is what
     lets a flex child scroll instead of growing the shell. */
  .scr { flex:1; min-height:0; display:flex; flex-direction:column;
         overflow-y:auto; overflow-x:hidden; -webkit-overflow-scrolling:touch; }
  .scr::-webkit-scrollbar { width:0; height:0; }

  /* D6: 24px minimum at 380px — the floor of the --pad-x clamp. */
  .pad { width:100%; max-width:var(--page); margin-inline:auto;
         padding:var(--pad-y) var(--pad-x)
                 calc(var(--pad-y) + var(--s8) + env(safe-area-inset-bottom)); }

  /* BOOKS IN THE MIDDLE OF A SHELF THAT HAS ROOM.
     Both shelves lay their spines out from the left, which is right on a phone
     where three of them nearly fill the width. On a laptop it left two volumes
     at one end of a plank running the whole page — furniture with everything
     stacked in a corner. Above the width where they stop filling it, they
     centre. */
  #lib-shelf { justify-content:flex-start; }
  @media (min-width: 900px) {
    #lib-shelf { justify-content:center; }
  }

  /* A RUNNING HEAD IS ALREADY WHITESPACE.
     `--pad-y` scales with viewport WIDTH and tops out at 72px, which is right
     on a screen that opens straight onto its title — and doubled on one that
     opens under a 73px header with a rule along the bottom of it. On a laptop
     that put 145px of nothing above the first word, and a laptop window is
     wide without being tall, so it read as the page having slipped down.
     Capped, not reduced: `min()` leaves every width below ~1000px exactly as
     it was, so the phone is untouched and only the case that was wrong moves.
     D6 stands — whitespace is a feature, and this is the same feature counted
     once instead of twice. */
  .head:not([hidden]) ~ #screen .pad { padding-top:min(var(--pad-y), 44px); }

  /* TWO NARROWER PAGES. Both live in THIS layer, beside the `.pad` they
     override, and not with the components they are about: `@layer` beats
     specificity, so `.pad.doc` written among the components lost to a bare
     `.pad` down here and silently did nothing at all.

     `.doc` — a page of running text is exactly as wide as its measure. In the
     ordinary column the text block sat against the left edge with 220px of
     nothing to its right: not a margin, an accident of two different widths.

     `.narrow` — a D9 screen holds a heading, one control and a line of
     explanation. Given the full column the control stretched to fill it, so the
     first screen a stranger sees was a 720px band of empty paper with a
     sentence under it wrapping at a third of that width. */
  .pad.doc    { max-width:calc(var(--page-doc) + 2 * var(--pad-x)); }

  /* A DOCUMENT SECTION: its heading in the margin, its prose in the measure.
     Below the laptop breakpoint this is one column and the heading simply sits
     above, which is what a narrow page wants. */
  .doc-sec { margin-top:var(--s6); }
  .doc-sec > .eyebrow { display:block; }
  .pad.narrow { max-width:calc(30rem + 2 * var(--pad-x)); }
  /* `min-height:100%` never worked: it resolves against the parent's HEIGHT,
     and .scr is a flex item with no height of its own, so the percentage
     computed to auto and every full-height screen was top-aligned. The waiting
     screen showed it worst — a pilcrow and one line pinned near the top of an
     empty page. `flex:1` fills the actual space. */
  .pad.tall { flex:1 0 auto; display:flex; flex-direction:column; }

  /* Tap targets. */
  button, .option, .toc-row, .row, [data-go] { min-height:44px; }
  button { -webkit-tap-highlight-color:transparent; }
  a, button, [role="link"], [role="radio"], [role="button"], .option, .room-obj, label { touch-action:manipulation; -webkit-tap-highlight-color:transparent; }

  /* ── the reader grid ────────────────────────────────────────────────────
     Phone: one column. Notes stack under the paragraph they annotate, keeping
     the rubric left rule — an 84px gutter gives ten characters per line, which
     is not reading. */
  .reader-grid { display:grid; grid-template-columns:1fr; }
  .reader-grid > .margin-note { margin:14px 0 6px; }
  /* NB: the empty placeholder divs must stay in flow — they are what keeps each
     note paired with its own paragraph once the grid has two columns. */

  /* ── the title page ─────────────────────────────────────────────────────
     TWO ZONES, the way an app opens. The top zone takes all the height there
     is and centres the composition in it — name, pilcrow, epigraph, one
     object in the open. The foot holds the decision where a thumb already is,
     and ends on the imprint. On a short phone the top simply stops growing
     and the page scrolls; nothing is squeezed. */
  .titlepg { text-align:center; }
  /* The foot sits close to the bottom edge, so the shared .pad allowance
     (built for screens that end on content) would float it off the floor. */
  .pad.titlepg { padding-bottom:calc(var(--s6) + env(safe-area-inset-bottom)); }
  .titlepg-top { flex:1 0 auto; display:flex; flex-direction:column;
                 justify-content:center; padding-block:var(--s6) var(--s8); }
  .titlepg-foot { display:flex; flex-direction:column; }
  .titlepg-name { margin:0; line-height:1; }
  .titlepg-pilcrow { font-size:var(--text-xl); color:var(--rubric); margin-top:var(--s3); }
  /* One step down from prose: at the larger size eight lines of italic were
     the loudest thing on the page, louder than the name they follow. */
  .titlepg-epigraph { font-style:italic; font-size:var(--text-xl); line-height:1.5;
                      margin:var(--s8) auto 0; max-width:32ch; }
  /* The closing mark, set like the pilcrow that opens the passage and at the
     same distance from the poem as the poem is from the pilcrow (D1: the
     archivist's mark, so rubric, as in the reader). It arrives when the poem
     has settled. */
  .titlepg-fleuron { font-size:var(--text-xl); color:var(--rubric); line-height:1;
                     margin-top:var(--s8); opacity:0; transition:opacity 1.2s ease-in-out; }
  .poem-settled .titlepg-fleuron { opacity:1; }

  /* THE UNFOLDING (MarginEpigraph.unfold; A77): at the tempo of an ending.
     Each part comes up out of the paper where it will rest — slowly, the way
     the last title of a film comes up and stays. The delays are a score
     measured from the first start (--t is how far in this render is), so a
     redraw carries on rather than starting again. Only the first time. */
  @keyframes nemo { from { opacity:0; transform:translateY(3px); } to { opacity:1; transform:none; } }
  .titlepg.first .titlepg-name     { animation:nemo 2.8s var(--ease-turning) calc(400ms - var(--t, 0ms)) both; }
  .titlepg.first .titlepg-pilcrow  { animation:nemo 2s var(--ease-turning) calc(2400ms - var(--t, 0ms)) both; }
  .titlepg.first .stanza           { animation:nemo 2.8s var(--ease-turning) calc(var(--at) - var(--t, 0ms)) both; }
  .titlepg.first .stanza .touch    { display:inline-block; animation:nemo 3s var(--ease-turning) calc(11800ms - var(--t, 0ms)) both; }
  .titlepg.first .titlepg-fleuron  { opacity:1; animation:nemo 2s var(--ease-turning) calc(14200ms - var(--t, 0ms)) both; }
  .titlepg.first .titlepg-foot     { animation:nemo 2.4s var(--ease-turning) calc(4800ms - var(--t, 0ms)) both; }
  .titlepg.first .titlepg-frame::before, .titlepg.first .titlepg-frame::after { animation:nemo 3.2s var(--ease-turning) calc(1200ms - var(--t, 0ms)) both; }
  .titlepg.first .season-air       { animation:nemo 4s ease calc(1600ms - var(--t, 0ms)) both; }
  /* the last line, "and somewhere, the pages touch", is the one the poem
     turns on; it arrives alone and a breath after its stanza */
  .titlepg-epigraph .touch { color:var(--ink); }

  /* A PRINTED PAGE (A77): a double rule around the composition, as a title
     page has, with the archivist's marks at its corners. */
  .titlepg-frame { position:relative; padding:var(--s8) var(--s6); }
  .titlepg-frame::before, .titlepg-frame::after { content:''; position:absolute; pointer-events:none; }
  .titlepg-frame::before { inset:0; border:1px solid var(--rule); }
  .titlepg-frame::after { inset:5px; border:1px solid var(--rule); }
  @media (min-width:640px) { .titlepg-frame { padding:var(--s8) calc(var(--s8) + var(--s4)); } }
  .titlepg-top, .titlepg-foot { position:relative; z-index:1; }

  /* THE SEASONS (A77): the air around the name, and the few things drifting
     down the opening page. Evergreen is the leaf it always was; the others
     are an approved exception for the opener only — the pigments, here,
     outside a drawing (A77). Never under reduced motion. */
  .season-air { position:fixed; inset:0; z-index:0; overflow:hidden; pointer-events:none; }
  .launch-veil .season-air { position:absolute; }
  .season-air .sp { position:absolute; top:-6%; left:var(--x); width:var(--s); height:var(--s); opacity:0;
                    animation:sp-fall var(--dur) linear var(--d) infinite; }
  .season-air .sp svg { display:block; width:100%; height:100%; overflow:visible;
                        animation:leaf-sway calc(2.4s + var(--k) * .7s) ease-in-out infinite alternate; }
  @keyframes sp-fall { 0% { opacity:0; transform:translate(0, 0); } 8% { opacity:.6; } 50% { transform:translate(5vw, 55vh); }
                       90% { opacity:.6; } 100% { opacity:0; transform:translate(-2vw, 112vh); } }
  .season-summer .sp { top:auto; bottom:6%; animation:sp-float var(--dur) ease-in-out var(--d) infinite; }
  .season-summer .sp svg { animation:sp-glow calc(2s + var(--k) * .8s) ease-in-out infinite alternate; }
  @keyframes sp-float { 0% { opacity:0; transform:translate(0, 0); } 15% { opacity:.85; } 50% { transform:translate(4vw, -30vh); }
                        85% { opacity:.85; } 100% { opacity:0; transform:translate(-3vw, -55vh); } }
  @keyframes sp-glow { from { opacity:.35; } to { opacity:1; } }
  .season-winter .sp svg { animation:sp-spin calc(9s + var(--k) * 3s) linear infinite; }
  @keyframes sp-spin { to { transform:rotate(360deg); } }
  /* what each season's air is made of */
  :is(.season-air.season-evergreen .sp, .gust.season-evergreen .leaf, .season-glyph.season-evergreen) path { fill:var(--evergreen); stroke:var(--evergreen); }
  :is(.season-air.season-autumn .sp, .gust.season-autumn .leaf, .season-glyph.season-autumn) path { fill:var(--pigment-ochre); stroke:var(--pigment-ochre); }
  :is(.season-air.season-autumn .sp, .gust.season-autumn .leaf):nth-child(2n) path { fill:var(--pigment-rose); stroke:var(--pigment-rose); }
  :is(.season-air.season-autumn .sp, .gust.season-autumn .leaf):nth-child(3n) path { fill:color-mix(in srgb, var(--rubric) 70%, var(--pigment-ochre)); stroke:color-mix(in srgb, var(--rubric) 70%, var(--pigment-ochre)); }
  :is(.season-air.season-spring .sp, .gust.season-spring .leaf, .season-glyph.season-spring) path { fill:color-mix(in srgb, var(--pigment-rose) 45%, var(--paper-raised)); stroke:var(--pigment-rose); }
  :is(.season-air, .gust).season-winter .flake { fill:none; stroke:var(--muted); stroke-width:1.1; stroke-linecap:round; }
  :is(.season-air, .gust).season-summer .glow { fill:var(--pigment-ochre); opacity:.28; stroke:none; }
  :is(.season-air, .gust).season-summer .core { fill:var(--pigment-ochre); stroke:none; }
  :is(.season-air, .gust) .vein { fill:none; stroke:var(--paper-raised); }
  .gust.season-summer .leaf-tilt { animation:sp-glow 1.6s ease-in-out infinite alternate; }
  .gust.season-winter .leaf-tilt { animation:sp-spin 8s linear infinite; }
  @media (prefers-reduced-motion:reduce) { .season-air { display:none; } }
  /* The claim stays mono and rubricated: it is the archivist's line about the
     product, and it introduces the decision under it. D1. */
  .titlepg-claim { margin:0 auto var(--s6); max-width:46ch; color:var(--rubric);
                   letter-spacing:.02em; text-wrap:balance; }
  /* The two actions were touching — two pills with no air between them read as
     one control with a seam. */
  .titlepg .btn-quiet { margin-top:var(--s3); }
  /* The maker's mark, last and quietest: muted, smaller than the kicker it
     was, under everything. */
  .titlepg-imprint { margin-top:var(--s6); font-size:var(--text-xs); color:var(--muted); }

  /* THE STANZA BREAK IS A PAUSE, NOT A GAP. Lines inside a stanza sit at
     1.5; the break between stanzas is a little over half a line more — enough
     to read as a breath, not so much that the poem falls into three
     separate notes. In em, so it scales with the poem. */
  .stanza { display:block; }
  .stanza + .stanza { margin-top:.85em; }

  /* ── the memory line (contents) ───────────────────────────────────────
     A margin note that opens a page: the archivist speaking — mono, rubric,
     the left rule, exactly as in the reader (D1) — with the chapter's own
     recall line, or one of its Margin Facts, in the reading face beneath it,
     because that part is theirs (D2). Its closing line when it has neither;
     its title only when it has none of them.
     The whole note is the control, 44px and more. */
  .recall { display:block; margin:0 0 var(--s8); padding:var(--s1) 0 var(--s1) 11px;
            border-left:1.5px solid var(--rubric); max-width:44ch; min-height:44px;
            text-decoration:none; }
  .recall:hover { text-decoration:none; }
  .recall-when { display:block; font-family:var(--font-annotate); font-size:var(--text-sm);
                 letter-spacing:.04em; color:var(--rubric); }
  .recall-title { display:block; margin-top:var(--s1); font-family:var(--font-read);
                  font-size:var(--text-2xl); line-height:1.25; color:var(--ink); }
  .recall-title::after { content:" \203A"; color:var(--rubric); }
  .recall:hover .recall-title { color:var(--ink-pressed); }
  /* The hook: the page's own recall line, or one of its Margin Facts, the
     title held back. Set in the reading face because it is read, italic
     because it is quoted. */
  .recall-hook { display:block; margin-top:var(--s2); font-family:var(--font-read);
                 font-style:italic; font-size:var(--text-xl); line-height:1.4; color:var(--ink); }
  .recall:hover .recall-hook { color:var(--ink-pressed); }
  .recall-door { display:block; margin-top:var(--s2); font-family:var(--font-annotate);
                 font-size:var(--text-xs); letter-spacing:.08em; text-transform:uppercase;
                 color:var(--rubric); }
  .recall-door::after { content:" \203A"; }

  /* ══════════════════════════════ ≥ 640px — tablet ═══════════════════════ */
  @media (min-width:640px) {
    /* Body and prose are fluid now and need no step here. What the breakpoint
       still decides is when the page stops being the screen and becomes a
       column on it.

       IT USED TO STOP AT 820px, which on a 1440px laptop left 310px of nothing
       down each side of the contents, the shelf and the endpapers. That cap was
       borrowed from the reading measure, and it should never have applied to
       these: a table of contents, a settings list and a shelf are not prose.
       Nothing on them has a line length to protect, and a book's index page at
       a large format IS wide — that is what makes the dotted leader work.

       Prose is unaffected. `.pad.doc` still stops at its measure and `.prose`
       still stops at 65ch; what got wider is the page around them. */
    :root { --page: clamp(660px, 400px + 54vw, var(--page-max)); }
    .head { padding-inline:var(--pad-x); }
  }

  /* ══════════════════════════ ≥ 1024px — laptop ═════════════════════════════
     The reader gets a real margin. This is the one screen that improves with
     width rather than just filling it: marginalia were always meant to sit in
     a margin, not a gutter. */
  @media (min-width:1024px) {
    .head { padding-inline:0; }
    .head > * { max-width:none; }
    /* THE RUNNING HEAD DOES NOT MOVE.
       It used to take its width from whichever page was under it, so the
       wordmark walked left and right between screens and the tabs went with it.
       That was chasing alignment and it bought a moving navigation bar, which
       is a worse thing than a misalignment: chrome is furniture, and furniture
       that shifts when you change rooms is broken.
       One width, the widest page column, on every screen. */
    .head-inner { width:min(var(--page-max),100%); margin-inline:auto;
                  padding-inline:var(--pad-x); }


    /* Reader: prose column at the 65ch measure, notes in the margin beside it. */
    .pad.reader { max-width:none; padding-inline:0; }
    /* THE HEAD AND FOOT SHARE THE PROSE COLUMN'S GRID.
       They used to be `width:65ch; margin-inline:auto` — centred on the PAGE,
       while the prose is the first column of a centred two-column grid whose
       second column is 240px of margin notes. The two centres differ by half of
       (gap + notes), so the title and the plates sat 142px right of the prose
       they belong to. Sharing the grid aligns them by construction rather than
       by an offset somebody would have to maintain. */
    .reader-head, .reader-grid, .reader-foot {
      display:grid;
      grid-template-columns:minmax(0,65ch) 240px;
      column-gap:44px; justify-content:center; align-items:start;
    }
    .reader-head > *, .reader-foot > * { grid-column:1; }
    .reader-grid > .margin-note { margin:6px 0 0; }

    .prose { line-height:1.58; }
    .margin-note { font-size:var(--text-base); }

    /* THE TITLE PAGE ON A LAPTOP. It was reading as a small block of type
       stranded in a tall empty sheet: the type had been pinned at phone sizes
       while the sheet grew to 900px of height, so the only thing that scaled
       was the emptiness. The type scales now; the rest is holding the
       composition together — the name larger than the body scale would make it,
       the block capped so the lines do not sprawl, and the two actions in a row
       rather than stacked full-width, which is what left the deepest gap. */
    .titlepg { max-width:40rem; margin-inline:auto; }
    .titlepg-name { font-size:clamp(58px, 40px + 1.8vw, 76px); }
    /* Both actions to one width. Left to their labels the quiet one came out
       wider than the ink one, which reads as the secondary action being the
       bigger offer. */
    .titlepg .btn-ink, .titlepg .btn-quiet { width:auto; min-width:17rem; margin-inline:auto; }

      /* The wordmark is the running head of a book and at laptop size it was
       set at phone size — smaller than the tabs it sits beside, which inverts
       what a running head is for. */
    .brand { font-size:var(--text-2xl); }
    .head { padding-block:var(--s2); }

  /* THE DOCUMENT PAGE FILLS THE WIDTH WITHOUT STRETCHING THE LINE.
       The measure is law (D6) and a 1440px line is unreadable, so the answer to
       an empty page is never a longer line — it is a second column doing work.
       Section headings move into a real margin, right-aligned against the text
       they head, the way a scholarly page sets them. The prose column does not
       move a pixel; the page around it stops being empty. */
    .pad.doc { max-width:calc(var(--page-doc) + 15rem + 2 * var(--pad-x)); }

    /* AN EDITION IS NOT A DOCUMENT. All three were set with `.pad.doc`, which
       pushes every child right by the width of a margin column — correct for
       Privacy, where section headings live in that margin, and wrong for these,
       which have nothing to put there. The result was a 592px column of content
       shoved to the right of a 928px page: the "old small UI" on the Scroll and
       the Scrapbook, and the reason the Book looked cramped beside the contents.

       They get the whole page, and the width does structural work rather than
       stretching a line. The Scroll, since A71, is a column of short rows
       (see .scroll-row). The Scrapbook lays its plates two up, because a
       scrapbook spread is two pages. */
    .edition-scrapbook .sb-grid {
      display:grid; grid-template-columns:repeat(2, minmax(0,1fr));
      column-gap:3rem; row-gap:var(--s8); align-items:start;
    }
    .edition-scrapbook .sb-grid > .sb-page + .sb-page { margin-top:0; }

    /* A ONE-DECISION SCREEN, GIVEN A LAPTOP, IS TWO COLUMNS.
       `.narrow` capped these at 30rem, which is a phone column stranded in the
       middle of a 1440px screen — the same "too much space left to right" as
       before, just on the screens I had narrowed. The decision does not want a
       longer line; it wants the second column the width was always offering.
       The control sits beside its explanation instead of under it. */
    .pad.narrow { max-width:calc(56rem + 2 * var(--pad-x)); }
    .pad.narrow.split {
      display:grid; grid-template-columns:minmax(0,26rem) minmax(0,1fr);
      column-gap:3rem; align-items:start;
    }
    .pad.narrow.split > .col-b { grid-column:2; grid-row:1 / span 99; align-self:stretch;
                                 display:flex; flex-direction:column; justify-content:center; }
    .doc-sec {
      display:grid; grid-template-columns:13rem minmax(0, var(--page-doc));
      column-gap:2rem; align-items:start; margin-top:var(--s8);
    }
    .doc-sec > .eyebrow { grid-column:1; text-align:right; margin:0; padding-top:.55em; }
    .doc-sec > :not(.eyebrow) { grid-column:2; }
    /* The head, the title and the rows below the prose share the text column so
       nothing floats loose in the margin. PADDING, not margin: several of these
       carry an inline `margin` shorthand from their screen, and an inline style
       beats a stylesheet — the title sat 240px left of the kicker above it
       because `margin-left` was being reset by `style="margin:12px 0 24px"`.
       Nothing sets padding-left inline, so nothing can quietly undo this. */
    .pad.doc > :not(.doc-sec) { max-width:calc(var(--page-doc) + 15rem); padding-left:15rem; }

    /* Onboarding cards go side by side — still one decision. */
    .options-row { display:grid; grid-template-columns:repeat(3,1fr); gap:18px; }
    .options-row .option { display:flex; flex-direction:column; justify-content:center; }
  }

  /* ── correspondence: ephemera, marginalia, letters (A70), the Book of Days (A73–A74) and the Pigeonholes (A73) ── */

  /* A KEEPSAKE, cut from a photograph or a scan and stuck down. A paper
     backing a little wider than the picture, square-cut (D4: paper is sharp),
     with the plates' own lift. The picture inside is never filtered (D5): the
     backing and the angle do all of it. */
  .ephemera { position:absolute; width:var(--eph-w, 110px); padding:4px; margin:0;
              background:var(--paper-raised); border:1px solid var(--rule);
              box-shadow:var(--lift); transform:rotate(var(--a, 0deg));
              touch-action:none; cursor:grab; z-index:2;
              animation:eph-settle .7s var(--ease-settling) both; }
  .ephemera img { display:block; width:100%; height:auto; pointer-events:none; }
  .ephemera .eph-from { position:absolute; left:4px; top:100%; margin-top:3px;
              font-family:var(--font-annotate); font-size:var(--text-2xs);
              letter-spacing:.08em; color:var(--muted); white-space:nowrap; }
  /* ONE MOTION EACH, slow and small, once it has settled: the second ambient
     exception to D7, approved with A70. Removed under reduced motion. */
  .eph-sway    { animation:eph-settle .7s var(--ease-settling) both, eph-sway 7s ease-in-out .7s infinite; }
  .eph-lift    { animation:eph-settle .7s var(--ease-settling) both, eph-lift 6s ease-in-out .7s infinite; }
  .eph-flutter { animation:eph-settle .7s var(--ease-settling) both, eph-flutter 5s ease-in-out .7s infinite; }
  .ephemera.held { cursor:grabbing; animation:none; z-index:5; }
  @keyframes eph-settle  { from { opacity:0; transform:translateY(-10px) rotate(calc(var(--a, 0deg) - 5deg)) scale(1.06); }
                           to   { opacity:1; transform:rotate(var(--a, 0deg)); } }
  @keyframes eph-sway    { 50% { transform:rotate(calc(var(--a, 0deg) + 1.6deg)); } }
  @keyframes eph-lift    { 50% { transform:rotate(var(--a, 0deg)) translateY(-3px); } }
  @keyframes eph-flutter { 50% { transform:rotate(var(--a, 0deg)) skewX(-2deg); } }

  /* The tools above a scrapbook, and the tray a keepsake waits in before it
     is stuck down. Choosing one in the tray and then touching a page puts it
     there; the chosen one carries the rubric ring, because the reader acts. */
  .sb-tools { display:flex; flex-wrap:wrap; gap:var(--s2) var(--s3); margin:0 0 var(--s6); }
  .sb-tools button, .chips button, .tray-actions button { width:auto; padding:var(--s2) var(--s4);
              font-size:var(--text-base); }
  .tray { display:flex; flex-wrap:wrap; align-items:flex-start; gap:var(--s6) var(--s4);
          padding:var(--s3) 0 var(--s6); min-height:64px; }
  .tray .ephemera { position:relative; --eph-w:72px; }
  .tray .ephemera[aria-pressed="true"] { outline:1.5px solid var(--rubric); outline-offset:3px; }
  .tray-actions, .chips { display:flex; flex-wrap:wrap; gap:var(--s2); }
  .chips button[aria-pressed="true"] { border-color:var(--rubric); color:var(--rubric); }
  .placing [data-open] { cursor:copy; }
  .sb-page { position:relative; }
  /* One column (below the two-up spread): pages stood edge to edge, so a
     taped page's tape lay across the date line of the page above it. */
  .edition-scrapbook .sb-page + .sb-page { margin-top:var(--s8); }
  /* A pick from the reader's own photographs: a well of square thumbnails. */
  .picks { display:grid; grid-template-columns:repeat(auto-fill, minmax(72px, 1fr)); gap:var(--s2); margin:var(--s3) 0; }
  .picks button { padding:0; border:1px solid var(--rule); border-radius:var(--radius-paper);
                  background:var(--paper-sunk); aspect-ratio:1; overflow:hidden; min-height:44px; }
  .picks button[aria-pressed="true"] { outline:1.5px solid var(--rubric); outline-offset:2px; }
  .picks img { width:100%; height:100%; object-fit:cover; display:block; }

  /* MARGINALIA FROM A FRIEND. Theirs, not the archivist's: ink and the
     reading face, never rubric (D1), their name beneath in the mono. */
  .friend-note { margin:var(--s6) var(--s2) 0; padding-left:11px; border-left:1px solid var(--muted);
                 font-family:var(--font-read); font-style:italic; font-size:var(--text-xl);
                 line-height:1.4; color:var(--ink); max-width:36ch; }
  .friend-note cite { display:block; margin-top:var(--s1); font-family:var(--font-annotate);
                 font-style:normal; font-size:var(--text-2xs); letter-spacing:.12em;
                 text-transform:uppercase; color:var(--muted); }
  .friend-write { width:100%; min-height:5rem; margin-top:var(--s3); resize:vertical;
                 font-family:var(--font-read); font-style:italic; font-size:var(--text-xl); line-height:1.4; }

  /* A SEALED LETTER. Paper, a flap, a postmark and the seal. The seal is the
     button — it is what you press to open — so it is round (D4) and rubric
     (the reader acts). */
  .envelope { position:relative; width:100%; max-width:380px; aspect-ratio:7 / 5; margin:0 auto;
              background:var(--paper-raised); border:1px solid var(--rule); box-shadow:var(--lift);
              perspective:900px; }
  .envelope-flap { position:absolute; inset:0 0 auto 0; height:58%; background:var(--paper-sunk);
              clip-path:polygon(0 0, 100% 0, 50% 100%); transform-origin:top; z-index:2;
              transition:transform 1.3s var(--ease-settling); }
  .envelope.open .envelope-flap { transform:rotateX(180deg); z-index:0; }
  /* An opened flap stands above the envelope; the envelope steps down to make
     room for it, so it never lies over the words above. The flap is 58% of an
     envelope 5/7 as tall as it is wide (at most 380px). */
  .envelope { transition:margin-top .9s var(--ease-settling); }
  .envelope.open { margin-top:min(157px, calc((100vw - 48px) * .414)); }
  .envelope-to { position:absolute; left:8%; bottom:11%; font-family:var(--font-read);
              font-style:italic; font-size:var(--text-2xl); color:var(--ink); }
  .envelope-to small { display:block; margin-bottom:var(--s1); font-family:var(--font-annotate);
              font-style:normal; font-size:var(--text-2xs); letter-spacing:.14em;
              text-transform:uppercase; color:var(--muted); }
  /* The postmark is a cancellation, not a badge: a ruled box, a little off true. */
  .postmark { position:absolute; right:7%; bottom:11%; padding:var(--s1) var(--s2);
              border-top:1.5px solid var(--muted); border-bottom:1.5px solid var(--muted);
              transform:rotate(-6deg); font-family:var(--font-annotate); font-size:var(--text-2xs);
              letter-spacing:.12em; text-transform:uppercase; color:var(--muted); text-align:center; }
  .seal { position:absolute; left:50%; top:58%; z-index:3; width:58px; height:58px; min-height:58px;
          padding:0; border:none; transform:translate(-50%, -50%); background:var(--rubric);
          color:var(--paper); font-family:var(--font-read); font-style:italic; font-size:var(--text-2xl);
          box-shadow:var(--lift); transition:transform .4s var(--ease-settling), opacity .4s; }
  .seal:hover:not(:disabled) { background:var(--rubric-pressed); }
  /* Not yet is still a seal: it keeps its colour and simply does not press. */
  .seal:disabled, .seal:disabled:hover { background:var(--rubric); color:var(--paper); cursor:default; }
  .envelope.open .seal { opacity:0; transform:translate(-50%, -50%) scale(.6); pointer-events:none; }
  .countdown { margin-top:var(--s4); text-align:center; font-family:var(--font-annotate);
               font-size:var(--text-sm); letter-spacing:.14em; text-transform:uppercase; color:var(--muted); }
  .countdown b { font-weight:400; color:var(--ink); }
  .letter-body { max-width:var(--page-doc); margin:var(--s8) auto 0; white-space:pre-wrap; text-align:left;
                 font-family:var(--font-read); font-size:var(--text-2xl); line-height:1.5; color:var(--ink);
                 animation:arrives .8s var(--ease-arriving) .6s both; }
  .letter-field { min-height:9rem; resize:vertical; font-family:var(--font-read);
                  font-size:var(--text-xl); line-height:1.5; }

  /* A POSTCARD Margin made: the sender's own photograph, untouched (D5), with
     its place and one Margin Fact beneath — the archivist speaking, so the
     place is in rubric (D1). */
  .postcard { max-width:420px; margin:0 auto; padding:8px; background:var(--paper-raised);
              border:1px solid var(--rule); box-shadow:var(--lift); }
  .postcard-front { aspect-ratio:3 / 2; background:var(--paper-sunk); overflow:hidden; }
  .postcard-front img { width:100%; height:100%; object-fit:cover; display:block; }
  .postcard-place { margin:var(--s2) var(--s1) 0; font-family:var(--font-annotate);
              font-size:var(--text-2xs); letter-spacing:.14em; text-transform:uppercase; color:var(--rubric); }
  .postcard-fact { margin:var(--s1) var(--s1) var(--s1); font-family:var(--font-read); font-style:italic;
              font-size:var(--text-lg); line-height:1.4; color:var(--ink); }

  /* THE DAYBOOK: the year by its days (A70 as the Almanac; A73). A day number
     in the reading face, the page's photograph, its title beside — a page is
     found by the look of it. Square-cut and unfiltered (D4, D5). */
  .db-month { margin:var(--s8) 0 var(--s2); }
  .db-day { display:grid; grid-template-columns:2.6rem clamp(56px, 16vw, 84px) 1fr; gap:var(--s3); align-items:center;
            padding:var(--s3) 0; border-bottom:1px solid var(--rule); min-height:44px;
            color:inherit; text-decoration:none; cursor:pointer; }
  .db-day:hover .db-what { color:var(--ink-pressed); }
  .db-n { font-family:var(--font-read); font-size:var(--text-2xl); color:var(--ink); text-align:right; }
  .db-thumb { display:block; aspect-ratio:4 / 3; overflow:hidden; background:var(--paper-sunk); border:1px solid var(--rule); }
  .db-thumb img { width:100%; height:100%; object-fit:cover; display:block; }
  .db-what { display:block; font-family:var(--font-read); font-size:var(--text-xl); line-height:1.3; color:var(--ink); }
  .db-kind { display:block; margin-bottom:2px; font-family:var(--font-annotate); font-size:var(--text-2xs);
             letter-spacing:.14em; text-transform:uppercase; color:var(--muted); }
  .db-kind.ready { color:var(--rubric); }

  /* THE PIGEONHOLES (A73): a writing bureau, a cubby per correspondent. The
     frame is the bureau, each cubby an inset well with its plate beneath;
     what is in it is drawn — a postcard's photograph, or the envelope while
     it is sealed. Paper, so square-cut (D4). Two across on a phone, four
     from 720px. */
  .ph-news { margin:0 0 var(--s4); }
  .ph-bureau { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:var(--s2); margin:var(--s6) 0 0;
               padding:var(--s2); background:var(--rule); border:1px solid var(--muted); }
  @media (min-width:720px) { .ph-bureau { grid-template-columns:repeat(4, minmax(0, 1fr)); } }
  .ph-hole { display:flex; flex-direction:column; align-items:stretch; gap:var(--s2); width:100%; height:100%; margin:0;
             padding:var(--s3) var(--s2); background:var(--paper-sunk); color:var(--ink); border:1px solid var(--muted);
             border-radius:var(--radius-paper); box-shadow:inset 0 2px 0 var(--rule); letter-spacing:normal; font-size:inherit;
             transition:background var(--dur) var(--ease), border-color var(--dur) var(--ease); }
  .ph-hole:hover, .ph-hole:focus-visible, .ph-hole[aria-expanded="true"] { background:var(--paper); border-color:var(--ink); }
  .ph-slot { position:relative; display:block; aspect-ratio:2 / 1; overflow:hidden; }
  .ph-thing { position:absolute; bottom:4%; width:60%; aspect-ratio:7 / 5; display:block; }
  .ph-thing:nth-child(1) { left:4%; transform:rotate(-4deg); }
  .ph-thing:nth-child(2) { left:20%; bottom:5%; transform:rotate(3deg); }
  .ph-thing:nth-child(3) { left:36%; bottom:2%; transform:rotate(-1.5deg); }
  .ph-thing svg, .ph-thumb svg { display:block; width:100%; height:100%; }
  .ph-thing.pic { padding:3px; background:var(--paper-raised); border:1px solid var(--rule); }
  .ph-thing img, .ph-thumb img { display:block; width:100%; height:100%; object-fit:cover; }
  .pe-paper { fill:var(--paper-raised); stroke:var(--muted); stroke-width:1; }
  .pe-flap { fill:none; stroke:var(--muted); stroke-width:1; }
  .pe-seal { fill:var(--rubric); }
  .pe-date { font-family:var(--font-annotate); font-size:7px; letter-spacing:.08em; fill:var(--muted); }
  .ph-plate { align-self:center; max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
              padding:2px var(--s2); background:var(--paper-raised); border:1px solid var(--muted);
              font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.14em; text-transform:uppercase; }
  .ph-state { text-align:center; font-family:var(--font-read); font-style:italic; font-size:var(--text-base); color:var(--muted); }
  .ph-state.ready { color:var(--rubric); }
  .ph-drawer { margin:var(--s6) 0 0; }
  .ph-item { display:grid; grid-template-columns:clamp(64px, 18vw, 96px) 1fr; gap:var(--s3); align-items:center;
             padding:var(--s3) 0; border-bottom:1px solid var(--rule); min-height:44px; color:inherit; text-decoration:none; }
  .ph-item:hover .db-what { color:var(--ink-pressed); }
  .ph-thumb { display:block; aspect-ratio:7 / 5; overflow:hidden; background:var(--paper-sunk); border:1px solid var(--rule); }
  .ph-more { display:block; margin-top:2px; }
  .ph-write { display:inline-block; margin-top:var(--s4); }

  /* ── the study, the Scroll and its chart, the shelf's tours, the Gazette (A71) ── */

  /* THE STUDY. Six tiles of one size on one grid, every edge on the same lines:
     two across on a phone, three from 720px. Paper, so square-cut (D4); the
     drawing in each plays what its room is for on hover or focus, and is still
     otherwise and under reduced motion. */
  .hub { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:var(--s3); margin:var(--s6) 0 0; }
  @media (min-width:720px) { .hub { grid-template-columns:repeat(3, minmax(0, 1fr)); gap:var(--s4); } }
  .hub-tile { display:flex; flex-direction:column; align-items:stretch; gap:var(--s2); width:100%; height:100%;
              margin:0; padding:var(--s4); text-align:left; background:var(--paper-raised); color:var(--ink);
              border:1px solid var(--rule); border-radius:var(--radius-paper); letter-spacing:normal; font-size:inherit;
              transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
  .hub-tile:hover, .hub-tile:focus-visible { border-color:var(--ink); box-shadow:var(--lift); background:var(--paper-raised); }
  .hub-art { display:block; aspect-ratio:4 / 3; }
  .hub-art svg { display:block; width:100%; height:100%; overflow:visible; }
  .hub-name { font-family:var(--font-annotate); font-size:var(--text-xs); letter-spacing:.18em; text-transform:uppercase; }
  .hub-line { font-family:var(--font-read); font-style:italic; font-size:var(--text-lg); line-height:1.3; color:var(--muted); }
  #new-chapter .hub-name { color:var(--rubric); }
  /* THE DESK'S DIORAMAS (desk-art.js; A72 §6, A73, A77).

     AT REST, PAPER AND INK. Every block has three faces lit from the upper
     left — top, left, right — in three of the page's own tokens, so a drawing
     at rest is the same stuff as the page it sits on (D3).

     IN :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play), THE PIGMENTS. Hovered, focused, or tapped (.play), anything
     marked `pg` takes its pigment (`p-*`) and each face is shaded from it:
     the lit face warmed toward ochre, the shade cooled toward lapis — warm
     light, cool shadow (A77). Mixed only from the page's own tokens and the
     five pigments, which appear nowhere else.

     STATES EASE, LOOPS ARE FEW (A77). What changes when a drawing is reached
     for — a light going out, a ladder rolling, a lens opening — is a
     transition, so it eases back just as gently when the hand moves away.
     Only what keeps going while held (a flame, a wing, a fader) loops, on a
     slow and even beat. */
  .hub-tile { --wash:var(--pigment-ochre); }
  .hub-art { --tan:color-mix(in srgb, var(--pigment-ochre) 60%, var(--pigment-rose)); }
  .hub-art .p-ochre { --pg:var(--pigment-ochre); }   .hub-art .p-rose  { --pg:var(--pigment-rose); }
  .hub-art .p-lapis { --pg:var(--pigment-lapis); }   .hub-art .p-lilac { --pg:var(--pigment-lilac); }
  .hub-art .p-verdigris { --pg:var(--pigment-verdigris); } .hub-art .p-paper { --pg:var(--paper-raised); }
  .hub-art * { transition:fill .6s var(--ease), stroke .6s var(--ease), opacity .6s var(--ease); }
  /* Only what moves is turned about its own box; anything placed with a
     transform attribute keeps the user-space origin that attribute assumes. */
  .hub-art [class*="dk-"], .hub-art .arm, .hub-art .wing { transform-box:fill-box; }
  .hub-art .bd { fill:var(--paper-sunk); opacity:.55; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) { background:color-mix(in srgb, var(--wash) 7%, var(--paper-raised)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .bd { fill:color-mix(in srgb, var(--wash) 24%, var(--paper-raised)); opacity:1; }

  /* blocks, at rest */
  .hub-art polygon { stroke:var(--muted); stroke-width:.45; stroke-linejoin:round; }
  .i-t.m-stone { fill:var(--paper-raised); } .i-l.m-stone { fill:var(--paper); }     .i-r.m-stone { fill:var(--paper-sunk); }
  .i-t.m-paper { fill:var(--paper-raised); } .i-l.m-paper { fill:var(--paper-sunk); } .i-r.m-paper { fill:var(--rule); }
  .i-t.m-wood  { fill:var(--paper-sunk); }   .i-l.m-wood  { fill:var(--rule); }       .i-r.m-wood  { fill:var(--muted); }
  .i-t.m-sand  { fill:var(--rule); }         .i-l.m-sand  { fill:var(--muted); }      .i-r.m-sand  { fill:var(--ink-pressed); }
  .i-t.m-dark  { fill:var(--muted); }        .i-l.m-dark  { fill:var(--ink-pressed); } .i-r.m-dark  { fill:var(--ink); }
  .i-t.m-night { fill:var(--paper-sunk); }   .i-l.m-night { fill:var(--paper-sunk); } .i-r.m-night { fill:var(--rule); }
  /* flat shapes, at rest: light, mid, shade, dark, and a hollow */
  .hub-art .f-l { fill:var(--paper); }       .hub-art .f-m { fill:var(--paper-raised); }
  .hub-art .f-d { fill:var(--paper-sunk); }  .hub-art .f-k { fill:var(--ink-pressed); }
  .hub-art .f-hole { fill:var(--rule); }
  .hub-art .f-m.i-leaves { fill:var(--evergreen); } .hub-art .i-hi { opacity:.3; }

  /* in play: the pigments — warm light, true middle, cool shade */
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .pg:is(.i-t, .f-l) { fill:color-mix(in srgb, var(--pg) 54%, color-mix(in srgb, var(--paper-raised) 84%, var(--pigment-ochre))); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .pg:is(.i-l, .f-m) { fill:var(--pg); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .pg:is(.i-r, .f-d) { fill:color-mix(in srgb, var(--pg) 72%, color-mix(in srgb, var(--pigment-lapis) 38%, var(--ink))); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .pg.f-k { fill:color-mix(in srgb, var(--pg) 56%, color-mix(in srgb, var(--pigment-lapis) 26%, var(--ink))); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .pg.f-hole { fill:color-mix(in srgb, var(--pg) 30%, color-mix(in srgb, var(--pigment-lapis) 22%, var(--ink))); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .pg.i-t.m-night { fill:color-mix(in srgb, var(--pg) 42%, var(--ink)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .pg.i-l.m-night { fill:color-mix(in srgb, var(--pg) 50%, var(--ink)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .pg.i-r.m-night { fill:color-mix(in srgb, var(--pg) 32%, var(--ink)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .pg:is(.i-ribbon, .i-tail, .i-paw) { stroke:var(--pg); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-hi { opacity:.55; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) :is(.i-window, .i-lamp, .i-flame) { fill:color-mix(in srgb, var(--pigment-ochre) 70%, var(--paper-raised)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-gilt { stroke:var(--pigment-ochre); }

  /* the furniture of the scenes */
  .i-seam, .i-write, .i-pole, .i-ln, .i-ink, .i-ladder, .i-rail, .i-twine, .i-ribbon, .i-tail, .i-paw, .i-wick, .i-arc,
  .i-gilt, .i-finger, .i-course, .i-vous, .i-log, .i-mull, .i-bars, .i-trail, .i-stitch, .i-perf, .i-clip, .i-doodle,
  .i-stem, .i-trunk, .i-note, .i-rugline, .i-cobble, .i-sconce, .i-specs, .i-shut, .i-shut2, .i-shut3, .i-fold, .i-tongue,
  .i-tailbar, .i-wingbar, .i-foot, .i-stamp, .i-curl-ln { fill:none; stroke-linecap:round; stroke-linejoin:round; }
  .i-seam { stroke:var(--rule); stroke-width:.6; }
  .i-write { stroke:var(--ink-pressed); stroke-width:.6; }
  .i-ink { stroke:var(--muted); stroke-width:.8; }
  .i-pole { stroke:var(--ink); stroke-width:1.3; }
  .i-ln { stroke:var(--ink); stroke-width:.8; }
  .i-ladder { stroke:var(--ink-pressed); stroke-width:1.2; }
  .i-rail { stroke:var(--ink); stroke-width:1.1; }
  .i-twine { stroke:var(--muted); stroke-width:.7; }
  .i-ribbon { stroke:var(--muted); stroke-width:1.6; }
  .i-tail, .i-paw { stroke:var(--ink-pressed); stroke-width:1.7; }
  .i-wick { stroke:var(--ink); stroke-width:.8; }
  .i-arc { stroke:var(--pigment-lapis); stroke-width:1.1; opacity:0; }
  .i-gilt { stroke:var(--paper-sunk); stroke-width:.8; }
  .i-shadow { fill:var(--ink); opacity:.12; }
  .i-photo, .i-env, .i-sheet, .i-label, .i-tag, .i-paperbig, .i-clock {
    fill:var(--paper-raised); stroke:var(--muted); stroke-width:.45; }
  .i-paperbig, .i-clock { stroke:var(--ink); }
  .i-glow { fill:var(--pigment-ochre); opacity:0; }
  .i-knob, .i-door { fill:var(--ink-pressed); }
  .i-seal { fill:var(--rubric); }
  .i-flame { fill:var(--paper-sunk); stroke:var(--muted); stroke-width:.4; }
  .i-glass { fill:var(--paper-raised); opacity:.8; stroke:var(--ink); stroke-width:.7; }
  .i-window { fill:var(--paper-sunk); stroke:var(--ink); stroke-width:.6; }
  .i-mull { stroke:var(--ink); stroke-width:.35; }
  .i-lamp { fill:var(--paper-raised); stroke:var(--ink); stroke-width:.7; }
  .i-sign { font-family:var(--font-annotate); font-size:3.1px; letter-spacing:.08em; fill:var(--paper); }
  .i-rugline { stroke:var(--paper-raised); stroke-width:.5; stroke-dasharray:1.6 1.2; }

  /* people, the pigeons, the dog and the cat: outlined in ink at rest */
  .hub-art :is(.who, .bird) :is(path, rect, circle, ellipse):not(.i-flat, .i-eye, .i-cheek, .i-shadow, .i-shut, .i-shut2, .i-shut3,
    .i-specs, .i-fold, .i-tongue, .i-nose, .i-paw, .i-tail, .i-tailbar, .i-wingbar, .i-foot, .i-iris, .i-cere, .i-beak) {
    stroke:var(--ink); stroke-width:.8; vector-effect:non-scaling-stroke; }
  .hub-art .who .i-finger { stroke:var(--ink); stroke-width:1.6; }
  .hub-art .who polygon { stroke:var(--muted); stroke-width:.5; vector-effect:non-scaling-stroke; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .who polygon { stroke:transparent; }
  .hub-art .who .i-flat, .hub-art .who .i-cheek { stroke:none; }
  .i-legs { fill:var(--ink-pressed); } .i-shoe { fill:var(--ink); }
  .i-shade-d { fill:var(--ink); }
  .i-eye { fill:var(--ink); }
  .i-cheek { fill:var(--pigment-rose); opacity:0; }
  .i-shut, .i-shut2 { stroke:var(--ink); stroke-width:1.1; vector-effect:non-scaling-stroke; }
  .i-shut3 { stroke:var(--paper-raised); stroke-width:.6; }
  .i-specs { stroke:var(--ink); stroke-width:.7; vector-effect:non-scaling-stroke; }
  .i-fold { stroke:var(--ink); stroke-width:.5; opacity:.22; vector-effect:non-scaling-stroke; }
  .hub-art .arm { transform-origin:50% 0; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-cheek { opacity:.55; }
  /* skin, in five tones: tonal ink at rest, warm and true in play */
  .hub-art .i-skin { fill:var(--paper-raised); }   .hub-art .i-skin-d { fill:var(--paper-sunk); }
  .hub-art .i-skin.sk2 { fill:var(--paper-sunk); } .hub-art .i-skin-d.sk2 { fill:var(--rule); }
  .hub-art .i-skin.sk3 { fill:color-mix(in srgb, var(--rule) 65%, var(--muted)); } .hub-art .i-skin-d.sk3 { fill:color-mix(in srgb, var(--rule) 30%, var(--muted)); }
  .hub-art .i-skin.sk4 { fill:color-mix(in srgb, var(--muted) 70%, var(--rule)); } .hub-art .i-skin-d.sk4 { fill:color-mix(in srgb, var(--muted) 72%, var(--ink-pressed)); }
  .hub-art .i-skin.sk5 { fill:color-mix(in srgb, var(--muted) 62%, var(--ink-pressed)); } .hub-art .i-skin-d.sk5 { fill:color-mix(in srgb, var(--muted) 34%, var(--ink-pressed)); }
  .hub-art path.i-skin { stroke:var(--muted); stroke-width:.4; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-skin { fill:color-mix(in srgb, color-mix(in srgb, var(--pigment-rose) 55%, var(--tan)) 22%, var(--paper-raised)); }    :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-skin-d { fill:color-mix(in srgb, color-mix(in srgb, var(--pigment-rose) 55%, var(--tan)) 36%, var(--paper-sunk)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-skin.sk2 { fill:color-mix(in srgb, var(--tan) 48%, var(--paper-raised)); } :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-skin-d.sk2 { fill:color-mix(in srgb, var(--tan) 66%, var(--paper-sunk)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-skin.sk3 { fill:color-mix(in srgb, var(--tan) 80%, var(--muted)); }        :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-skin-d.sk3 { fill:color-mix(in srgb, var(--tan) 64%, var(--muted)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-skin.sk4 { fill:color-mix(in srgb, var(--tan) 64%, var(--ink)); }          :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-skin-d.sk4 { fill:color-mix(in srgb, var(--tan) 52%, var(--ink)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-skin.sk5 { fill:color-mix(in srgb, var(--tan) 46%, var(--ink)); }          :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-skin-d.sk5 { fill:color-mix(in srgb, var(--tan) 36%, var(--ink)); }
  /* hair: black, brown, auburn, grey */
  .hub-art .i-hair { fill:var(--ink-pressed); }
  .hub-art .i-hair.ht-grey { fill:var(--rule); }
  .hub-art .i-buzz { opacity:.8; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-hair { fill:color-mix(in srgb, var(--pigment-lapis) 14%, var(--ink)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-hair.ht-grey { fill:color-mix(in srgb, var(--paper-raised) 74%, var(--pigment-lilac)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-hair.ht-brown { fill:color-mix(in srgb, var(--pigment-ochre) 40%, var(--ink)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-hair.ht-auburn { fill:color-mix(in srgb, var(--pigment-rose) 62%, var(--ink)); }

  /* PEOPLE THAT MOVE (A78). While a place is played everyone in it
     breathes — a rise so small it reads as life, each on their own beat —
     and the passers-by in the square really walk: legs and arms swinging
     against each other, the body lifting on every step, crossing slowly and
     fading at the ends. Sine-shaped easing throughout, so nothing jerks. */
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .pp { animation:breathe 3.6s cubic-bezier(.45, 0, .55, 1) var(--bd, 0s) infinite; }
  @keyframes breathe { 0%, 100% { transform:none; } 50% { transform:translateY(-.6px); } }
  .i-freckle { fill:var(--muted); opacity:.45; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-freckle { fill:color-mix(in srgb, var(--pigment-ochre) 40%, var(--ink)); opacity:.45; }
  .hub-art :is(.wk-leg, .wk-arm) { transform-box:fill-box; transform-origin:50% 0; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .walker :is(.wk-leg.wk-a, .wk-arm.wk-b) { animation:swing-a var(--st, .9s) cubic-bezier(.45, 0, .55, 1) infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .walker :is(.wk-leg.wk-b, .wk-arm.wk-a) { animation:swing-b var(--st, .9s) cubic-bezier(.45, 0, .55, 1) infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .walker .wk-bob { animation:wk-bob calc(var(--st, .9s) / 2) cubic-bezier(.45, 0, .55, 1) infinite; }
  @keyframes swing-a { 0%, 100% { transform:rotate(20deg); } 50% { transform:rotate(-20deg); } }
  @keyframes swing-b { 0%, 100% { transform:rotate(-20deg); } 50% { transform:rotate(20deg); } }
  @keyframes wk-bob  { 0%, 100% { transform:none; } 50% { transform:translateY(-.5px); } }
  .i-broom { fill:none; stroke:var(--ink-pressed); stroke-width:1.6; stroke-linecap:round; }
  .i-bristle { fill:var(--paper-sunk); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-bristle { fill:var(--pigment-ochre); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-sweep { animation:sweep 1.8s cubic-bezier(.45, 0, .55, 1) infinite alternate; }
  @keyframes sweep { from { transform:rotate(-12deg); } to { transform:rotate(14deg); } }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-tell { animation:tell 3s cubic-bezier(.45, 0, .55, 1) 1s infinite; }
  @keyframes tell { 0%, 100% { transform:none; } 35% { transform:rotate(-9deg); } 70% { transform:rotate(4deg); } }
  .hub-art .dk-breathe { transform-origin:50% 100%; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-breathe { animation:sleep 3.2s cubic-bezier(.45, 0, .55, 1) infinite; }
  @keyframes sleep { 0%, 100% { transform:none; } 50% { transform:scaleY(1.05); } }
  .hub-art .dk-tail { transform-origin:100% 50%; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-tail { animation:tail 2.6s cubic-bezier(.45, 0, .55, 1) infinite alternate; }
  @keyframes tail { from { transform:rotate(-6deg); } to { transform:rotate(9deg); } }

  /* ── the darkroom: lit, then the red room ── */
  .i-liquid { fill:var(--paper-sunk); stroke:none; opacity:.9; }
  .i-peg { fill:var(--paper-raised); stroke:var(--ink); stroke-width:.4; }
  .i-tongs { fill:none; stroke:var(--ink); stroke-width:1.2; vector-effect:non-scaling-stroke; }
  .i-pool { fill:var(--paper-raised); opacity:.75; stroke:none; }
  .i-lamplight { transition:opacity 1s var(--ease); }
  .i-sconce { stroke:var(--ink); stroke-width:.6; }
  .i-shade { fill:var(--paper-raised); stroke:var(--ink); stroke-width:.4; }
  .i-bulb { fill:var(--paper-raised); stroke:var(--muted); stroke-width:.3; }
  .i-redveil { fill:color-mix(in srgb, var(--rubric) 68%, var(--ink)); stroke:none; mix-blend-mode:multiply; opacity:0;
               transition:opacity 1.4s var(--ease); }
  .i-safelight { fill:var(--ink-pressed); stroke:var(--ink); stroke-width:.4; }
  .i-safeglow { fill:color-mix(in srgb, var(--rubric) 55%, var(--pigment-rose)); mix-blend-mode:screen; opacity:0; stroke:none;
                transition:opacity 1.2s var(--ease); }
  .i-dev { fill:color-mix(in srgb, var(--rubric) 30%, var(--ink)); stroke:none; }
  .i-dev.i-dev-sun { fill:color-mix(in srgb, var(--rubric) 55%, var(--ink)); }
  .hub-art .dk-develop { opacity:0; transition:opacity 2.6s cubic-bezier(.5, 0, .3, 1); }
  .i-beam { fill:color-mix(in srgb, var(--paper-raised) 55%, var(--pigment-rose)); mix-blend-mode:screen; opacity:0; stroke:none;
            transition:opacity .9s var(--ease); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-lamplight { opacity:0; transition-delay:.3s; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-bulb { fill:var(--pigment-ochre); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-redveil { opacity:.88; transition-delay:.7s; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-safelight { fill:color-mix(in srgb, var(--pigment-rose) 55%, var(--rubric)); transition-delay:.9s; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-safeglow { opacity:.3; transition-delay:1s; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-develop { opacity:1; transition-delay:1.6s; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-beam { opacity:.55; transition-delay:2.2s; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-liquid { fill:color-mix(in srgb, var(--pigment-rose) 35%, var(--paper-sunk)); }
  .hub-art .dk-swing { transform-origin:50% 0; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-swing { animation:dk-swing 2.6s ease-in-out var(--d, 0s) infinite alternate; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-dip { animation:dk-dip 1.8s ease-in-out .6s infinite alternate; }
  @keyframes dk-swing { from { transform:rotate(-3.5deg); } to { transform:rotate(3.5deg); } }
  @keyframes dk-dip   { to { transform:rotate(16deg); } }

  /* ── the pigeonholes ── */
  .i-cubby-sh { fill:var(--ink); opacity:.14; stroke:none; }
  .i-beak { fill:var(--ink-pressed); } .i-cere { fill:var(--paper-raised); }
  .i-iris { fill:var(--paper-sunk); } .i-tailbar { stroke:var(--ink); stroke-width:1.4; }
  .i-wingbar { stroke:var(--ink-pressed); stroke-width:1.5; } .i-foot { stroke:var(--muted); stroke-width:1.1; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-iris { fill:var(--pigment-ochre); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-foot { stroke:var(--pigment-rose); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-wingbar { stroke:color-mix(in srgb, var(--pigment-lapis) 30%, var(--ink)); }
  .hub-art .wing { transform-origin:15% 90%; }
  .hub-art .dk-out { transition:transform 1s var(--ease-settling); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-out { transform:translate(-6px, 3.4px); transition-delay:.9s; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-flight { animation:dk-flight 3.4s linear .2s both; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-flight .wing { animation:dk-flap .24s ease-in-out infinite alternate; }
  .hub-art .dk-lift { transition:transform 1.2s var(--ease-settling); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-lift { animation:dk-lift 1.6s var(--ease-settling) .4s both; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-opens { animation:dk-opens 1s var(--ease-settling) 1.6s both; }
  .hub-art .dk-seal { transform-origin:center; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-seal { animation:dk-pulse 1.4s ease-in-out .6s 2; }
  .hub-art .dk-turn { transform-origin:center; transition:transform 1.4s var(--ease-settling); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-turn { transform:rotate(180deg); }
  .hub-art .dk-sand { transform-origin:50% 100%; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-sand { animation:dk-sand 3.4s linear 1.2s both; }
  .hub-art .dk-flame { transform-origin:50% 100%; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-flame { animation:dk-flicker .9s ease-in-out infinite alternate; }
  .hub-art .dk-coo { transform-origin:50% 100%; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-coo { animation:dk-coo 2.2s ease-in-out infinite; }
  /* the pigeon's flight (A80): one long, even curve in, a lift before it settles */
  @keyframes dk-flight  { 0% { transform:none; animation-timing-function:cubic-bezier(.4, 0, .6, 1); }
                          22% { transform:translate(calc(var(--dx) * .12 + 4px), -14px); animation-timing-function:cubic-bezier(.4, 0, .6, 1); }
                          48% { transform:translate(calc(var(--dx) * .42), calc(var(--dy) * .3 - 16px)); animation-timing-function:cubic-bezier(.4, 0, .6, 1); }
                          76% { transform:translate(calc(var(--dx) * .8), calc(var(--dy) * .74 - 8px)); animation-timing-function:cubic-bezier(.3, 0, .2, 1); }
                          92% { transform:translate(var(--dx), calc(var(--dy) - 2px)); }
                          100% { transform:translate(var(--dx), var(--dy)); } }
  @keyframes dk-flap    { from { transform:rotate(8deg); } to { transform:rotate(-38deg); } }
  @keyframes dk-lift    { 50% { transform:rotate(-24deg); } to { transform:rotate(-14deg); } }
  @keyframes dk-opens   { to { transform:translateY(-8px); } }
  @keyframes dk-pulse   { 50% { transform:scale(1.3); } }
  @keyframes dk-sand    { to { transform:scaleY(.1); } }
  @keyframes dk-flicker { from { transform:scale(.92, 1.04) skewX(-2deg); } to { transform:scale(1.04, .94) skewX(2deg); } }
  @keyframes dk-coo     { 0%, 100% { transform:none; } 30% { transform:translateY(-.6px) rotate(-3deg); } 60% { transform:rotate(2deg); } }

  /* ── the shelf, and the editions' own drawings ── */
  .hub-art .dk-unroll { transform-origin:50% 0; transform:scaleY(.07); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-unroll { animation:dk-unroll 1.8s var(--ease-settling) .3s both; }
  .hub-art .dk-sway { transform-origin:50% 0; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-sway { animation:dk-sway 2.2s ease-in-out var(--d, 0s) infinite alternate; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-pop { animation:dk-pop 1s var(--ease-settling) .9s both; }
  .hub-art .dk-star { transform-origin:center; opacity:0; transform:scale(.3); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-star { animation:dk-star 1.4s var(--ease-settling) 1.1s both; }
  .hub-art .dk-point { transition:transform 1.2s var(--ease-settling); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-point { animation:dk-point 1.2s var(--ease-settling) .5s both; }
  @keyframes dk-unroll  { from { transform:scaleY(.07); } to { transform:none; } }
  @keyframes dk-sway    { from { transform:rotate(-5deg); } to { transform:rotate(5deg); } }
  @keyframes dk-pop     { to { transform:translate(2px, -7px) rotate(-8deg); } }
  @keyframes dk-star    { 0% { opacity:0; transform:scale(.3); } 55% { opacity:1; transform:translateY(-12px) scale(1.2) rotate(16deg); }
                          100% { opacity:1; transform:translateY(-10px) scale(1.08) rotate(-4deg); } }
  @keyframes dk-point   { to { transform:rotate(-60deg); } }

  /* ── the Gazette's square ── */
  .i-cobble { stroke:var(--rule); stroke-width:.35; }
  .i-band, .i-col { fill:var(--paper-raised); stroke:var(--muted); stroke-width:.3; }
  .i-band + .i-sign { fill:var(--ink); }
  .i-walker { fill:none; stroke:var(--muted); stroke-width:.55; stroke-linecap:round; stroke-linejoin:round; }
  .walker { opacity:.55; }
  .i-call { font-family:var(--font-annotate); font-size:4.2px; letter-spacing:.12em; fill:var(--rubric); opacity:0; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .walker { animation:walk 7.5s linear var(--d) infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-call { animation:call 2.8s var(--ease-settling) .5s infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-wave { animation:dk-wave 1.8s ease-in-out infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-sheet { animation:dk-sheet 2.2s var(--ease-settling) var(--d) both; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-sheet2 { animation-name:dk-sheet2; }
  .hub-art .dk-tick { transform-origin:50% 100%; transition:transform 2.2s var(--ease-settling); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-tick { transform:rotate(360deg); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-band + .i-sign { fill:var(--ink); }
  @keyframes walk { 0% { opacity:0; transform:translate(calc(-9px * var(--wx)), calc(-5.2px * var(--wx))); }
                    22%, 78% { opacity:.62; }
                    100% { opacity:0; transform:translate(calc(9px * var(--wx)), calc(5.2px * var(--wx))); } }
  @keyframes call { 0% { opacity:0; transform:translateY(2px); } 18% { opacity:1; } 70% { opacity:1; transform:translateY(-4px); }
                    100% { opacity:0; transform:translateY(-6px); } }
  @keyframes dk-wave   { 0%, 100% { transform:rotate(0); } 50% { transform:rotate(14deg); } }
  @keyframes dk-sheet  { 0% { transform:none; } 60% { transform:translate(-8px, -20px) rotate(-16deg); } 100% { transform:translate(-18px, -30px) rotate(10deg); } }
  @keyframes dk-sheet2 { 0% { transform:none; } 60% { transform:translate(10px, -22px) rotate(14deg); } 100% { transform:translate(20px, -34px) rotate(-8deg); } }

  /* ── the Library at night ── */
  .i-plaque { fill:var(--paper-raised); stroke:var(--muted); stroke-width:.3; }
  .i-year { font-family:var(--font-annotate); font-size:2.5px; letter-spacing:.06em; fill:var(--ink); }
  .i-frame { fill:var(--paper-raised); stroke:var(--ink); stroke-width:.4; }
  .i-dusk, .i-dusk rect { fill:var(--ink); stroke:none; }
  .hub-art .i-dusk { opacity:.4; transition:opacity 1.4s var(--ease); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-dusk { opacity:1; }
  .i-firelight { fill:var(--pigment-ochre); stroke:none; opacity:0; mix-blend-mode:screen; }
  .i-firelight.dk-flick2 { fill:color-mix(in srgb, var(--pigment-ochre) 70%, var(--pigment-rose)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-flick { animation:flick 2.8s ease-in-out .4s infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-flick2 { animation:flick2 2.1s ease-in-out .6s infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-glow { animation:flick2 2.4s ease-in-out .5s infinite; }
  .i-winframe { fill:var(--paper-raised); stroke:var(--muted); stroke-width:.5; }
  .i-night { fill:var(--muted); stroke:var(--ink); stroke-width:.4; }
  .i-moon { fill:var(--paper-raised); stroke:none; }
  .i-star { fill:var(--paper-sunk); stroke:none; }
  .i-tree { fill:var(--ink); stroke:none; }
  .i-ember { fill:var(--pigment-ochre); stroke:none; opacity:0; }
  .i-bars { stroke:var(--paper-raised); stroke-width:.5; }
  .i-sill { fill:var(--paper-raised); stroke:var(--muted); stroke-width:.3; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-night { fill:color-mix(in srgb, var(--pigment-lapis) 46%, var(--ink)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-tree { fill:color-mix(in srgb, var(--ink) 88%, var(--pigment-lapis)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-ember { opacity:.75; transition-delay:.6s; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-winframe { fill:color-mix(in srgb, var(--pigment-ochre) 28%, var(--paper-sunk)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-star { fill:var(--paper-raised); animation:twinkle 3s ease-in-out infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-pix { animation:pix 2.4s steps(1, end) var(--d) infinite; }
  .i-course { stroke:var(--muted); stroke-width:.35; }
  .i-vous { stroke:var(--ink); stroke-width:.5; }
  .i-key { fill:var(--paper-raised); stroke:var(--muted); stroke-width:.3; }
  .i-hearth { fill:var(--ink-pressed); stroke:var(--ink); stroke-width:.4; }
  .i-fire { fill:var(--paper-sunk); opacity:.5; stroke:none; }
  .i-log { stroke:var(--muted); stroke-width:1.6; }
  .i-ember2 { fill:var(--muted); stroke:none; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-course { stroke:color-mix(in srgb, var(--pigment-ochre) 40%, var(--ink)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-hearth { fill:color-mix(in srgb, var(--pigment-rose) 18%, var(--ink)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-fire { fill:var(--pigment-ochre); opacity:1; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-fire.i-fire-o { fill:color-mix(in srgb, var(--pigment-rose) 80%, var(--rubric)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-fire.i-fire-c { fill:color-mix(in srgb, var(--paper-raised) 70%, var(--pigment-ochre)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-ember2 { fill:var(--pigment-rose); animation:twinkle 1.6s ease-in-out infinite; }
  .hub-art .dk-fire { transform-origin:50% 100%; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-fire { animation:dk-flicker .8s ease-in-out infinite alternate; }
  /* the sleepers */
  .i-nose { fill:var(--ink); } .i-tongue { stroke:var(--muted); stroke-width:.7; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-tongue { stroke:var(--pigment-rose); }
  .i-z { font-family:var(--font-annotate); font-size:3.6px; fill:var(--muted); opacity:.75; }
  .i-z.i-z2 { font-size:4.6px; opacity:.55; } .i-z.i-z3 { font-size:5.8px; opacity:.35; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-z .i-z { animation:zzz 3.6s ease-out infinite; fill:var(--pigment-lilac); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-z .i-z2 { animation-delay:1.2s; } :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-z .i-z3 { animation-delay:2.4s; }
  /* the ladder rolls along and stays while held; the finger runs over the
     years; a volume slides out. Let go, and it rolls home. */
  .hub-art .dk-ladder { transition:transform 2.4s var(--ease-settling); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-ladder { transform:translate(var(--lx), var(--ly)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-scan { animation:dk-scan 1.4s ease-in-out 1.8s infinite alternate; }
  .hub-art .dk-pull { transition:transform 1s var(--ease-settling); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-pull { transform:translate(var(--px), var(--py)); transition-delay:2.6s; }
  @keyframes dk-scan { from { transform:rotate(16deg); } to { transform:rotate(-20deg); } }
  @keyframes flick   { 0% { opacity:.16; } 18% { opacity:.27; } 34% { opacity:.19; } 52% { opacity:.31; } 70% { opacity:.2; } 86% { opacity:.28; } 100% { opacity:.16; } }
  @keyframes flick2  { 0% { opacity:.24; } 22% { opacity:.38; } 41% { opacity:.27; } 63% { opacity:.42; } 81% { opacity:.3; } 100% { opacity:.24; } }
  @keyframes twinkle { 0%, 100% { opacity:1; } 50% { opacity:.45; } }
  @keyframes pix     { 0% { transform:none; } 30% { transform:translateX(.5px); } 55% { transform:translateX(1.1px); } 80% { transform:translateX(.4px); } }
  @keyframes zzz     { 0% { opacity:0; transform:translate(0, 3px); } 25% { opacity:.9; } 100% { opacity:0; transform:translate(4px, -8px); } }

  /* ── the Studio ── */
  .i-foam { fill:var(--paper-sunk); stroke:none; }
  .i-foam.alt { fill:var(--rule); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-foam { fill:color-mix(in srgb, var(--pigment-lilac) 40%, var(--paper-sunk)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-foam.alt { fill:color-mix(in srgb, var(--pigment-lilac) 62%, var(--ink)); }
  .hub-art :is(.i-t, .i-l, .i-r).m-glass { fill:var(--paper-raised); opacity:.28; stroke:var(--ink); stroke-width:.5; }
  .i-onair { fill:var(--ink-pressed); }
  .i-onair-t { font-family:var(--font-annotate); font-size:2.4px; letter-spacing:.1em; fill:var(--paper); }
  .i-mic { fill:var(--paper-raised); stroke:var(--paper); stroke-width:.3; }
  .i-pop { fill:none; stroke:var(--ink); stroke-width:.6; }
  .i-slit { fill:none; stroke:var(--ink); stroke-width:.6; }
  .i-screen { fill:var(--ink); }
  .i-wave { fill:none; stroke:var(--paper-sunk); stroke-width:.7; stroke-dasharray:30; }
  .i-vu { fill:var(--paper-sunk); stroke:none; }
  .i-cone { fill:var(--ink-pressed); stroke:var(--muted); stroke-width:.3; }
  .i-note { stroke:var(--ink); stroke-width:.6; }
  .i-note-h { fill:var(--ink); }
  .hub-art .dk-note { opacity:0; }
  .hub-art .dk-onair { transition:fill .8s var(--ease); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-onair { fill:var(--pigment-rose); transition-delay:.3s; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-wave { stroke:var(--pigment-verdigris); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-vu { fill:var(--pigment-verdigris); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) :is(.i-note, .i-note-h) { stroke:var(--rubric); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-note-h { fill:var(--rubric); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-wavef { animation:dk-wavef 1.8s linear infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-vu { animation:vu .9s ease-in-out var(--d) infinite; }
  .hub-art .dk-vu { transform-origin:50% 100%; }
  .hub-art .dk-thump { transform-origin:center; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-thump { animation:thump .55s ease-out infinite alternate; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-note { animation:note 2.8s ease-out var(--d) infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-nod { animation:nod 1.4s ease-in-out infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-sing { animation:dk-sing 1.6s ease-in-out .4s infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-fader { animation:dk-fader 1.6s ease-in-out var(--d) infinite alternate; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-dial { animation:dk-dial 1.3s ease-in-out .3s infinite alternate; }
  @keyframes dk-wavef { from { stroke-dashoffset:30; } to { stroke-dashoffset:-30; } }
  @keyframes vu       { 0%, 100% { transform:scaleY(.35); } 30% { transform:scaleY(.9); } 50% { transform:scaleY(.55); } 75% { transform:scaleY(1); } }
  @keyframes thump    { to { transform:scale(1.14); } }
  @keyframes note     { 0% { opacity:0; transform:translate(0, 2px); } 20% { opacity:1; } 100% { opacity:0; transform:translate(-6px, -11px) rotate(-8deg); } }
  @keyframes nod      { 0%, 100% { transform:none; } 50% { transform:translateY(.9px); } }
  @keyframes dk-sing  { 0%, 100% { opacity:0; transform:none; } 50% { opacity:1; transform:translate(-2px, -2px); } }
  @keyframes dk-fader { to { transform:translate(var(--fx), var(--fy)); } }
  @keyframes dk-dial  { to { transform:rotate(-12deg); } }

  /* ── Through Their Eyes ── */
  .i-lampglow { fill:color-mix(in srgb, var(--pigment-ochre) 60%, var(--paper-raised)); opacity:0; stroke:none; }
  .i-lens-sky { fill:var(--paper-raised); stroke:none; }
  .i-lens { fill:none; stroke:var(--ink); stroke-width:1.6; }
  .i-trunk { stroke:var(--ink-pressed); stroke-width:1.3; }
  .i-trail { stroke:var(--muted); stroke-width:.6; stroke-dasharray:1.2 2; opacity:.6; }
  .hub-art .dk-lens { transform-origin:30% 100%; transform:scale(.6); opacity:.85;
                      transition:transform 1.6s var(--ease-settling), opacity .6s var(--ease); }
  .hub-art .dk-lean { transition:transform 1.2s var(--ease-settling); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-lens { transform:translateY(-4px); opacity:1; transition-delay:.4s; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-lens-sky { fill:color-mix(in srgb, var(--pigment-lapis) 32%, var(--paper-raised)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-lampglow { opacity:.2; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-trail { animation:trail 1.4s linear infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-lean { transform:translate(-1.5px, -1px); transition-delay:.8s; }
  @keyframes trail { to { stroke-dashoffset:-6.4; } }

  /* ── the Scrapbook's album ── */
  .i-cover { fill:var(--paper-sunk); stroke:var(--muted); stroke-width:.5; }
  .i-pagebg { fill:var(--paper-raised); stroke:var(--rule); stroke-width:.8; }
  .i-gutter { fill:var(--ink); opacity:.1; stroke:none; } .i-gutter.i-gutter2 { opacity:.06; }
  .i-stitch { stroke:var(--muted); stroke-width:.8; stroke-dasharray:2.4 2; }
  .i-corner { fill:var(--ink); opacity:.8; }
  .i-perf { stroke:var(--paper-raised); stroke-width:.8; stroke-dasharray:1 1.4; }
  .i-washi { fill:var(--rule); opacity:.78; }
  .i-clip { stroke:var(--muted); stroke-width:1; }
  .i-doodle { stroke:var(--rubric); stroke-width:.8; }
  .i-stem { stroke:var(--evergreen); stroke-width:1; }
  .i-sleeve { fill:var(--paper-sunk); stroke:var(--muted); stroke-width:.5; }
  .i-stamp { stroke:var(--rubric); stroke-width:.8; }
  .i-stamp-t { font-family:var(--font-annotate); font-size:3.4px; letter-spacing:.12em; fill:var(--rubric); }
  .i-curl { fill:var(--paper-sunk); stroke:var(--muted); stroke-width:.4; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .pg.i-cover { fill:color-mix(in srgb, var(--pg) 50%, var(--paper-sunk)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .pg.i-washi { fill:color-mix(in srgb, var(--pg) 62%, var(--paper-raised)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .pg.i-sleeve { fill:var(--pg); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-clip { stroke:color-mix(in srgb, var(--pigment-lapis) 45%, var(--muted)); }
  .hub-art :is(.dk-place, .dk-hand, .dk-stampin) { opacity:0; }
  .hub-art .dk-tapeon { transform-origin:0 50%; opacity:0; }
  .hub-art .dk-curl { transform-origin:0 100%; transform:scale(.25); transition:transform 1s var(--ease-settling); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-hand { animation:sb-hand 2.4s cubic-bezier(.45, 0, .25, 1) .2s both; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-place { animation:sb-place 2.4s cubic-bezier(.45, 0, .25, 1) .2s both; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-tapeon { animation:dk-tapeon .7s var(--ease-settling) 2.3s both; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-stampin { animation:sb-stamp .8s cubic-bezier(.3, 1.5, .5, 1) 2.9s both; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-curl { transform:none; transition-delay:3.3s; }
  @keyframes sb-hand  { 0% { opacity:0; transform:translate(32px, -36px); } 18% { opacity:1; } 52%, 66% { opacity:1; transform:none; }
                        100% { opacity:0; transform:translate(36px, -30px); } }
  @keyframes sb-place { 0% { opacity:0; transform:translate(32px, -36px) rotate(9deg); } 18% { opacity:1; }
                        52%, 100% { opacity:1; transform:none; } }
  @keyframes dk-tapeon { from { opacity:0; transform:scaleX(.2); } to { opacity:1; transform:none; } }
  @keyframes sb-stamp { 0% { opacity:0; transform:scale(1.6); } 60% { opacity:1; transform:scale(.94); } 100% { opacity:1; transform:none; } }

  /* ── HOME (A74): a greeting, the memory card, the study, and lately ── */
  .home-head { display:flex; flex-direction:column; gap:var(--s1); margin:0 0 var(--s6); }
  .home-head .display { margin:0; }
  .home-today { font-family:var(--font-read); font-style:italic; font-size:var(--text-xl); color:var(--muted); }

  /* THE ROOM: the six things on the desk as one study of floating islands. */
  .room { margin:var(--s6) calc(var(--s3) * -1) 0; }
  .room-art { display:block; width:100%; height:auto; aspect-ratio:auto; overflow:visible; }
  .room-art .bd { opacity:0; }
  .room-obj { cursor:pointer; outline:none; }
  .room-obj:is(:hover, :focus-visible, .play) .bd { fill:color-mix(in srgb, var(--wash) 26%, var(--paper-raised)); opacity:.75; }
  .room-hit { fill:transparent; pointer-events:all; }
  .room-name { font-family:var(--font-annotate); font-size:6.4px; letter-spacing:.2em; fill:var(--muted);
               transition:fill var(--dur) var(--ease); }
  .room-name.begin { fill:var(--rubric); }
  .room-obj:is(:hover, :focus-visible, .play) .room-name { fill:var(--ink); }
  .room-obj:focus-visible .room-name { text-decoration:underline; }
  .room-say { min-height:3.2em; margin:var(--s2) 0 0; text-align:center; font-family:var(--font-read); font-style:italic;
              font-size:var(--text-lg); color:var(--muted); }
  .room-say b { font-family:var(--font-annotate); font-style:normal; font-weight:400; font-size:var(--text-xs);
                letter-spacing:.18em; text-transform:uppercase; color:var(--ink); margin-right:var(--s2); }

  /* AN IPAD IS HELD, NOT SAT AT (A79). From 760px up to a laptop — and on
     any touch screen that wide, so the largest iPads in landscape count — the
     type steps up a size and the reading column widens with it, so a line
     keeps its measure in characters (D6) while the page stops being a thin
     strip with empty sides. The memory card and the narrow screens take the
     width they now have. */
  @media (min-width:760px) and (max-width:1199px), (min-width:760px) and (hover:none) {
    :root { --page-doc:44rem;
            --text-base:clamp(12.5px, 11.4px + .22vw, 14.5px); --text-lg:clamp(15px, 13.8px + .24vw, 17.5px);
            --text-xl:clamp(19px, 17.4px + .3vw, 22px); --text-2xl:clamp(21px, 19.2px + .34vw, 25px); }
    .pad.narrow { max-width:calc(38rem + 2 * var(--pad-x)); }
    .titlepg { max-width:46rem; }
    .room-card { max-width:34rem; }
  }

  /* THE FIRST TAP IS A LOOK (A78): on a phone the island plays and this
     card comes up from the foot of the screen — the place, a way of seeing
     it, what it is for, and the way in. */
  .room-card { position:fixed; z-index:40; left:var(--s3); right:var(--s3); bottom:calc(var(--s3) + env(safe-area-inset-bottom, 0px));
               max-width:30rem; margin-inline:auto; padding:var(--s4) var(--s4) var(--s3); background:var(--paper-raised);
               border:1px solid var(--rule); box-shadow:var(--lift); opacity:0; transform:translateY(18px);
               transition:opacity .45s var(--ease), transform .6s var(--ease-settling); }
  .room-card.up { opacity:1; transform:none; }
  .room-card-k { font-family:var(--font-annotate); font-size:var(--text-xs); letter-spacing:.18em; text-transform:uppercase; color:var(--rubric); }
  .room-card-see { margin:var(--s2) 0 var(--s2); font-family:var(--font-read); font-style:italic; font-size:var(--text-xl); line-height:1.35; color:var(--ink); }
  .room-card-what { margin:0; }
  .room-card-row { display:flex; align-items:center; justify-content:space-between; gap:var(--s3); margin-top:var(--s4); }
  .room-card-go { width:auto; padding:var(--s3) var(--s6); }
  .room-card-x { width:auto; margin:0; min-height:44px; }
  .room-card-grab { display:none; }
  /* ON A PHONE (A79) the card is a sheet: the full width, from the bottom
     edge, clear of the home indicator, with a grabber to pull it away. */
  @media (max-width:599px) {
    .room-card { left:0; right:0; bottom:0; max-width:none; touch-action:none;
                 padding:var(--s2) max(var(--s4), env(safe-area-inset-right, 0px)) calc(var(--s4) + env(safe-area-inset-bottom, 0px)) max(var(--s4), env(safe-area-inset-left, 0px));
                 border-width:1px 0 0; transform:translateY(100%); }
    .room-card.up { transform:none; }
    .room-card-grab { display:block; width:40px; height:5px; min-height:0; margin:0 auto var(--s3); padding:0;
                      border:0; border-radius:var(--radius-button); background:var(--rule); }
    .room-card-go { flex:1; }
  }
  /* the desk on a phone: larger names under islands seen one at a time */
  @media (max-width:719px) { .room-name { font-size:7.4px; } .room { margin-inline:calc(var(--s4) * -1); } }

  /* THE MEMORY CARD: the memory line beside its own photograph. The title is
     held back; the picture is not, because a picture is the better clue. */
  /* ON THE BLOTTER (A77): the desk's green blotter with its leather
     corners; on it an index card — the red margin line, one ruled line — and
     the photograph taped down beside it. Hovered, the card lifts and the
     photograph straightens. */
  .recall-pin { position:relative; display:block; }
  .recall-tape { position:absolute; z-index:1; top:-9px; left:50%; width:56px; height:17px; margin-left:-28px;
                 background:var(--rule); opacity:.88; transform:rotate(-5deg); }
  .recall-photo { display:block; aspect-ratio:4 / 3; overflow:hidden; background:var(--paper-sunk);
                  border:5px solid var(--paper-raised); box-shadow:var(--lift); transform:rotate(2deg);
                  transition:transform .8s var(--ease-settling); }
  .recall-photo img { display:block; width:100%; height:100%; object-fit:cover; }

  /* LATELY: the last three chapters as pictures, and the way to the rest. */
  /* LATELY ON ITS LEDGE (A78): the three pictures stand framed on a
     picture ledge against the wall's own panel, not floating on the page;
     each is set down a little by hand, and straightens when reached for. */
  .lately { margin:var(--s8) 0 0; padding:var(--s6) var(--s6) var(--s4); background:var(--paper-sunk); border:1px solid var(--rule); }
  .lately .lately-row { gap:var(--s4); }
  .lately .lately-pic { position:relative; z-index:1; border:6px solid var(--paper-raised); outline:1px solid var(--rule);
                        box-shadow:var(--lift); transform:rotate(-.7deg); transform-origin:50% 100%; transition:transform .8s var(--ease-settling); }
  .lately .lately-card:nth-child(2) .lately-pic { transform:rotate(.5deg); }
  .lately .lately-card:nth-child(3) .lately-pic { transform:rotate(-.3deg); }
  .lately .lately-card:is(:hover, :focus-visible) .lately-pic { transform:translateY(-3px); }
  .lately-ledge { display:block; height:9px; margin:-3px calc(var(--s4) / -2) var(--s2);
                  background:var(--ink-pressed); border-top:3px solid color-mix(in srgb, var(--paper) 24%, var(--ink-pressed)); }
  @media (max-width:560px) { .lately { padding:var(--s4) var(--s3) var(--s3); } }
  .lately-row { display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:var(--s3); margin:var(--s3) 0 0; }
  @media (max-width:560px) { .lately-row { grid-template-columns:none; grid-auto-flow:column; grid-auto-columns:72%;
                                          overflow-x:auto; scroll-snap-type:x mandatory; padding-bottom:var(--s2); }
                             .lately-card { scroll-snap-align:start; } }
  .lately-card { display:flex; flex-direction:column; gap:var(--s2); padding:0; background:none; border:0; border-radius:var(--radius-paper);
                 text-align:left; color:var(--ink); cursor:pointer; letter-spacing:normal; font-size:inherit; }
  .lately-card .well, .lately-pic { display:block; aspect-ratio:4 / 3; overflow:hidden; background:var(--paper-sunk); border:1px solid var(--rule); }
  .lately-pic img { display:block; width:100%; height:100%; object-fit:cover; transition:transform .6s var(--ease); }
  .lately-card:hover .lately-pic img, .lately-card:focus-visible .lately-pic img { transform:scale(1.04); }
  .lately-when { font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.14em; text-transform:uppercase; color:var(--muted); }
  .lately-title { font-family:var(--font-read); font-size:var(--text-xl); line-height:1.25; }
  .lately-more { display:inline-block; margin-top:var(--s6); }

  /* ── A74: the shelf as one bookcase, a book's own page, the Book of Days,
     the Scroll drawn as a scroll, the Scrapbook and Library heads ── */

  /* THE BOOKCASE. Two bays in one case: the year's books, and the three ways
     to read it. Side by side from 760px; stacked on a phone. Paper, so
     square-cut (D4); the boards are the shelf's own ink line. */
  .case { display:grid; grid-template-columns:1fr; gap:var(--s6); margin:var(--s6) 0 0; padding:var(--s4);
          background:var(--paper-sunk); border:1px solid var(--muted); box-shadow:inset 0 2px 0 var(--rule); }
  @media (min-width:760px) { .case { grid-template-columns:minmax(0, 1fr) minmax(0, 1.25fr); } }
  .case-bay { display:flex; flex-direction:column; min-width:0; }
  .case-label { margin:0 0 var(--s3); }
  .case-row { flex:1; display:flex; align-items:flex-end; justify-content:center; gap:var(--s3); min-height:190px;
              padding:var(--s3) var(--s2) 0; overflow-x:auto; }
  .case-board { height:9px; border-top:4px solid var(--ink); background:var(--paper-raised); }
  .case-manage { margin-top:var(--s4); align-self:flex-start; }
  /* A spine slides up a little under the hand, and out of the case when taken. */
  #shelf-books-row [data-shelf-book] { transition:translate .55s var(--ease-settling), opacity .55s var(--ease); }
  #shelf-books-row [data-shelf-book]:is(:hover, :focus-visible) { translate:0 -10px; }
  #shelf-books-row [data-shelf-book].pulled { translate:0 -46px; opacity:0; transition-duration:.7s; }
  .case-eds { gap:var(--s2); }
  .ed-slot { position:relative; flex:1 1 0; min-width:0; max-width:180px; }
  .ed-obj { display:flex; flex-direction:column; align-items:center; gap:2px; width:100%; margin:0; padding:var(--s2) 0 var(--s2);
            background:none; border:0; border-radius:var(--radius-paper); color:var(--ink); cursor:pointer; letter-spacing:normal; }
  .ed-obj:hover, .ed-obj:focus-visible { background:color-mix(in srgb, var(--wash) 10%, transparent); }
  .ed-art { display:block; width:100%; height:auto; aspect-ratio:120 / 150; overflow:visible; }
  .ed-name { font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.16em; text-transform:uppercase; }
  .ed-line { font-family:var(--font-read); font-style:italic; font-size:var(--text-base); color:var(--muted); }
  .ed-slot .ribbon { position:absolute; top:0; right:12%; }
  /* the editions' parts */
  .i-pages { fill:var(--paper-raised); stroke:var(--muted); stroke-width:.5; }
  .i-cal { fill:var(--paper-raised); stroke:var(--muted); stroke-width:.5; }
  .i-cal-band { fill:var(--ink-pressed); }
  .i-cal-m { font-family:var(--font-annotate); font-size:6px; letter-spacing:.12em; fill:var(--paper); }
  .i-cal-d { font-family:var(--font-read); font-size:24px; fill:var(--ink); }
  .i-knob-h { fill:var(--ink-pressed); }
  .i-ring { fill:none; stroke:var(--ink); stroke-width:.9; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-cal-band { fill:var(--pigment-rose); }
  .hub-art .ed-paper { transform-origin:50% 0; transform:scaleY(.3); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .ed-paper { animation:dk-unroll .9s var(--ease-settling) both; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-roll-down { animation:dk-roll-down .9s var(--ease-settling) both; }
  .hub-art .dk-tear { transform-origin:0 0; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-tear { animation:dk-tear .9s var(--ease-settling) .15s both; }
  .hub-art .dk-peek { transform-origin:50% 100%; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-peek { animation:dk-peek .8s var(--ease-settling) var(--d, 0s) both; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-stick { animation:dk-stick 1.1s var(--ease-settling) .2s both; }
  @keyframes dk-roll-down { to { transform:translateY(82px); } }
  @keyframes dk-tear    { 40% { transform:translate(4px, -6px) rotate(8deg); opacity:1; } 100% { transform:translate(30px, 60px) rotate(40deg); opacity:0; } }
  @keyframes dk-peek    { 50% { transform:translateY(-9px) rotate(-4deg); } 100% { transform:translateY(-6px) rotate(2deg); } }
  @keyframes dk-stick   { 0% { transform:none; } 55% { transform:rotate(24deg); } 70% { transform:rotate(22deg); } 100% { transform:rotate(4deg); } }

  /* A DRAWN HEAD for an edition's own page: the drawing beside the title,
     playing once on arrival and again when reached for. */
  .ed-head { display:flex; align-items:flex-end; justify-content:space-between; gap:var(--s4); }
  .ed-head-art { flex:none; width:clamp(150px, 30vw, 260px); padding:0; border:0; background:none; box-shadow:none; }
  .ed-head-art:is(:hover, :focus-visible, .play) { background:none; box-shadow:none; }
  .ed-head-art .hub-art { aspect-ratio:4 / 3; width:100%; height:auto; }
  @media (max-width:520px) { .ed-head { flex-direction:column; align-items:flex-start; } .ed-head-art { width:70%; align-self:center; } }

  /* A BOOK, OPENED: the title page and its contents as one spread, opening
     from the spine as it arrives. */
  .spread { display:grid; grid-template-columns:1fr; margin:var(--s6) 0 0; background:var(--paper-raised);
            border:1px solid var(--rule); box-shadow:var(--lift); }
  @media (min-width:760px) { .spread { grid-template-columns:minmax(0, .85fr) minmax(0, 1.15fr); } }
  .spread-left, .spread-right { padding:var(--s6) var(--s6); }
  .spread-left { display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center;
                 gap:var(--s2); border-bottom:1px solid var(--rule); transform-origin:100% 50%; }
  @media (min-width:760px) { .spread-left { border-bottom:0; border-right:1px solid var(--rule); animation:spread-open 1.2s var(--ease-settling) both; } }
  .spread-numeral { font-family:var(--font-annotate); font-size:var(--text-xs); letter-spacing:.3em; color:var(--rubric); }
  .spread-name { margin:0; }
  .spread-dates { margin:0; font-family:var(--font-read); font-style:italic; font-size:var(--text-lg); color:var(--muted); }
  .spread-orn { font-size:17px; color:var(--muted); letter-spacing:.3em; }
  .spread-state { margin:0; }
  @keyframes spread-open { from { transform:perspective(900px) rotateY(35deg); opacity:.4; } to { transform:none; opacity:1; } }
  .bk-row { display:grid; grid-template-columns:2rem clamp(56px, 14vw, 80px) 1fr; gap:var(--s3); align-items:center;
            padding:var(--s3) 0; border-bottom:1px solid var(--rule); min-height:44px; color:inherit; text-decoration:none; }
  .bk-num { font-family:var(--font-annotate); font-size:var(--text-xs); color:var(--muted); }
  .bk-pic { display:block; aspect-ratio:4 / 3; overflow:hidden; background:var(--paper-sunk); border:1px solid var(--rule); }
  .bk-pic img { display:block; width:100%; height:100%; object-fit:cover; }
  .bk-title { display:block; font-family:var(--font-read); font-size:var(--text-xl); line-height:1.25; }
  .bk-when { display:block; font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.12em; text-transform:uppercase; color:var(--muted); }
  .bk-row:hover .bk-title { color:var(--ink-pressed); }

  /* THE BOOK OF DAYS: the year as calendar months; a kept day is its own
     photograph in its square (no tint, no filter, no text over it: D5). */
  .db-soon { display:flex; flex-direction:column; }
  .cal-year { display:grid; grid-template-columns:repeat(auto-fill, minmax(min(100%, 290px), 1fr)); gap:var(--s6) var(--s4); }
  .cal-month { padding:var(--s3); background:var(--paper-raised); border:1px solid var(--rule); }
  .cal-month:not(.has) { background:transparent; }
  .cal-head { display:flex; justify-content:space-between; align-items:baseline; margin:0 0 var(--s2);
              font-family:var(--font-read); font-size:var(--text-xl); }
  .cal-y { font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.14em; color:var(--muted); }
  .cal-dow, .cal-grid { display:grid; grid-template-columns:repeat(7, minmax(0, 1fr)); gap:3px; }
  .cal-dow span { font-family:var(--font-annotate); font-size:var(--text-2xs); color:var(--muted); text-align:center; }
  .cal-day, .cal-blank { aspect-ratio:1; display:flex; align-items:center; justify-content:center;
                         font-family:var(--font-annotate); font-size:var(--text-2xs); color:var(--muted); }
  .cal-day.today { outline:1.5px solid var(--rubric); outline-offset:-1px; color:var(--rubric); }
  .cal-day.kept { overflow:hidden; background:var(--paper-sunk); outline:1px solid var(--ink); outline-offset:0; color:var(--ink);
                  animation:arrives .9s var(--ease-arriving) calc(var(--i) * 90ms) both; transition:transform var(--dur) var(--ease); }
  .cal-day.kept img { width:100%; height:100%; object-fit:cover; display:block; }
  .cal-day.kept:is(:hover, :focus-visible) { transform:scale(1.35); position:relative; z-index:2; outline-width:2px; }

  /* THE SCROLL, DRAWN AS ONE: a long sheet between two wooden rollers, the
     chapters either side of a thread with their days knotted on it. */
  .scroll-sheet { position:relative; margin:var(--s4) 0 0; }
  .roller { position:relative; height:16px; margin:0 -14px; background:var(--ink-pressed); z-index:2; }
  .roller::before, .roller::after { content:''; position:absolute; top:-4px; width:12px; height:24px; background:var(--ink); }
  .roller::before { left:-10px; } .roller::after { right:-10px; }
  .roller-top { position:sticky; top:0; }
  .scroll-paper { position:relative; padding:var(--s6) var(--s4); background:var(--paper-raised);
                  border-left:1px solid var(--rule); border-right:1px solid var(--rule); }
  .scroll-thread { position:absolute; top:0; bottom:0; left:calc(var(--s4) + 7px); width:0; border-left:1px dashed var(--muted); }
  .scroll-sheet .scroll-row { position:relative; grid-template-columns:minmax(88px, 34%) 1fr; padding:var(--s4) 0 var(--s4) var(--s6);
                               border-top:0; }
  .scroll-knot { position:absolute; left:2px; top:var(--s4); width:11px; height:11px; background:var(--paper-raised);
                 border:1.5px solid var(--ink); transform:rotate(45deg); }
  .scroll-sheet .scroll-row .scroll-frame { margin-top:var(--s4); }
  .scroll-sheet .scroll-row .scroll-words { margin-top:var(--s4); }
  @media (min-width:760px) {
    .scroll-thread { left:50%; }
    .scroll-sheet .scroll-row { grid-template-columns:minmax(0, 1fr) minmax(0, 1fr); gap:var(--s6); padding:var(--s6) 0; width:50%; }
    .scroll-sheet .scroll-row.side-l { margin-right:auto; padding-right:var(--s6); }
    .scroll-sheet .scroll-row.side-r { margin-left:auto; padding-left:var(--s6); }
    /* Each chapter starts halfway down the one before, across the thread. */
    .scroll-sheet .scroll-row + .scroll-row { margin-top:-88px; }
    .scroll-knot { left:auto; right:-6px; }
    .side-r .scroll-knot { left:-6px; right:auto; }
  }
  /* Each unrolls once, the first time it is reached; shown plainly where
     nothing reports it reached, so a scroll is never blank. */
  .scroll-sheet.rolls .scroll-row.unrolled { animation:unroll .8s var(--ease-settling) both; }
  @keyframes unroll { from { clip-path:inset(0 0 100% 0); } to { clip-path:inset(0 0 0 0); } }

  /* THE SCRAPBOOK, handled: a page lifts and straightens under the hand,
     and some are held down with tape rather than corners. */
  .edition-scrapbook figure.mat { transition:translate .35s var(--ease), rotate .35s var(--ease), box-shadow .35s var(--ease); }
  .edition-scrapbook .sb-page:is(:hover, :focus-within) figure.mat { translate:0 -6px; rotate:1.4deg; }
  .edition-scrapbook .sb-page:is(:hover, :focus-within) .corner { opacity:1; border-color:var(--ink); }
  .tape { position:absolute; top:-10px; left:50%; width:74px; height:20px; margin-left:-37px; z-index:2;
          background:var(--rule); opacity:.85; transform:rotate(-3deg); transition:background .35s var(--ease); }
  .sb-page:is(:hover, :focus-within) .tape { background:color-mix(in srgb, var(--pigment-ochre) 55%, var(--paper-raised)); }

  /* THE ROOM'S GROUND: each island on its own patch, stones between. */
  .room-ground { fill:var(--paper-sunk); stroke:var(--rule); stroke-width:.6; transition:fill .45s var(--ease); }
  .room-stone { fill:var(--rule); }
  /* THE AIR: the title page's leaves, crossing the study slowly — the
     fourth ambient motion (A75): long, sparse, never two at once in one
     place, none under reduced motion. */
  .room-leaf { opacity:0; animation:room-leaf 26s linear calc(var(--i) * 5.2s) infinite; }
  .room-leaf path { fill:var(--evergreen); }
  .room-leaf .vein { fill:none; stroke:var(--paper-raised); stroke-width:.8; }
  @keyframes room-leaf {
    0%   { opacity:0; transform:translate(0, var(--y)) rotate(0); }
    6%   { opacity:.7; }
    50%  { transform:translate(290px, calc(var(--y) + 24px)) rotate(200deg); }
    94%  { opacity:.7; }
    100% { opacity:0; transform:translate(580px, calc(var(--y) - 10px)) rotate(400deg); } }

  /* SECTION LABELS INSIDE A PLACE are written in rubric (A75): the place
     speaking about itself, as the margin does. */
  .case-label, .ph-plate-label, .edition-scrapbook .sb-page > .eyebrow { color:var(--rubric); }

  /* THE LIBRARY'S BOOKCASE (A75): a piece of furniture — a cornice with its
     plaque, two shelves on planks, the year's books along the top and the
     three ways to read it below. The books settle onto the shelf as the
     library opens. Ink and sunk paper at rest (D3). */
  .bookcase { margin:var(--s6) 0 0; background:var(--paper-sunk); border:10px solid var(--ink-pressed);
              border-top-width:0; box-shadow:inset 0 2px 0 var(--rule); }
  .bookcase-top { display:flex; justify-content:center; padding:var(--s2) 0; background:var(--ink-pressed); }
  .bookcase-plaque { padding:2px var(--s4); background:var(--paper-raised); border:1px solid var(--muted);
                     font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.2em; text-transform:uppercase; color:var(--rubric); }
  .bookcase-shelf { padding:var(--s4) var(--s4) 0; border-bottom:10px solid var(--ink-pressed); box-shadow:0 1px 0 var(--paper-raised); }
  .bookcase-shelf .case-row { min-height:170px; }
  .bookcase-shelf .case-label { margin:0; }
  /* The year's books are set on the shelf one at a time, each lowered and
     settling with the smallest give, never dropped in a rush (A77). */
  .bookcase .case-row > * { animation:shelve 1.2s cubic-bezier(.3, 0, .2, 1) .2s both; }
  .bookcase .case-row > :nth-child(2) { animation-delay:.36s; } .bookcase .case-row > :nth-child(3) { animation-delay:.52s; }
  .bookcase .case-row > :nth-child(4) { animation-delay:.68s; } .bookcase .case-row > :nth-child(5) { animation-delay:.84s; }
  .bookcase .case-row > :nth-child(n+6) { animation-delay:1s; }
  @keyframes shelve { 0% { opacity:0; transform:translateY(-18px); } 55% { opacity:1; } 78% { transform:translateY(1.5px); } 100% { opacity:1; transform:none; } }

  /* THE STUDIO (A76): voices only, in the order they are asked about — who is
     on air, who else could be, and where you will hear them. */
  .on-air { display:flex; flex-wrap:wrap; align-items:center; gap:var(--s4); padding:var(--s4);
            background:var(--paper-raised); border:1px solid var(--rule); }
  .on-air-lamp { flex:none; padding:var(--s1) var(--s3); border:1px solid var(--rubric); color:var(--rubric);
                 font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.18em; text-transform:uppercase; }
  .on-air.playing .on-air-lamp { background:var(--rubric); color:var(--paper-raised); animation:lamp 1.4s var(--ease) infinite alternate; }
  @keyframes lamp { to { opacity:.55; } }
  .on-air-words { flex:1; min-width:12rem; display:flex; flex-direction:column; gap:2px; }
  .on-air-words .eyebrow { margin:0; }
  .on-air-name { font-family:var(--font-read); font-size:var(--text-2xl); line-height:1.2; }
  .on-air-hear { padding:var(--s3) var(--s6); }
  .studio-h { margin:var(--s8) 0 var(--s3); }
  .mic-grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); gap:var(--s3); }
  .mic-card { display:flex; flex-direction:column; align-items:flex-start; gap:var(--s1); width:auto; margin:0; padding:var(--s4);
              background:var(--paper-raised); border:1px solid var(--rule); border-radius:var(--radius-paper);
              color:var(--ink); text-align:left; transition:border-color .2s var(--ease); }
  .mic-card.on { border-color:var(--rubric); }
  .voice-name { display:block; font-family:var(--font-read); font-size:var(--text-xl); line-height:1.25; }
  .voice-note { display:block; }
  .voice-remove { color:var(--rubric); }
  .mic-top { display:flex; align-items:flex-start; justify-content:space-between; align-self:stretch; margin-bottom:var(--s2); }
  .mic-top .mic-now { min-height:0; padding:2px var(--s2); border:1px solid var(--rubric); }
  /* A VOICE'S FACE (A77): its person, in the desk's own style. Chosen, it
     takes its colour and blinks now and then; speaking, its mouth moves. */
  .face-tile { display:inline-flex; flex:none; width:auto; height:auto; margin:0; padding:0; border:0; background:none; box-shadow:none; }
  .face-tile:is(:hover, :focus-visible, .play) { background:none; box-shadow:none; }
  .face { display:block; width:58px; height:auto; aspect-ratio:72 / 78; overflow:hidden; }
  .face-lg .face { width:78px; } .face-sm .face { width:40px; }
  .face .bd { opacity:1; }
  .hub-art .who rect.i-mouth { fill:var(--ink-pressed); stroke:none; transform-box:fill-box; transform-origin:center; transform:scaleY(.5); }
  .face-tile.play .i-eye { transform-box:fill-box; transform-origin:center; animation:blink 5.2s ease-in-out 1.5s infinite; }
  .face-tile.talking .i-mouth { animation:talk .24s ease-in-out infinite alternate; }
  @keyframes blink { 0%, 93%, 100% { transform:none; } 96% { transform:scaleY(.1); } }
  @keyframes talk  { from { transform:scaleY(.4); } to { transform:scaleY(2); } }
  .on-air .face-tile { align-self:center; }
  .on-air .on-air-lamp { align-self:flex-start; display:inline-block; }
  .face-xl .face { width:132px; }
  /* what a voice's person looks like, chosen by the face each choice would make */
  .look-pick { display:grid; grid-template-columns:1fr; gap:var(--s4); }
  @media (min-width:640px) { .look-pick { grid-template-columns:auto minmax(0, 1fr); align-items:start; } }
  .look-face { display:flex; justify-content:center; padding:var(--s4); background:var(--paper-raised); border:1px solid var(--rule); }
  @media (min-width:640px) { .look-face { position:sticky; top:calc(env(safe-area-inset-top, 0px) + 72px); } }
  .look-groups { display:flex; flex-direction:column; gap:var(--s3); min-width:0; }
  .look-group .eyebrow { margin:0 0 var(--s1); }
  .look-row { display:flex; flex-wrap:wrap; gap:var(--s1); }
  .look-opt { width:auto; min-height:44px; margin:0; padding:2px; border:1px solid transparent; border-radius:var(--radius-paper);
              background:none; cursor:pointer; transition:border-color var(--dur) var(--ease); }
  .look-opt:hover, .look-opt:focus-visible { border-color:var(--ink); background:none; }
  .look-opt[aria-checked="true"] { border-color:var(--rubric); }
  .teller-opt { display:flex; align-items:center; gap:var(--s3); }
  .mic-actions { display:flex; flex-direction:column; align-items:flex-start; gap:var(--s1); margin-top:auto; padding-top:var(--s3); }
  .mic-links { display:flex; flex-wrap:wrap; gap:var(--s6); }
  .mic-actions .btn-quiet { width:auto; padding:var(--s2) var(--s4); font-size:var(--text-base); }
  .mic-actions .linkish { width:auto; margin:0; min-height:44px; padding:var(--s2) 0; }
  .mic-now { display:inline-flex; align-items:center; min-height:44px; font-family:var(--font-annotate); font-size:var(--text-2xs);
             letter-spacing:.16em; text-transform:uppercase; color:var(--rubric); }
  .mic-add { border-style:dashed; background:transparent; font-family:var(--font-read); font-size:inherit; letter-spacing:normal; cursor:pointer; }
  .mic-add:hover, .mic-add:focus-visible { border-color:var(--ink); background:var(--paper-raised); }
  .mic-add .voice-note { font-family:var(--font-annotate); }
  .mic-plus { display:flex; align-items:center; justify-content:center; width:40px; height:40px; margin-bottom:var(--s2);
              border:1px dashed var(--rubric); border-radius:var(--radius-button); color:var(--rubric);
              font-family:var(--font-read); font-size:var(--text-2xl); line-height:1; transition:transform .7s var(--ease-settling); }
  .mic-add:hover .mic-plus, .mic-add:focus-visible .mic-plus { transform:rotate(90deg); }
  .hear-where { display:grid; grid-template-columns:1fr; gap:var(--s4); }
  @media (min-width:640px) { .hear-where { grid-template-columns:repeat(3, minmax(0, 1fr)); } }
  .hear-cell { display:block; padding:var(--s3) 0 0; border-top:2px solid var(--ink); color:var(--ink); text-decoration:none; }
  a.hear-cell { cursor:pointer; }
  a.hear-cell:hover .hear-k, a.hear-cell:focus-visible .hear-k { color:var(--rubric); }
  .hear-k { font-family:var(--font-read); font-size:var(--text-xl); }
  .hear-cell .note { margin:var(--s1) 0 0; }
  .studio-terms { margin-top:var(--s8); border-top:1px solid var(--rule); text-decoration:none; }
  /* The one quiet line at the foot of the desk that opens the endpapers. */
  a.desk-foot { display:table; margin:var(--s8) auto 0; font-family:var(--font-annotate); font-size:var(--text-xs);
                letter-spacing:.06em; color:var(--muted); text-decoration:none; }
  a.desk-foot:hover, a.desk-foot:focus-visible { color:var(--rubric); }

  /* THE ENDPAPERS (A76): you on the left, the library and the small print
     stacked beside it. */
  .ep-grid { display:grid; grid-template-columns:1fr; gap:var(--s4); margin:var(--s4) 0 0; }
  @media (min-width:760px) { .ep-grid { grid-template-columns:minmax(0, 1fr) minmax(0, 1fr); align-items:start; } }
  .ep-card { padding:var(--s4) var(--s4) var(--s3); background:var(--paper-raised); border:1px solid var(--rule); }
  .ep-card .row:last-child { border-bottom:0; }
  .season-chips button { display:inline-flex; align-items:center; gap:var(--s2); }
  .season-glyph { display:inline-block; width:14px; height:14px; }
  .season-glyph svg { display:block; width:100%; height:100%; overflow:visible; }

  /* THROUGH THEIR EYES (A76): the life of one question, left to right — the
     three steps up top, then a numbered part of the page for each. */
  .eyes-line { margin:var(--s3) 0 var(--s6); max-width:40ch; font-family:var(--font-read); font-style:italic;
               font-size:var(--text-xl); line-height:1.4; color:var(--ink); }
  .eyes-foot { margin:var(--s8) auto 0; text-align:center; color:var(--muted); }
  .eyes-steps { list-style:none; margin:0; padding:0; display:grid; grid-template-columns:1fr; gap:var(--s2); }
  /* on a phone the three steps are a row you swipe, one card in view and the
     next showing at the edge (A79) */
  @media (max-width:639px) {
    .eyes-steps { grid-template-columns:none; grid-auto-flow:column; grid-auto-columns:82%; gap:var(--s3);
                  overflow-x:auto; scroll-snap-type:x mandatory; padding-bottom:var(--s2); margin-inline:calc(var(--pad-x) * -1);
                  padding-inline:var(--pad-x); scroll-padding-inline:var(--pad-x); }
    .eyes-steps li { scroll-snap-align:start; }
  }
  @media (min-width:640px) { .eyes-steps { grid-template-columns:repeat(3, minmax(0, 1fr)); gap:var(--s6); } }
  .eyes-steps li { display:flex; }
  .eyes-step { position:relative; flex:1; display:grid; grid-template-columns:auto minmax(0, 1fr); column-gap:var(--s3); row-gap:var(--s1);
               align-content:start; width:100%; margin:0; padding:var(--s4); background:var(--paper-raised); border:1px solid var(--rule);
               border-radius:var(--radius-paper); color:var(--ink); text-align:left; font-size:inherit; letter-spacing:normal;
               transition:border-color .4s var(--ease), transform .5s var(--ease-settling); }
  .eyes-step:hover, .eyes-step:focus-visible { border-color:var(--ink); transform:translateY(-2px); }
  .eyes-step > :not(.step-n) { grid-column:2; }
  .eyes-step .step-n { grid-row:1 / span 3; }
  /* The arrow between steps, at width: this happens, then this. */
  @media (min-width:640px) {
    .eyes-steps li:not(:last-child) .eyes-step::after { content:'\203A'; position:absolute; right:calc(-1 * var(--s6) / 2); top:50%;
      transform:translate(50%, -50%); color:var(--rubric); font-family:var(--font-read); font-size:var(--text-2xl); }
  }
  .step-n { display:inline-flex; align-items:center; justify-content:center; width:28px; height:28px; flex:none;
            border:1px solid var(--rubric); border-radius:var(--radius-button); color:var(--rubric);
            font-family:var(--font-annotate); font-size:var(--text-xs); line-height:1; }
  .step-k { font-family:var(--font-read); font-size:var(--text-xl); line-height:1.2; }
  .step-say { margin:0; font-size:var(--text-sm); line-height:1.5; }
  .step-count { margin-top:var(--s1); font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.14em;
                text-transform:uppercase; color:var(--rubric); }
  .eyes-sec { margin:var(--s8) 0 0; padding-top:var(--s6); border-top:1px solid var(--rule); scroll-margin-top:calc(var(--s8) * 3); }
  .eyes-sec:focus { outline:none; }
  .eyes-h { display:flex; align-items:center; gap:var(--s3); margin:0 0 var(--s4); font-family:var(--font-read); font-weight:400;
            font-size:var(--text-2xl); line-height:1.2; }
  .eyes-empty { margin:0; padding:var(--s4); border:1px dashed var(--rule); }
  /* ① the card on a mat, the choices beside it */
  .ask-desk { display:grid; grid-template-columns:1fr; gap:var(--s6); padding:var(--s4); background:var(--paper-sunk); border:1px solid var(--rule); }
  @media (min-width:760px) { .ask-desk { grid-template-columns:minmax(0, 1.15fr) minmax(0, 1fr); gap:var(--s8); padding:var(--s6); } }
  .ask-pick, .ask-form { min-width:0; }
  .ask-pick .deck-why { margin-top:var(--s4); }
  .ask-form { display:flex; flex-direction:column; gap:var(--s4); }
  .ask-field .eyebrow { margin:0 0 var(--s2); }
  .ask-field .field { margin-top:var(--s2); }
  .ask-form .deck-first { margin:0; }
  .ask-hint { margin:calc(-1 * var(--s2)) 0 0; text-align:center; }
  /* A note in the margin's own voice: rubric, set like the margin notes. */
  .lens-note { margin:var(--s2) 0 0; font-family:var(--font-annotate); font-size:var(--text-xs); line-height:1.7;
               letter-spacing:.04em; color:var(--rubric); max-width:46ch; }
  .reader-lens { margin:var(--s3) 0 var(--s6); padding-left:var(--s3); border-left:1px solid var(--rubric); }
  .deck-card { padding:var(--s6) var(--s6) var(--s8); background:var(--paper-raised); border:1px solid var(--rule); box-shadow:var(--lift);
               transform:rotate(-1.2deg); }
  .deck-card.dealt { animation:deal .85s var(--ease-settling) both; }
  @keyframes deal { from { opacity:0; transform:translate(16px, -8px) rotate(4deg); } to { opacity:1; transform:rotate(-1.2deg); } }
  .deck-tone { font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.16em; text-transform:uppercase; color:var(--rubric); }
  .deck-q { margin:var(--s2) 0 0; font-family:var(--font-read); font-size:var(--text-2xl); line-height:1.3; color:var(--ink); }
  .deck-more { display:flex; flex-wrap:wrap; gap:0 var(--s6); margin-top:var(--s3); }
  .deck-more .linkish { margin:0; min-height:44px; }
  .deck-first { display:flex; gap:var(--s3); align-items:flex-start; margin:var(--s4) 0 0; max-width:52ch; cursor:pointer; }
  .deck-first input { margin-top:5px; width:18px; height:18px; flex:none; accent-color:var(--rubric); }
  .deck-first b { font-weight:400; color:var(--ink); }
  .deck-first span { font-family:var(--font-read); font-size:var(--text-lg); color:var(--muted); }
  .deck-sent { margin-top:var(--s4); }
  .deck-link { display:flex; gap:var(--s2); align-items:center; flex-wrap:wrap; }
  .deck-link code { flex:1; min-width:0; overflow-wrap:anywhere; font-family:var(--font-annotate); font-size:var(--text-2xs); color:var(--ink); }
  .chips [role="radio"][aria-checked="true"] { border-color:var(--rubric); color:var(--rubric); }
  /* ② what is out, beside the round */
  .eyes-pair { display:grid; grid-template-columns:1fr; gap:var(--s6); }
  @media (min-width:760px) { .eyes-pair { grid-template-columns:minmax(0, 1.2fr) minmax(0, 1fr); align-items:start; } }
  .eyes-pair .case-label { margin:0 0 var(--s2); }
  .wait-row { display:grid; grid-template-columns:minmax(80px, auto) 1fr; gap:var(--s1) var(--s4); padding:var(--s3) 0; border-bottom:1px solid var(--rule); }
  .wait-row:first-child { border-top:1px solid var(--rule); }
  .wait-who { font-family:var(--font-annotate); font-size:var(--text-xs); letter-spacing:.14em; text-transform:uppercase; }
  .wait-q { font-family:var(--font-read); font-size:var(--text-lg); }
  .wait-state { grid-column:2; font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.1em; text-transform:uppercase; color:var(--muted); }
  .wait-state.done { color:var(--rubric); }
  .wait-nudge { grid-column:2; justify-self:start; width:auto; margin:0; }
  .round-card { padding:var(--s4); background:var(--paper-raised); border:1px solid var(--rule); }
  .round-env { display:flex; gap:var(--s4); margin-top:var(--s4); flex-wrap:wrap; }
  .round-one { display:flex; flex-direction:column; align-items:center; gap:var(--s1); }
  .round-one small { font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.1em; color:var(--muted); }
  .round-seal { position:relative; width:52px; height:36px; background:var(--paper-sunk); border:1px solid var(--muted); }
  .round-seal::after { content:''; position:absolute; left:50%; top:50%; width:12px; height:12px; margin:-6px 0 0 -6px; border-radius:var(--radius-button); background:var(--rubric); }
  .round-one.open .round-seal::after { opacity:0; }
  /* ③ what came back, a picture card each */
  .their-grid { display:grid; grid-template-columns:1fr; gap:var(--s8) var(--s6); }
  @media (min-width:760px) { .their-grid { grid-template-columns:repeat(2, minmax(0, 1fr)); } }
  .their-grid .eyes-empty { grid-column:1 / -1; }
  .their-card { display:flex; flex-direction:column; gap:var(--s4); min-width:0; }
  .their-photo { aspect-ratio:4 / 3; overflow:hidden; background:var(--paper-sunk); border:6px solid var(--paper-raised); outline:1px solid var(--rule);
                 transform:rotate(-1deg); transition:transform .4s var(--ease); }
  .their-card:nth-child(even) .their-photo { transform:rotate(.8deg); }
  .their-card:hover .their-photo { transform:rotate(0) translateY(-3px); }
  .their-photo img { display:block; width:100%; height:100%; object-fit:cover; }
  .their-words { display:flex; flex-direction:column; gap:var(--s1); }
  .their-title { font-family:var(--font-read); font-size:var(--text-2xl); line-height:1.2; }
  .their-asked { font-style:italic; }
  .their-actions { display:flex; flex-wrap:wrap; align-items:center; gap:var(--s3); margin-top:var(--s4); }
  .their-actions .narrate { margin:0; }

  /* THE QUESTION, at the other end. */
  .ask-page { max-width:var(--page-doc); margin:0 auto; text-align:center; }
  .ask-card { margin:var(--s4) auto var(--s3); max-width:460px; text-align:left; }
  .ask-first { margin:var(--s4) auto 0; max-width:44ch; }
  .ask-page .lens-note, .ask-page .eyes-line { margin-left:auto; margin-right:auto; }
  .ask-how { margin:var(--s6) auto; max-width:44ch; text-align:left; font-family:var(--font-read); font-size:var(--text-lg); line-height:1.5; }
  .ask-how p { margin:0 0 var(--s2); } .ask-how b { font-family:var(--font-annotate); font-weight:400; color:var(--rubric); margin-right:var(--s2); }

  /* A LETTER, OPENED (A75): the pocket, the sheet that rises out of it, the
     seal that cracks. A ready letter gives a small wiggle, twice, to say so. */
  .envelope-front { position:absolute; inset:0; z-index:2; background:var(--paper-raised);
                    clip-path:polygon(0 30%, 50% 72%, 100% 30%, 100% 100%, 0 100%); border-top:1px solid var(--rule); }
  .envelope-sheet { position:absolute; left:8%; right:8%; top:12%; height:78%; z-index:1; padding:12% 9% 0;
                    background:var(--paper); border:1px solid var(--rule); transition:transform 1.2s var(--ease-settling); }
  .envelope-sheet i { display:block; height:2px; margin:0 0 9%; background:var(--rule); }
  .envelope-sheet i:nth-child(2) { width:80%; } .envelope-sheet i:nth-child(4) { width:60%; }
  .envelope:not(.open) .envelope-sheet { opacity:0; }
  .envelope.out .envelope-sheet { transform:translateY(-62%); }
  .envelope-to, .postmark { z-index:3; }
  .envelope.ready { animation:env-ready 1.1s ease-in-out .8s 2; }
  @keyframes env-ready { 0%, 100% { transform:none; } 25% { transform:rotate(-1.4deg); } 75% { transform:rotate(1.4deg); } }
  .envelope.cracking .seal { animation:seal-crack .7s ease-in-out both; }
  .envelope.cracking .seal::before, .envelope.cracking .seal::after { content:''; position:absolute; width:9px; height:9px; border-radius:var(--radius-button);
                    background:var(--rubric); left:24px; top:24px; animation:wax-l .9s var(--ease-settling) .4s both; }
  .envelope.cracking .seal::after { animation-name:wax-r; }
  @keyframes seal-crack { 30% { transform:translate(-50%, -50%) rotate(-8deg); } 60% { transform:translate(-50%, -50%) rotate(7deg) scale(1.08); }
                          100% { transform:translate(-50%, -50%) scale(1.25); opacity:0; } }
  @keyframes wax-l { to { transform:translate(-34px, 22px) scale(.4); opacity:0; } }
  @keyframes wax-r { to { transform:translate(30px, 26px) scale(.5); opacity:0; } }
  .letter-narrate { justify-content:center; margin:var(--s6) auto 0; }
  .postcard { animation:card-flip 1.1s var(--ease-settling) .2s both; }
  @keyframes card-flip { from { transform:perspective(800px) rotateY(70deg); opacity:0; } to { transform:none; opacity:1; } }

  /* THE SCROLL: a heading with its chart in the corner, then short rows. */
  .scroll-head { display:flex; justify-content:space-between; align-items:flex-start; gap:var(--s4); margin-bottom:var(--s6); }
  .chart-corner { flex:none; width:clamp(140px, 34vw, 240px); margin:22px 0 0; padding:4px; height:auto;
                  background:var(--paper-raised); border:1px solid var(--rule); border-radius:var(--radius-paper);
                  box-shadow:var(--lift); transform:rotate(1.2deg); cursor:zoom-in; }
  .chart-corner:hover { border-color:var(--ink); background:var(--paper-raised); }
  .chart-corner svg { width:100%; height:auto; display:block; }
  .scroll-row { display:grid; grid-template-columns:minmax(96px, 30%) 1fr; gap:var(--s4); align-items:center;
                padding:var(--s4) 0; border-top:1px solid var(--rule); cursor:pointer; }
  .scroll-frame { aspect-ratio:4 / 3; overflow:hidden; background:var(--paper-sunk); border:1px solid var(--rule); }
  .scroll-frame img { width:100%; height:100%; object-fit:cover; display:block; transform:scale(1.08); }
  .scroll-frame .well { height:100%; }
  /* The drift: across the picture and back, only while the row is in view.
     The third ambient motion (A71); none under reduced motion. */
  .scroll-row.in-view .scroll-frame img { animation:scroll-drift 16s ease-in-out infinite alternate; }
  @keyframes scroll-drift { from { transform:scale(1.08) translate(-2.5%, 1%); } to { transform:scale(1.14) translate(2.5%, -1.5%); } }
  .scroll-words { display:flex; flex-direction:column; gap:var(--s1); min-width:0; }
  .scroll-title { font-family:var(--font-read); font-size:var(--text-2xl); line-height:1.2; color:var(--ink); }
  .scroll-line { font-family:var(--font-read); font-style:italic; font-size:var(--text-lg); line-height:1.35; color:var(--muted); }
  .scroll-added { font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.12em; text-transform:uppercase; color:var(--rubric); }

  /* THE CHART: engraved, in the page's own inks. Sea is paper, land a sunk
     well with an ink coast, the graticule in rule; × marks in rubric, home a
     compass star in ink. */
  .chart-svg { font-family:var(--font-annotate); }
  .ch-sea { fill:var(--paper-raised); }
  .ch-land { fill:var(--paper-sunk); stroke:var(--muted); stroke-width:.6; }
  .ch-land.home { fill:var(--rule); stroke:var(--ink); }
  .ch-grat { fill:none; stroke:var(--rule); stroke-width:.6; }
  .ch-ring { fill:none; stroke:var(--muted); stroke-width:.7; stroke-dasharray:3 3; }
  .ch-spoke { stroke:var(--rule); stroke-width:.6; }
  .ch-spoke.main { stroke:var(--muted); }
  .ch-pin { stroke:var(--rubric); stroke-width:1.8; stroke-linecap:round; fill:none; }
  .ch-home { fill:var(--ink); }
  .ch-rose circle, .ch-rose path { fill:none; stroke:var(--muted); stroke-width:.7; }
  .ch-rose text, .ch-n { font-size:7px; fill:var(--muted); letter-spacing:.1em; }
  .ch-label { font-size:11px; fill:var(--ink); letter-spacing:.04em; }
  .ch-cartouche { font-size:8px; letter-spacing:.18em; text-transform:uppercase; fill:var(--muted); }
  .chart-sheet { position:fixed; inset:0; z-index:90; display:grid; grid-template-rows:auto 1fr auto;
                 background:var(--paper); padding:calc(var(--s4) + env(safe-area-inset-top, 0px)) var(--s4) var(--s4); }
  .chart-sheet-head { display:flex; flex-wrap:wrap; align-items:center; gap:var(--s3) var(--s4); }
  .chart-sheet-head .chips { flex:1; }
  .chart-sheet-head button, .chart-zoom button { width:auto; padding:var(--s2) var(--s4); font-size:var(--text-base); }
  .chart-sheet [data-level][aria-pressed="true"] { border-color:var(--rubric); color:var(--rubric); }
  .chart-stage { position:relative; min-height:0; margin:var(--s3) 0; border:1px solid var(--rule); background:var(--paper-raised);
                 touch-action:none; cursor:grab; overflow:hidden; }
  .chart-stage svg { width:100%; height:100%; display:block; }
  .chart-zoom { position:absolute; right:calc(var(--s4) + 12px); bottom:calc(var(--s8) + 30px); display:flex; gap:var(--s2); }
  .chart-why { margin:0; }

  /* THE SHELF'S RIBBONS: a bookmark hanging over the top of each book, in
     rubric because touching it is the reader acting. */
  .shelf-slot { position:relative; display:flex; }
  .ribbon { position:absolute; top:-6px; right:16%; z-index:3; width:28px; height:58px; min-height:44px;
            padding:0; border:0; border-radius:0; background:transparent; }
  .ribbon span { display:block; width:14px; height:52px; margin:0 auto; background:var(--rubric);
                 clip-path:polygon(0 0, 100% 0, 100% 100%, 50% 80%, 0 100%);
                 transition:transform var(--dur) var(--ease); transform-origin:top; }
  .ribbon:hover span, .ribbon:focus-visible span { transform:scaleY(1.12); }
  .ribbon:hover { background:transparent; }

  /* THE TOUR behind a ribbon: three cards, faded one into the next. */
  .tour-sheet { position:fixed; inset:0; z-index:90; display:grid; place-items:center; padding:var(--s4);
                background:color-mix(in srgb, var(--ink) 30%, transparent); animation:arrives .3s var(--ease-arriving) both; }
  .tour-card { width:min(420px, 100%); padding:var(--s6); background:var(--paper); border:1px solid var(--rule); box-shadow:var(--lift); }
  .tour-stage { position:relative; height:250px; margin-top:var(--s3); }
  .tour-step { position:absolute; inset:0; opacity:0; transition:opacity .5s var(--ease-settling); pointer-events:none; }
  .tour-step.on { opacity:1; pointer-events:auto; }
  .tour-step svg { width:100%; height:170px; display:block; }
  .tour-line { margin:var(--s3) 0 0; font-family:var(--font-read); font-size:var(--text-xl); line-height:1.35; color:var(--ink); }
  .tour-dots { display:flex; gap:6px; justify-content:center; margin:var(--s3) 0; }
  .tour-dots span { width:6px; height:6px; background:var(--rule); }
  .tour-dots span.on { background:var(--rubric); }
  .tour-actions { display:flex; justify-content:space-between; gap:var(--s2); }
  .tour-actions button { width:auto; padding:var(--s2) var(--s4); font-size:var(--text-base); }
  .tour-paper { fill:var(--paper-raised); stroke:var(--muted); stroke-width:1; }
  .tour-ink { fill:none; stroke:var(--muted); stroke-width:2; stroke-linecap:round; }
  .tour-red { fill:none; stroke:var(--rubric); stroke-width:2; stroke-linecap:round; }
  .tour-rule { stroke:var(--rubric); stroke-width:1.5; }
  .tour-day { fill:var(--paper-raised); stroke:var(--rule); }
  .tour-today { fill:none; stroke:var(--rubric); stroke-width:2; }
  .tour-seal { fill:var(--rubric); }
  .tour-count, .tour-when, .tour-name { font-family:var(--font-annotate); font-size:10px; letter-spacing:.14em; fill:var(--muted); }
  .tour-land { fill:var(--paper-sunk); stroke:var(--muted); }
  .tour-x { fill:none; stroke:var(--rubric); stroke-width:2.4; stroke-linecap:round; }
  .tour-plate { fill:var(--paper-sunk); }
  .tour-ticket { fill:var(--paper-sunk); stroke:var(--muted); }
  .tour-write { fill:none; stroke:var(--ink); stroke-width:1.6; stroke-linecap:round; stroke-dasharray:1; }
  .tour-day, .tour-seal, .tour-rise, .tour-x, .tour-roll, .tour-note, .tour-drop, .tour-stick { transform-box:fill-box; transform-origin:center; }
  .tour-step.on .tour-day { animation:tour-light 3s ease-in-out calc(var(--i) * 90ms) infinite; }
  .tour-step.on .tour-today { animation:tour-pop 3s ease-in-out infinite; }
  .tour-step.on .tour-seal { animation:tour-pulse 1.6s ease-in-out infinite; }
  .tour-step.on .tour-rise { animation:tour-rise 2.8s var(--ease-settling) infinite; }
  .tour-step.on .tour-roll { animation:tour-roll 6s linear infinite; }
  .tour-step.on .tour-x { animation:tour-mark 3.2s ease-out calc(var(--i) * 500ms) infinite; }
  .tour-step.on .tour-note { animation:tour-note 3s var(--ease-settling) infinite; }
  .tour-step.on .tour-drop { animation:tour-drop 3s var(--ease-settling) infinite; }
  .tour-step.on .tour-stick { animation:tour-stick 3s var(--ease-settling) infinite; }
  .tour-step.on .tour-write { animation:tour-write 3s ease-in-out infinite; }
  @keyframes tour-light { 0%, 100% { fill:var(--paper-raised); } 30% { fill:var(--paper-sunk); } }
  @keyframes tour-pop   { 0%, 60% { opacity:0; } 75%, 100% { opacity:1; } }
  @keyframes tour-pulse { 50% { transform:scale(1.15); } }
  @keyframes tour-rise  { 0% { opacity:0; transform:translateY(16px); } 30%, 80% { opacity:1; transform:none; } 100% { opacity:0; } }
  @keyframes tour-roll  { from { transform:translateY(0); } to { transform:translateY(-150px); } }
  @keyframes tour-mark  { 0%, 10% { opacity:0; transform:scale(1.8); } 25%, 85% { opacity:1; transform:none; } 100% { opacity:0; } }
  @keyframes tour-note  { 0% { opacity:0; transform:translateX(24px); } 30%, 85% { opacity:1; transform:none; } 100% { opacity:0; } }
  @keyframes tour-drop  { 0% { opacity:0; transform:translateY(-30px) rotate(-8deg); } 35%, 85% { opacity:1; transform:rotate(-2deg); } 100% { opacity:0; } }
  @keyframes tour-stick { 0% { transform:translate(30px, -20px) rotate(14deg); opacity:0; } 40%, 85% { transform:translate(-60px, 50px) rotate(-6deg); opacity:1; } 100% { opacity:0; transform:translate(-60px, 50px) rotate(-6deg); } }
  @keyframes tour-write { 0% { stroke-dashoffset:1; } 60%, 100% { stroke-dashoffset:0; } }

  /* THE GAZETTE: a town paper, one issue a week. */
  .gz-mast { border-bottom:3px double var(--ink); padding-bottom:var(--s4); margin-bottom:var(--s6); }
  .gz-prompt { padding:var(--s6) 0; border-bottom:1px solid var(--rule); }
  .gz-q { margin:var(--s2) 0 var(--s3); font-family:var(--font-read); font-size:clamp(28px, 5vw, 44px); line-height:1.1; color:var(--ink); }
  .gz-sec { margin:var(--s8) 0 var(--s4); }
  .gz-chosen { display:grid; grid-template-columns:repeat(auto-fill, minmax(220px, 1fr)); gap:var(--s4); align-items:start; }
  .gz-story { padding:var(--s4); background:var(--paper-raised); border:1px solid var(--rule); }
  .gz-art { aspect-ratio:4 / 3; overflow:hidden; margin:calc(var(--s4) * -1) calc(var(--s4) * -1) var(--s3); border-bottom:1px solid var(--rule); }
  .gz-art img { width:100%; height:100%; object-fit:cover; display:block; }
  .gz-t { margin:0; font-family:var(--font-read); font-weight:400; font-size:var(--text-2xl); line-height:1.15; }
  .gz-line { margin:var(--s2) 0 var(--s3); font-family:var(--font-read); font-style:italic; font-size:var(--text-lg); line-height:1.35; color:var(--muted); }
  .gz-issue { border-top:1px solid var(--rule); }
  .gz-issue summary { display:flex; flex-wrap:wrap; align-items:baseline; gap:2px var(--s3); padding:var(--s3) 0; cursor:pointer; min-height:44px; list-style:none; }
  .gz-issue summary .gz-meta { flex-basis:100%; }
  .gz-inner { margin-left:var(--s4); }
  .gz-issue summary::-webkit-details-marker { display:none; }
  .gz-no { font-family:var(--font-annotate); font-size:var(--text-sm); letter-spacing:.12em; color:var(--rubric); }
  .gz-ip { font-family:var(--font-read); font-size:var(--text-xl); color:var(--ink); }
  .gz-meta { font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.12em; text-transform:uppercase; color:var(--muted); }
  .gz-issue[open] .gz-chosen { padding-bottom:var(--s6); }
  .gz-pick { display:flex; flex-direction:column; gap:var(--s2); margin-top:var(--s4); max-width:34rem; }
  .gz-entered { margin-top:var(--s4); max-width:34rem; }
  .gz-how { margin-top:var(--s8); max-width:44ch; }
  /* The front page: the week's winner, set larger, across the column. */
  .gz-lead { display:grid; grid-template-columns:minmax(0, 1fr); margin-bottom:var(--s4); padding:var(--s6); }
  .gz-lead .gz-t { font-size:clamp(26px, 4vw, 36px); }
  .gz-lead .gz-line { font-size:var(--text-xl); max-width:52ch; }
  @media (min-width:720px) { .gz-lead:has(.gz-art) { grid-template-columns:minmax(0, 1fr) minmax(0, 1.2fr); column-gap:var(--s6); }
    .gz-lead .gz-art { grid-row:span 5; margin:calc(var(--s6) * -1) 0 calc(var(--s6) * -1) calc(var(--s6) * -1); border:0; border-right:1px solid var(--rule); aspect-ratio:auto; } }
  .gz-flag { color:var(--rubric); margin-bottom:var(--s2); }
  /* The desk answers in its own voice, set apart by a rule, in the mono. */
  .gz-desk { margin:var(--s3) 0 0; padding-top:var(--s2); border-top:1px solid var(--rule);
             font-family:var(--font-annotate); font-size:var(--text-sm); line-height:1.6; color:var(--ink); }
  .gz-desk span { color:var(--rubric); letter-spacing:.08em; }
  /* The month so far: one column per issue, building to this week's, open. */
  .gz-month { display:grid; grid-template-columns:repeat(auto-fill, minmax(200px, 1fr)); gap:0; border-top:3px double var(--ink); }
  .gz-col { padding:var(--s4) var(--s4) var(--s4) 0; border-right:1px solid var(--rule); }
  .gz-col + .gz-col { padding-left:var(--s4); }
  .gz-col:last-child { border-right:0; }
  .gz-col .gz-ip { display:block; margin:var(--s2) 0; line-height:1.2; }
  .gz-won { margin:var(--s2) 0 0; font-family:var(--font-read); font-style:italic; font-size:var(--text-lg); color:var(--muted); }
  .gz-won .eyebrow { display:block; font-style:normal; color:var(--rubric); }
  .gz-col-next .gz-ip { color:var(--muted); font-style:italic; }

  /* MAKING A CHAPTER (A72): what it becomes, drawn; and the spoken questions. */
  /* MAKING A CHAPTER (A77). First, alone: what it becomes — two drawn
     blocks, each playing what it would be. Chosen, they shrink to a pair
     of tabs above the rest, which arrives in two columns on a wide screen:
     the photographs and the telling on the left; how it sounds, its shape
     and who tells it on the right. */
  .make-pick { display:grid; grid-template-columns:1fr; gap:var(--s4); }
  @media (min-width:600px) { .make-pick { grid-template-columns:repeat(2, minmax(0, 1fr)); } }
  .make-block { display:flex; flex-direction:column; align-items:flex-start; gap:var(--s2); padding:var(--s6); cursor:pointer;
                transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), padding .5s var(--ease-settling); }
  .make-block[aria-checked="true"] { border-color:var(--rubric); }
  .make-art { display:block; width:100%; height:auto; aspect-ratio:160 / 100; transition:width .5s var(--ease-settling); }
  .make-t { font-family:var(--font-read); font-size:var(--text-2xl); color:var(--ink); }
  .make-n { font-size:var(--text-sm); }
  .make-pick.chosen { grid-template-columns:repeat(2, minmax(0, 1fr)); }
  .make-pick.chosen .make-block { flex-direction:row; align-items:center; gap:var(--s3); padding:var(--s2) var(--s3); }
  .make-pick.chosen .make-art { width:84px; flex:none; }
  .make-pick.chosen .make-t { font-size:var(--text-xl); }
  .make-pick.chosen .make-n { display:none; }
  /* Two tiles side by side at a phone's width leave ~40px beside an 84px drawing, and "scrapbook" ran out of its
     tile at 380 (QA, 28 Oct 2026): there the drawing sits above the name instead. */
  @media (max-width:599px) { .make-pick.chosen .make-block { flex-direction:column; align-items:flex-start; gap:var(--s1); }
                             .make-pick.chosen .make-art { width:64px; } }
  .make-cols { display:grid; grid-template-columns:1fr; gap:0 var(--s8); }
  @media (min-width:960px) { .make-cols { grid-template-columns:minmax(0, 1.05fr) minmax(0, 1fr); } }
  .make-sec { margin:var(--s8) 0 0; }
  .make-sec[hidden] { display:none; }
  .make-h { display:flex; justify-content:space-between; align-items:baseline; margin:0 0 var(--s3); }
  .make-go { margin-top:var(--s8); }
  @media (min-width:960px) { .make-go { width:auto; min-width:22rem; padding-inline:var(--s8); } }
  /* the contact sheet: a strip of film, its sprocket holes, its frames */
  .strip-zone { display:block; padding:0; border:0; background:none; cursor:pointer; }
  .strip { position:relative; display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:var(--s3) var(--s2);
           padding:calc(var(--s6) + 2px) var(--s3); background:var(--ink-pressed); }
  @media (min-width:480px) { .strip { grid-template-columns:repeat(4, minmax(0, 1fr)); } }
  .strip::before, .strip::after { content:''; position:absolute; left:var(--s3); right:var(--s3); border-top:5px dashed var(--paper-sunk); opacity:.5; }
  .strip::before { top:9px; } .strip::after { bottom:9px; }
  .strip.strip-one { grid-template-columns:1fr; }
  .strip-one .frame.full .frame-well, .strip-one .frame-well:has(img) { background:var(--paper-sunk); border-style:solid; border-color:var(--paper-raised); }
  .frame { position:relative; display:flex; flex-direction:column; gap:3px; margin:0; }
  .frame-edge { font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.12em;
                color:color-mix(in srgb, var(--rubric) 45%, var(--paper-sunk)); }
  .strip .frame-well { position:relative; height:auto; aspect-ratio:4 / 3; overflow:hidden;
                      background:color-mix(in srgb, var(--paper) 8%, var(--ink-pressed));
                      border:1px solid color-mix(in srgb, var(--paper) 24%, var(--ink-pressed)); transition:border-color var(--dur) var(--ease); }
  .strip .frame.next .frame-well { border-style:dashed; border-color:var(--paper-sunk); }
  .strip .frame.full .frame-well { background:var(--paper-sunk); border-color:var(--paper-raised); }
  .frame-hint { display:flex; flex-direction:column; align-items:center; gap:2px; font-family:var(--font-annotate); font-size:var(--text-2xs);
                letter-spacing:.12em; text-transform:uppercase; color:color-mix(in srgb, var(--paper) 50%, var(--ink-pressed)); }
  .frame-hint b { font-family:var(--font-read); font-weight:400; font-size:var(--text-2xl); line-height:1; }
  .frame.next .frame-hint { color:var(--paper-sunk); }
  .strip-zone:hover .frame.next .frame-well, .dropzone.dropping .frame.next .frame-well { border-color:var(--paper); }
  /* a vignette beside each choice: how it sounds, its shape */
  .vig-grid { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:var(--s3); }
  .vig-grid.vig-3 { grid-template-columns:repeat(3, minmax(0, 1fr)); }
  @media (max-width:420px) { .vig-grid.vig-3 { grid-template-columns:1fr; } }
  .vig-opt { display:flex; flex-direction:column; gap:var(--s2); padding:var(--s2) var(--s2) var(--s3); }
  .vig-tile { display:block; width:auto; height:auto; padding:0; border:0; background:var(--paper-sunk); box-shadow:none; }
  .vig-tile:is(:hover, :focus-visible, .play) { box-shadow:none; }
  .vig { display:block; width:100%; height:auto; aspect-ratio:120 / 72; overflow:hidden; }
  .vig-line { font-family:var(--font-read); font-style:italic; font-size:var(--text-lg); line-height:1.35; color:var(--ink); }
  .vig-name { font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.14em; text-transform:uppercase; }
  .vig-opt:hover .vig-tile { background:color-mix(in srgb, var(--wash) 10%, var(--paper-sunk)); }
  .vig-opt .shape-n { text-align:left; }
  /* who tells it: every voice as its person */
  .teller-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(min(100%, 9.5rem), 1fr)); gap:var(--s3); margin:0 0 var(--s3); }
  .teller-card { display:flex; flex-direction:column; align-items:center; gap:var(--s1); padding:var(--s3) var(--s2); text-align:center; }
  .teller-name { font-family:var(--font-read); font-size:var(--text-lg); line-height:1.2; }
  .teller-note { font-size:var(--text-2xs); line-height:1.4; }
  .teller-hear { width:auto; margin:0; min-height:44px; }
  /* SMALL SIGNS (A77): a line glyph beside a choice or a step, in the text's ink; rubric where the archivist marks it */
  .glyph { flex:none; width:24px; height:24px; fill:none; stroke:currentColor; stroke-width:1.4; stroke-linecap:round; stroke-linejoin:round; }
  .glyph .g-mark { stroke:var(--rubric); } .glyph .g-fill { fill:var(--rubric); stroke:none; }
  .glyph-opt, .options-row .option.glyph-opt { display:flex; flex-direction:row; align-items:center; justify-content:flex-start; gap:var(--s4); text-align:left; }
  .glyph-opt > .glyph { width:38px; height:38px; color:var(--ink); }
  .ask-step { display:flex; align-items:flex-start; gap:var(--s3); }
  .ask-step .glyph { width:28px; height:28px; margin-top:1px; color:var(--ink); }
  .step-glyph { position:absolute; top:var(--s3); right:var(--s3); color:var(--muted); }
  .eyes-step:hover .step-glyph, .eyes-step:focus-visible .step-glyph { color:var(--ink); }
  .hear-k .glyph { width:20px; height:20px; margin-right:var(--s2); vertical-align:-3px; }
  .vig-row { display:flex; align-items:center; gap:var(--s4); padding:var(--s2) var(--s3) var(--s2) var(--s2); }
  .vig-row .vig-tile { flex:none; width:clamp(96px, 28vw, 132px); }
  .look-eye { flex:none; width:32px; height:20px; margin-top:2px; fill:none; stroke:var(--ink); stroke-width:1.3; }
  .look-eye .look-pupil { fill:var(--ink); stroke:none; transition:transform .6s var(--ease-settling); transform-origin:center; transform-box:fill-box; transform:scale(.4); }
  .look:has(.tick:checked) .look-pupil { transform:none; }
  .ask-q.dealt { animation:arrives .6s var(--ease-arriving) both; }
  /* THE VIGNETTES' MOTION (A77): slow, even, and going while the choice is in
     front of you; still under reduced motion. Ink at rest, pigments once
     chosen or reached for, as on the desk. */
  :is(.vig, .make-art) path:is(.f-l, .f-m, .f-d, .f-k) { stroke:var(--muted); stroke-width:.5; stroke-linejoin:round; }
  .vg-num { font-family:var(--font-read); font-size:9px; letter-spacing:.2em; fill:var(--rubric); }
  .vg-orn { fill:none; stroke:var(--rubric); stroke-width:1; stroke-linecap:round; }
  .vg-write { fill:none; stroke:var(--muted); stroke-width:1.4; stroke-linecap:round; stroke-dasharray:44; stroke-dashoffset:44;
              animation:vg-write 6s var(--ease) var(--d, 0s) infinite; }
  .vg-leaf { stroke:var(--muted); stroke-width:.6; }
  .vg-turn { transform-origin:80px 50px; animation:vg-turn 6s var(--ease-settling) infinite; }
  .i-ribbonr { fill:var(--rubric); }
  .vg-ribbon { transform-box:fill-box; transform-origin:50% 0; animation:dk-sway 3s ease-in-out infinite alternate; }
  .vg-slot { fill:none; stroke:var(--rule); stroke-width:.8; stroke-dasharray:2 2; }
  .vg-drop { transform-box:fill-box; transform-origin:center; animation:vg-drop 6s var(--ease-settling) var(--d, 0s) infinite; }
  .vg-tape { transform-box:fill-box; transform-origin:0 50%; animation:vg-tape 6s var(--ease-settling) var(--d, 0s) infinite; }
  .vg-river { fill:none; stroke:var(--muted); stroke-width:3; stroke-linecap:round; stroke-dasharray:6 5; animation:vg-flow 3.2s linear infinite; }
  .vg-tiny { fill:none; stroke:var(--ink); stroke-width:.8; stroke-linecap:round; } .vg-tinyh { fill:var(--ink); }
  .i-bird2 { fill:none; stroke:var(--ink); stroke-width:.8; stroke-linecap:round; }
  .vg-drift { animation:vg-drift 10s linear infinite; }
  .vg-snow { fill:var(--paper-raised); stroke:var(--muted); stroke-width:.4; animation:vg-snow 4.6s linear var(--d, 0s) infinite; }
  .vg-walk { animation:vg-walk 1.3s ease-in-out var(--d, 0s) infinite; }
  .vg-head { fill:var(--paper-raised); stroke:var(--ink); stroke-width:.6; }
  .i-legs2 { fill:none; stroke:var(--ink); stroke-width:1.8; stroke-linecap:round; }
  .vg-hand { fill:none; stroke:var(--ink); stroke-width:.9; stroke-linecap:round; stroke-dasharray:60; stroke-dashoffset:60; animation:vg-hand 5s ease-in-out infinite; }
  .vg-pen { animation:vg-pen 5s ease-in-out infinite; }
  .vg-penb { fill:var(--ink-pressed); stroke:var(--ink); stroke-width:.4; }
  .vg-steam { fill:none; stroke:var(--muted); stroke-width:.9; stroke-linecap:round; animation:vg-steam 3.2s ease-in-out infinite; }
  .vg-stamp { font-family:var(--font-annotate); font-size:6px; letter-spacing:.06em; fill:var(--rubric); }
  .vg-box { fill:none; stroke:var(--ink); stroke-width:.7; }
  .vg-tick { fill:none; stroke:var(--rubric); stroke-width:1.3; stroke-linecap:round; stroke-linejoin:round; stroke-dasharray:10; stroke-dashoffset:10;
             animation:vg-tick 5.4s ease-out var(--d, 0s) infinite; }
  .vg-clockhand { transform-origin:94px 38px; animation:vg-clock 6s steps(12) infinite; }
  .vg-plate { fill:var(--paper-raised); stroke:var(--muted); stroke-width:.6; }
  .vg-talk { fill:none; stroke:var(--muted); stroke-width:.8; stroke-dasharray:1.4 2.4; }
  .vg-voice { fill:var(--rubric); offset-path:path('M28 30C40 12 52 34 62 22S88 22 92 34 86 60 76 54 46 66 40 52 18 44 28 30');
              animation:vg-voice 7.5s linear infinite; }
  .vg-bubble { opacity:0; animation:vg-bub 4.5s ease-in-out var(--d, 0s) infinite; }
  .vg-bub { fill:var(--paper-raised); stroke:var(--ink); stroke-width:.5; }
  .vg-frame { fill:var(--paper-raised); stroke:var(--ink); stroke-width:.7; animation:vg-panel 4.8s ease-in-out var(--d, 0s) infinite; }
  .vg-arrow { fill:none; stroke:var(--rubric); stroke-width:1; stroke-linecap:round; }
  .vg-rain { fill:none; stroke:var(--muted); stroke-width:.8; stroke-dasharray:2 3; animation:vg-rain .9s linear infinite; }
  .vg-lit { fill:var(--paper-raised); stroke:var(--ink); stroke-width:.4; }
  .vg-progress { fill:var(--rubric); transform-box:fill-box; transform-origin:0 50%; animation:vg-progress 4.8s linear infinite; }
  .vg-stampbox { fill:var(--paper-raised); stroke:var(--muted); stroke-width:.6; stroke-dasharray:1 1; }
  .vg-postmark { fill:none; stroke:var(--muted); stroke-width:.6; }
  .vg-snap { opacity:0; transform-box:fill-box; transform-origin:center; animation:vg-snap 5.4s var(--ease-settling) var(--d, 0s) infinite; }
  .vg-spark { opacity:0; transform-box:fill-box; transform-origin:center; animation:vg-spark 5.4s ease-out var(--d, 0s) infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .vg-river { stroke:var(--pigment-lapis); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .vg-snow { stroke:var(--pigment-lapis); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .vg-head { fill:color-mix(in srgb, var(--tan) 32%, var(--paper-raised)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .vg-lit { fill:var(--pigment-ochre); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .vg-penb { fill:var(--pigment-lapis); }
  @keyframes vg-write    { 0% { stroke-dashoffset:44; } 18%, 80% { stroke-dashoffset:0; } 94%, 100% { stroke-dashoffset:44; } }
  @keyframes vg-turn     { 0% { transform:scaleX(1); opacity:0; } 8%, 40% { transform:scaleX(1); opacity:1; } 72% { transform:scaleX(-1); opacity:1; }
                           86%, 100% { transform:scaleX(-1); opacity:0; } }
  @keyframes vg-drop     { 0% { opacity:0; transform:translateY(-18px) rotate(12deg); } 12%, 72% { opacity:1; transform:rotate(var(--r, 0deg)); }
                           86%, 100% { opacity:0; transform:rotate(var(--r, 0deg)); } }
  @keyframes vg-tape     { 0% { opacity:0; transform:scaleX(.2); } 8%, 58% { opacity:1; transform:none; } 72%, 100% { opacity:0; transform:none; } }
  @keyframes vg-flow     { to { stroke-dashoffset:-22; } }
  @keyframes vg-drift    { 0% { transform:translateX(-14px); opacity:0; } 12%, 80% { opacity:1; } 100% { transform:translateX(70px); opacity:0; } }
  @keyframes vg-snow     { 0% { transform:translate(0, 0); opacity:0; } 12% { opacity:1; } 85% { opacity:1; } 100% { transform:translate(4px, 58px); opacity:0; } }
  @keyframes vg-walk     { 0%, 100% { transform:none; } 50% { transform:translateY(-1.2px); } }
  @keyframes vg-hand     { 0% { stroke-dashoffset:60; } 62%, 86% { stroke-dashoffset:0; } 100% { stroke-dashoffset:60; } }
  @keyframes vg-pen      { 0% { transform:translate(-14px, -2px); } 30% { transform:translate(-4px, 0); } 62% { transform:translate(4px, 7px); }
                           86% { transform:translate(4px, 7px); } 100% { transform:translate(-14px, -2px); } }
  @keyframes vg-steam    { 0% { opacity:0; transform:none; } 40% { opacity:.9; } 100% { opacity:0; transform:translateY(-5px); } }
  @keyframes vg-tick     { 0% { stroke-dashoffset:10; } 10%, 78% { stroke-dashoffset:0; } 90%, 100% { stroke-dashoffset:10; } }
  @keyframes vg-clock    { to { transform:rotate(360deg); } }
  @keyframes vg-voice    { from { offset-distance:0%; } to { offset-distance:100%; } }
  @keyframes vg-bub      { 0% { opacity:0; transform:translateY(2px); } 10%, 34% { opacity:1; transform:none; } 46%, 100% { opacity:0; } }
  @keyframes vg-panel    { 0%, 100% { stroke:var(--ink); stroke-width:.7; } 10%, 30% { stroke:var(--rubric); stroke-width:1.6; } 40% { stroke:var(--ink); stroke-width:.7; } }
  @keyframes vg-rain     { to { stroke-dashoffset:-5; } }
  @keyframes vg-progress { from { transform:scaleX(0); } to { transform:scaleX(1); } }
  @keyframes vg-snap     { 0% { opacity:0; transform:scale(1.25); } 8%, 70% { opacity:1; transform:none; } 82%, 100% { opacity:0; transform:none; } }
  @keyframes vg-spark    { 0% { opacity:0; transform:scale(.3); } 8% { opacity:1; transform:scale(1.2); } 22%, 100% { opacity:0; transform:scale(.8); } }
  @media (prefers-reduced-motion:reduce) {
    .vig *, .make-art * { animation:none !important; }
    .vg-write, .vg-hand, .vg-tick { stroke-dashoffset:0; }
    .vg-drop, .vg-tape, .vg-snap, .vg-bubble:first-of-type { opacity:1; }
    .vg-turn { opacity:0; }
  }
  .shape-n { display:block; margin-top:var(--s1); font-size:var(--text-2xs); text-align:center; line-height:1.35; }
  .ask { padding:var(--s4); background:var(--paper-raised); border:1px solid var(--rule); }
  .ask-q { margin:0 0 var(--s3); font-family:var(--font-read); font-style:italic; font-size:var(--text-2xl); line-height:1.3; color:var(--ink); }
  .ask-row { display:flex; flex-wrap:wrap; align-items:center; gap:var(--s2) var(--s4); }
  /* The microphone is pressed, so it is round (D4); listening, it is rubric. */
  .ask-mic { width:auto; display:inline-flex; align-items:center; gap:var(--s2); padding:var(--s2) var(--s4);
             background:var(--ink); color:var(--paper); border:none; font-size:var(--text-base); }
  .ask-mic svg { width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:1.8; stroke-linecap:round; }
  .ask-mic[aria-pressed="true"] { background:var(--rubric); }
  .ask-said { margin:var(--s3) 0 0; font-family:var(--font-read); font-size:var(--text-lg); line-height:1.45; color:var(--ink); }
  .ask-why { margin:var(--s3) 0 0; font-size:var(--text-sm); max-width:60ch; }

  /* HEARING IT TOLD (A72): the bar under a chapter's title, and the voices screen. */
  .narrate { display:flex; flex-wrap:wrap; align-items:center; gap:var(--s2) var(--s4); margin:0 0 var(--s6); }
  .narrate-play { width:auto; display:inline-flex; align-items:center; gap:var(--s2); padding:var(--s2) var(--s4); font-size:var(--text-base); }
  .narrate-play[aria-pressed="true"] { border-color:var(--rubric); color:var(--rubric); }
  .narrate-icon { font-size:.8em; }
  .narrate-who { width:auto; text-align:left; }
  .narrate-ai { flex-basis:100%; margin:0; font-size:var(--text-sm); }
  /* Listen, and while it plays Pause/Resume and Stop with the time beside them: one row that wraps at 380px. */
  .narrate-controls { display:flex; flex-wrap:wrap; align-items:center; gap:var(--s2) var(--s3); flex-basis:100%; }
  .narrate-stop { width:auto; display:inline-flex; align-items:center; gap:var(--s2); padding:var(--s2) var(--s4); font-size:var(--text-base); }
  .narrate-time { margin:0; font-variant-numeric:tabular-nums; }
  .narrate-again { width:auto; text-align:left; }
  .voice-card { width:min(460px, 100%); }
  .voice-list { display:flex; flex-direction:column; gap:var(--s2); margin:var(--s3) 0 var(--s4); max-height:50vh; overflow:auto; }
  /* A scrolling list must not squeeze its rows: each keeps its own height, face, name and note (was overlapping at 380px). */
  .voice-list > .teller-opt { flex:none; }
  .voice-essay { max-width:var(--page-doc); margin-top:var(--s4); }
  .voice-essay p { font-family:var(--font-read); font-size:var(--text-xl); line-height:1.5; color:var(--ink); margin:0 0 var(--s3); }
  .voice-h { font-family:var(--font-read); font-weight:400; font-size:var(--text-2xl); margin:var(--s2) 0 var(--s4); }
  .voice-off { opacity:.6; cursor:not-allowed; }
  .voice-check { display:flex; gap:var(--s3); align-items:flex-start; margin-top:var(--s4); font-family:var(--font-read); font-size:var(--text-lg); line-height:1.4; cursor:pointer; }
  .voice-check input { width:20px; height:20px; flex:none; margin-top:3px; accent-color:var(--ink); }
  .voice-terms { margin:0; padding-left:1.1em; font-family:var(--font-read); font-size:var(--text-lg); line-height:1.5; }
  .voice-terms li { margin-bottom:var(--s2); }
  .voice-full { margin-top:var(--s4); }
  .voice-full .note p { margin:0 0 var(--s2); }
  .voice-draft { margin-left:var(--s2); padding:1px 6px; border:1px solid var(--rubric); color:var(--rubric); font-size:var(--text-2xs); letter-spacing:.12em; text-transform:uppercase; }
  .voice-take { padding:var(--s4) 0; border-top:1px solid var(--rule); }
  .voice-read { font-family:var(--font-read); font-style:italic; font-size:var(--text-xl); line-height:1.5; margin:var(--s2) 0 var(--s3); max-width:var(--page-doc); }

  /* THE PROLOGUE (A72): six lines, one at a time, each fading up somewhere new
     on an otherwise empty page, then the one line that asks for a photograph. */
  .prologue { position:relative; min-height:100vh; min-height:100dvh; overflow:hidden; background:var(--paper); cursor:pointer; }
  .pl-skip { position:absolute; top:calc(var(--s4) + env(safe-area-inset-top, 0px)); right:var(--s4); z-index:2; width:auto; }
  .pl-stage { position:absolute; inset:0; }
  .pl-line { position:absolute; margin:0; max-width:min(30ch, 80vw); color:var(--ink);
             opacity:0; transform:translateY(6px); transition:opacity 1.8s var(--ease-settling), transform 1.8s var(--ease-settling); }
  .pl-line.on { opacity:1; transform:none; }
  .pl-big { font-family:var(--font-read); font-style:italic; font-size:clamp(28px, 4.6vw, 48px); line-height:1.12; max-width:min(18ch, 84vw); }
  .pl-mid { font-family:var(--font-read); font-size:clamp(19px, 2.4vw, 26px); line-height:1.35; }
  .pl-small { font-family:var(--font-annotate); font-size:var(--text-sm); letter-spacing:.16em; text-transform:uppercase; color:var(--muted); }
  .pl-still { position:static; display:flex; flex-direction:column; gap:var(--s6); padding:var(--s8) var(--s6); }
  .pl-still .pl-line { position:static; }
  .pl-end { position:absolute; left:0; right:0; top:42%; display:flex; flex-direction:column; align-items:center; gap:var(--s6);
            text-align:center; animation:arrives 1.6s var(--ease-arriving) both; }
  .pl-still ~ .pl-end { position:static; padding:0 var(--s6) var(--s8); align-items:flex-start; text-align:left; }
  .pl-name { position:absolute; left:50%; bottom:calc(var(--s8) + env(safe-area-inset-bottom, 0px)); transform:translateX(-50%); }
  .pl-name .display { font-size:clamp(22px, 3vw, 30px); color:var(--muted); }

  @media (prefers-reduced-motion:reduce) {
    .ephemera, .eph-sway, .eph-lift, .eph-flutter, .letter-body, .scroll-frame img,
    .hub-tile *, .room-obj *, .ed-obj *, .tour-step * { animation:none !important; }
    .hub-art .dk-unroll { transform:none; } .hub-art .dk-ink-in { opacity:1; }
    .hub-art .ed-paper { transform:none; } .scroll-sheet.rolls .scroll-row { clip-path:none; animation:none; }
    .cal-day.kept, .spread-left { animation:none; }
    .room-leaf { animation:none; opacity:0; }
    .bookcase .case-row > *, .deck-card.dealt, .envelope.ready, .envelope.cracking .seal, .postcard { animation:none; }
    .on-air.playing .on-air-lamp, .face-tile .i-eye, .face-tile .i-mouth { animation:none; }
    .eyes-step:hover, .eyes-step:focus-visible { transform:none; } .mic-add:hover .mic-plus, .mic-add:focus-visible .mic-plus { transform:none; }
  }


  /* ── THE HANDS (A80): words in a hand, drawn stroke by stroke ── */
  .hand-words { display:block; width:100%; height:auto; overflow:visible; }
  .hand-ink path { fill:none; stroke:var(--ink); stroke-width:var(--w, 1.2); stroke-linecap:round; stroke-linejoin:round; }
  .pencil .hand-ink path { stroke:var(--muted); }
  .hand-rule { fill:none; stroke:var(--rule); stroke-width:.6; }
  /* written out once, a stroke at a time, as the words are stuck to a page */
  .hand-words.timed path { stroke-dasharray:var(--l) calc(var(--l) + 4); stroke-dashoffset:calc(var(--l) + 2); }
  .hand-words.timed.writing path { animation:hand-write calc(var(--t) * 1ms) linear calc(var(--d) * 1ms + 300ms) forwards; }
  .hand-words.timed.written path { stroke-dashoffset:0; }
  @keyframes hand-write { to { stroke-dashoffset:0; } }
  /* the pens, line-drawn at rest and in their colours when the hand is chosen */
  .hand-pen :is(path, circle) { fill:var(--paper-raised); stroke:var(--ink); stroke-width:.45; stroke-linejoin:round; }
  .hand-pen .pen-ln { fill:none; }
  .hand-pen :is(.pen-tipm, .pen-lead, .pen-dot) { fill:var(--ink); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .hand-pen .pg { fill:color-mix(in srgb, var(--pg) 78%, var(--paper-raised)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .hand-pen .pen-wood { fill:color-mix(in srgb, var(--pigment-ochre) 30%, var(--paper-raised)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .hand-pen :is(.pen-cap, .pen-cone, .pen-grip, .pen-ferrule) { fill:color-mix(in srgb, var(--muted) 34%, var(--paper-raised)); }
  .words-in { width:100%; min-height:3.4em; resize:vertical; font-family:var(--font-read); font-size:var(--text-xl); line-height:1.35; }
  .hands-k { margin:var(--s4) 0 var(--s2); }
  .hand-list { display:grid; grid-template-columns:1fr; gap:var(--s2); }
  .hand-opt { display:grid; grid-template-columns:minmax(0, 1.3fr) minmax(0, 1fr); align-items:center; gap:var(--s3); padding:var(--s2); text-align:left; }
  .hand-tile { display:block; width:auto; height:auto; padding:0; border:0; box-shadow:none; background:var(--paper-sunk); }
  .hand-tile:is(:hover, :focus-visible, .play) { box-shadow:none; }
  .hand-vig { display:block; width:100%; height:auto; aspect-ratio:4 / 1.25; }
  .hand-say { display:flex; flex-direction:column; gap:var(--s1); min-width:0; }
  .hand-opt:hover .hand-tile { background:color-mix(in srgb, var(--wash) 10%, var(--paper-sunk)); }
  @media (max-width:480px) { .hand-opt { grid-template-columns:1fr; } }
  /* A PAGE'S OWN LINE (A80), beside it on the scrapbook — never over the photograph (D5). */
  .sb-words { width:min(62%, 210px); margin:var(--s3) var(--s2) 0; transform:rotate(var(--a, 0deg)); cursor:default; }
  .sb-words.right { margin-left:auto; }

  /* ── CUTTING A KEEPSAKE (A80; 27 Oct 2026): the outcome first, the hand ways under Adjust ── */
  .cutter { margin:var(--s4) 0 var(--s2); }
  .cut-say { margin:0 0 var(--s2); }
  .cut-stage { position:relative; display:inline-block; max-width:100%; overflow:hidden; touch-action:none; cursor:crosshair; line-height:0; border:1px solid var(--rule); }
  .cut-stage[data-way="corners"] { cursor:default; }
  .cut-pic { display:block; }
  .cut-stage :is(img, .cut-src) { display:block; max-width:100%; max-height:min(56vh, 440px); width:auto; height:auto; user-select:none; -webkit-user-drag:none; }
  .cut-box { position:absolute; border:2px solid var(--rubric); cursor:grab; transition:left .25s var(--ease), top .25s var(--ease), width .35s var(--ease), height .35s var(--ease); }
  .cut-box::after { content:''; position:absolute; inset:-2px; outline:2000px solid color-mix(in srgb, var(--paper) 58%, transparent); pointer-events:none; }
  .cut-box:focus-visible { outline:2px solid var(--ink); outline-offset:2px; }
  /* The traced outline, or the four corners' edge: rubric, because the
     reader is acting; outside it, the frame's own paper wash. */
  .cut-lines { position:absolute; inset:0; width:100%; height:100%; pointer-events:none; }
  .cut-edge { fill:none; stroke:var(--rubric); stroke-width:2; stroke-linejoin:round; stroke-linecap:round; vector-effect:non-scaling-stroke; }
  .cut-wash { fill:color-mix(in srgb, var(--paper) 58%, transparent); stroke:none; }
  /* A corner to drag: a 44px target (it is pressed, so it may be round, D4)
     with a small ring at its centre exactly on the corner. */
  .cut-handle { position:absolute; width:44px; height:44px; min-height:44px; margin:-22px 0 0 -22px; padding:0;
                border:0; border-radius:var(--radius-button); background:transparent; cursor:grab; touch-action:none; z-index:1; }
  .cut-handle::after { content:''; position:absolute; inset:13px; border:2px solid var(--rubric); border-radius:var(--radius-button);
                       background:var(--paper-raised); box-shadow:var(--lift); }
  .cut-handle:focus-visible { outline:2px solid var(--ink); outline-offset:-4px; }
  .cut-handle:active { cursor:grabbing; }
  /* Waiting on the cut: the picture, washed, and the pilcrow (D7). */
  .cut-wait { position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
              background:color-mix(in srgb, var(--paper) 46%, transparent); font-size:56px; line-height:1; }
  /* THE OUTCOME: the keepsake as it will look stuck down, on its backing. */
  .cut-result { display:flex; justify-content:center; align-items:center; padding:var(--s6) var(--s4); max-width:40rem;
                border:1px solid var(--rule); background:var(--paper); min-height:160px; }
  .cut-result .ephemera { position:relative; width:auto; max-width:100%; z-index:auto; cursor:default; }
  .ephemera canvas { display:block; max-width:100%; height:auto; }
  .cut-size, .cut-ways { margin-top:var(--s3); }
  :is(.cut-size, .cut-ways) button[aria-checked="true"] { border-color:var(--rubric); color:var(--rubric); }
  .cut-acts { margin-top:var(--s3); align-items:center; }
  .cut-acts .linkish { width:auto; margin:0; min-height:44px; min-width:44px; padding:var(--s2) 0; }
  .cut-acts .btn-ink:disabled { opacity:.45; cursor:default; }

  /* A KEEPSAKE ON A PAGE is a third of it (27 Oct 2026: at 110px it read
     as a crumb beside the photograph): a share of the page's width, larger
     on a phone where the page is narrow. The tray keeps its small ones. */
  .sb-page { --eph-share:.32; }
  .sb-page .ephemera { width:calc(var(--eph-share) * 100%); }
  @media (max-width:560px) { .sb-page { --eph-share:.44; } }
  @media (min-width:1024px) { .edition-scrapbook .sb-page { --eph-share:.34; } }

  /* ── THE SCRAPBOOK, somebody making it (A80) ── */
  .i-pen-b { fill:none; stroke:var(--ink); stroke-width:1.4; stroke-linecap:round; }
  .hub-art .dk-scrawl { stroke-dasharray:30; stroke-dashoffset:30; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-scrawl { animation:sb-scrawl 2.6s var(--ease-settling) .6s both; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-pen { animation:sb-pen 2.6s cubic-bezier(.45, 0, .55, 1) .6s both; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-reach { animation:sb-reach 2.6s cubic-bezier(.45, 0, .55, 1) .1s both; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-keep { animation:sb-keep 2.6s var(--ease) .1s both; }
  .sb-scene .dk-place { opacity:0; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .sb-scene .dk-place { animation:sb-landed .6s var(--ease-settling) 1.3s both; }
  @keyframes sb-scrawl { to { stroke-dashoffset:0; } }
  @keyframes sb-pen    { 0% { transform:translate(-6px, -1px); } 25% { transform:translate(-2px, 1px); } 50% { transform:translate(2px, -1px); } 75% { transform:translate(6px, 1px); } 100% { transform:translate(8px, 0); } }
  @keyframes sb-reach  { 0% { transform:translate(4px, -6px); } 45%, 60% { transform:translate(10px, 4px); } 100% { transform:translate(2px, -4px); } }
  @keyframes sb-keep   { 0%, 44% { opacity:1; } 52%, 100% { opacity:0; } }
  @keyframes sb-landed { from { opacity:0; transform:translateY(-3px); } to { opacity:1; transform:none; } }

  /* ── FEELINGS, TAKEN APART (A80) ── */
  .feel-row { margin:var(--s4) 0 0; }
  .feel-row-k { display:block; margin:0 0 var(--s2); }
  .feel-chips { display:flex; flex-wrap:wrap; gap:var(--s2); }
  .feel-chip { width:auto; display:inline-flex; align-items:center; gap:var(--s1); min-height:44px; margin:0;
               padding:var(--s1) var(--s3) var(--s1) var(--s2); background:var(--paper-raised); color:var(--ink);
               border:1px solid var(--rule); font-family:var(--font-annotate); font-size:var(--text-sm); letter-spacing:.02em;
               transition:border-color var(--dur) var(--ease), color var(--dur) var(--ease); }
  .feel-chip .glyph { width:20px; height:20px; }
  .feel-chip:hover { border-color:var(--ink); }
  .feel-chip[aria-checked="true"] { border-color:var(--rubric); color:var(--rubric); }
  @media (max-width:640px) {
    .feel-chips { flex-wrap:nowrap; overflow-x:auto; scroll-snap-type:x proximity; margin-inline:calc(var(--pad-x) * -1); padding:0 var(--pad-x) var(--s2); }
    .feel-chip { flex:none; scroll-snap-align:start; }
  }
  .lens-card { margin:var(--s4) 0 0; padding:var(--s4) var(--s4) var(--s4); background:var(--paper-raised); border:1px solid var(--rule); border-left:3px solid var(--ink);
               animation:lens-in .6s var(--ease-settling) both; }
  @keyframes lens-in { from { opacity:0; transform:translateY(4px); } to { opacity:1; transform:none; } }
  .lens-card-h { display:flex; align-items:center; gap:var(--s2); }
  .lens-card-h .eyebrow { margin:0; }
  .lens-g { width:28px; height:28px; color:var(--ink); }
  .lens-also { margin:var(--s2) 0 var(--s4); }
  .lens-rows { display:grid; gap:var(--s3); margin:0; }
  .lens-rows div { display:grid; grid-template-columns:minmax(0, 9.5em) minmax(0, 1fr); gap:var(--s3); }
  .lens-rows dt { padding-top:.4em; font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.12em; text-transform:uppercase; color:var(--muted); }
  .lens-rows dd { margin:0; font-family:var(--font-read); font-size:var(--text-lg); line-height:1.4; color:var(--ink); }
  @media (max-width:560px) { .lens-rows div { grid-template-columns:1fr; gap:var(--s1); } .lens-rows dt { padding:0; } }
  .lens-asks { margin-top:var(--s6); }
  .lens-asks ul { margin:var(--s2) 0 var(--s4); padding-left:1.1em; }
  .lens-asks li, .lens-them { font-family:var(--font-read); font-style:italic; font-size:var(--text-lg); line-height:1.4; color:var(--ink); }
  .lens-asks li { margin:0 0 var(--s1); }
  .lens-them { margin:var(--s2) 0 0; }
  .lens-note-src { margin:var(--s4) 0 0; }
  .lens-care { margin:var(--s4) 0 0; padding:var(--s3) var(--s4); background:var(--paper); border:1px solid var(--rule); font-size:var(--text-base); line-height:1.6; }
  .lens-more { display:inline-block; margin-top:var(--s3); }
  .lens-quote { margin:var(--s6) 0 0; padding:0; }
  .lens-quote blockquote { margin:0; font-family:var(--font-read); font-size:var(--text-xl); line-height:1.38; color:var(--ink); text-wrap:pretty; }
  .lens-quote blockquote::before { content:'\201C'; } .lens-quote blockquote::after { content:'\201D'; }
  .lens-quote figcaption { margin-top:var(--s2); font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.1em; text-transform:uppercase; color:var(--ink); }
  .lens-quote figcaption span { display:block; margin-top:2px; letter-spacing:.03em; text-transform:none; color:var(--muted); }
  .lens-plain { margin:var(--s3) 0 0; font-size:var(--text-base); line-height:1.6; color:var(--ink); }
  .lens-plain b { margin-right:.5em; font-family:var(--font-annotate); font-size:var(--text-2xs); font-weight:400; letter-spacing:.12em; text-transform:uppercase; color:var(--rubric); }

  /* ── THE LENSES (A80) ── */
  .lens-sec { margin:0 0 calc(var(--s8) * 1.5); }
  .lens-sec-n { margin:var(--s1) 0 var(--s4); max-width:56ch; }
  .feel-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(148px, 1fr)); gap:var(--s2); }
  .feel-grid .feel-chip { justify-content:flex-start; width:100%; }
  .lens-about { margin:0 0 var(--s4); }
  .lens-about button[aria-checked="true"] { border-color:var(--rubric); color:var(--rubric); }
  .quote-grid { display:grid; grid-template-columns:1fr; gap:0 var(--s8); }
  @media (min-width:820px) { .quote-grid { grid-template-columns:repeat(2, minmax(0, 1fr)); } }
  .quote-grid .lens-quote { margin:0; padding:var(--s4) 0 var(--s6); border-top:1px solid var(--rule); }
  .sayings { list-style:none; margin:0; padding:0; columns:2 20rem; column-gap:var(--s8); }
  .sayings li { break-inside:avoid; margin:0 0 var(--s4); padding-top:var(--s3); border-top:1px solid var(--rule);
                font-family:var(--font-read); font-size:var(--text-xl); line-height:1.4; color:var(--ink); }

  /* ── THE ACKNOWLEDGMENTS (A80) ── */
  .ack { position:relative; z-index:1; }
  .ack-title { margin:0 0 var(--s2); }
  .ack-lede { margin:0 0 var(--s8); }
  .ack-sec { margin:0 0 var(--s8); }
  .ack-sec > .eyebrow { margin:0 0 var(--s3); }
  .ack .prose { margin:0 0 var(--s4); }
  .ack-pull { margin:var(--s8) 0; padding:var(--s6) 0; border-top:1px solid var(--rule); border-bottom:1px solid var(--rule); text-align:center; }
  .ack-pull blockquote { font-size:calc(var(--text-title) * .62); line-height:1.2; }
  .ack-list { list-style:none; margin:0; padding:0; }
  .ack-list li { margin:0 0 var(--s3); font-family:var(--font-read); font-size:var(--text-xl); line-height:1.45; color:var(--ink); }
  .ack-sign { display:flex; flex-direction:column; align-items:flex-start; gap:var(--s2); margin:var(--s6) 0 0; }
  .ack-hand { width:min(250px, 72%); }
  .ack-more { margin:var(--s8) 0 0; padding-top:var(--s4); border-top:1px solid var(--rule); }

  /* ── WHY IT'S HERE (A80): two people talking, and what the place is for ── */
  .intro { display:grid; grid-template-columns:1fr; gap:var(--s6); align-items:center; margin:var(--s4) 0 var(--s8); padding:var(--s6);
           background:var(--paper-raised); border:1px solid var(--rule); box-shadow:var(--lift); animation:lens-in .7s var(--ease-settling) both; }
  @media (min-width:900px) { .intro { grid-template-columns:minmax(0, 1.05fr) minmax(0, 1fr); align-items:start; } }
  .intro-stage { position:relative; display:block; width:auto; height:auto; padding:0; aspect-ratio:240 / 172; overflow:hidden;
                 background:var(--paper-sunk); border:1px solid var(--rule); box-shadow:none; cursor:default; }
  .intro-stage:is(:hover, :focus-visible, .play) { box-shadow:none; }
  .intro-art { position:absolute; left:0; right:0; bottom:0; width:100%; height:auto; }
  .intro-floor { fill:var(--rule); opacity:.75; }
  .intro-path { fill:none; stroke:var(--rule); stroke-width:6; stroke-linecap:round; }
  .intro-time { stroke:var(--muted); }
  .bub { position:absolute; bottom:60%; max-width:58%; margin:0; padding:var(--s2) var(--s3);
         background:var(--paper-raised); border:1px solid var(--rule); box-shadow:var(--lift);
         font-family:var(--font-read); font-size:var(--text-lg); line-height:1.3; color:var(--ink); text-wrap:pretty;
         opacity:0; transform:translateY(8px) scale(.97); pointer-events:none;
         transition:opacity .55s var(--ease), transform .7s var(--ease-settling); }
  .bub::after { content:''; position:absolute; bottom:-6px; width:10px; height:10px; background:var(--paper-raised);
                border:solid var(--rule); border-width:0 1px 1px 0; transform:rotate(45deg); }
  .bub-left { left:4%; transform-origin:20% 100%; } .bub-left::after { left:24%; }
  .bub-right { right:4%; text-align:left; transform-origin:80% 100%; } .bub-right::after { right:24%; }
  .bub-mid { left:21%; right:21%; max-width:none; } .bub-mid::after { left:calc(50% - 5px); }
  .bub.now { opacity:1; transform:none; }
  .bub.was { opacity:.42; transform:translateY(-38%) scale(.93); }
  .bub.was::after { display:none; }
  .intro-who .i-mouth { transform-box:fill-box; transform-origin:50% 50%; }
  .intro-who.speaking .i-mouth { animation:mouth .28s steps(2, jump-none) infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .intro-who.speaking .pp { animation:talk-nod 1.1s cubic-bezier(.45, 0, .55, 1) infinite; }
  @keyframes mouth { 50% { transform:scaleY(2.6); } }
  @keyframes talk-nod { 0%, 100% { transform:none; } 50% { transform:translateY(-.8px) rotate(-.6deg); } }
  .intro-words .eyebrow { margin:0 0 var(--s2); }
  .intro-h { margin:0 0 var(--s3); font-family:var(--font-read); font-weight:400; font-size:calc(var(--text-title) * .66); line-height:1.15; color:var(--ink); text-wrap:balance; }
  .intro-say { margin:0 0 var(--s4); font-family:var(--font-read); font-size:var(--text-xl); line-height:1.45; color:var(--ink); max-width:var(--measure); }
  .intro-rows { display:grid; gap:var(--s3); margin:0; }
  .intro-rows div { display:grid; grid-template-columns:minmax(0, 10.5em) minmax(0, 1fr); gap:var(--s3); padding-top:var(--s3); border-top:1px solid var(--rule); }
  .intro-rows dt { padding-top:.35em; font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.12em; text-transform:uppercase; color:var(--muted); }
  .intro-rows dd { margin:0; font-size:var(--text-base); line-height:1.6; color:var(--ink); }
  @media (max-width:560px) { .intro-rows div { grid-template-columns:1fr; gap:var(--s1); } .intro { padding:var(--s4); } }
  .intro-after { margin:var(--s4) 0 0; font-family:var(--font-read); font-style:italic; font-size:var(--text-xl); line-height:1.4; color:var(--rubric);
                 opacity:0; transform:translateY(4px); transition:opacity .9s var(--ease), transform .9s var(--ease-settling); }
  .intro.ended .intro-after, .intro.still .intro-after { opacity:1; transform:none; }
  .intro-acts { display:flex; flex-wrap:wrap; align-items:center; gap:var(--s2) var(--s4); margin-top:var(--s4); }
  .intro-acts .btn-quiet { width:auto; min-height:44px; padding:var(--s2) var(--s4); }
  .intro-acts .linkish { width:auto; margin:0; }
  .intro-open { display:block; width:auto; margin:0 0 var(--s6); text-align:left; }
  /* still: the conversation printed whole, under the people */
  .intro.still .intro-stage { aspect-ratio:auto; overflow:visible; padding:var(--s3); }
  .intro.still .intro-art { position:static; }
  .intro.still .bub { position:relative; inset:auto; display:block; max-width:none; margin:var(--s2) 0 0; opacity:1; transform:none; }
  .intro.still .bub-right { margin-left:12%; } .intro.still .bub-left { margin-right:12%; }
  .intro.still .bub::after { display:none; }

  /* ── PIXEL SCENES (A80): a still in relief beneath, the colour that plays above ── */
  .px-scene { position:relative; display:block; line-height:0; }
  .px-scene canvas { display:block; width:100%; height:auto; image-rendering:pixelated; image-rendering:crisp-edges; }
  .px-scene .px-live { position:absolute; inset:0; width:100%; height:100%; opacity:0; transition:opacity .9s var(--ease-settling); }
  .px-scene.on .px-live { opacity:1; }
  .px-scene.px-always .px-live { opacity:1; transition:none; }   /* A81: a scene that always plays has no fade to wait for */


  /* ── ITS SHAPE, SEEN (A80): a wander, a plot line, the good bits ── */
  .vg-route, .vg-arc { fill:none; stroke:var(--rule); stroke-width:1.4; stroke-linecap:round; stroke-linejoin:round; stroke-dasharray:2 2.6; }
  .vg-route-on, .vg-arc-on { fill:none; stroke:var(--ink); stroke-width:1.4; stroke-linecap:round; stroke-linejoin:round;
                             stroke-dasharray:100; stroke-dashoffset:100; animation:vg-draw 6s cubic-bezier(.45, 0, .55, 1) infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) :is(.vg-route-on, .vg-arc-on) { stroke:var(--rubric); }
  .vg-axis { fill:none; stroke:var(--rule); stroke-width:.8; }
  .vg-walker { fill:var(--rubric); offset-rotate:0deg; animation:vg-walk-on 6s cubic-bezier(.45, 0, .55, 1) infinite; }
  .vg-stop, .vg-beat { transform-box:fill-box; transform-origin:50% 100%; opacity:.28; animation:vg-light 6s var(--ease-settling) var(--d, 0s) infinite; }
  .vg-lab { font-family:var(--font-annotate); font-size:4.6px; letter-spacing:.06em; fill:var(--muted); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .vg-lab { fill:var(--ink); }
  .vg-film { fill:var(--ink-pressed); }
  .vg-cell { fill:color-mix(in srgb, var(--paper-raised) 30%, var(--ink-pressed)); }
  .vg-hole { fill:var(--paper-sunk); }
  .vg-lift { transform-box:fill-box; transform-origin:50% 100%; animation:vg-lift 6.6s var(--ease-settling) var(--d, 0s) infinite; }
  @keyframes vg-draw    { 0% { stroke-dashoffset:100; opacity:1; } 80%, 90% { stroke-dashoffset:0; opacity:1; } 100% { stroke-dashoffset:0; opacity:0; } }
  @keyframes vg-walk-on { 0% { offset-distance:0%; opacity:1; } 80%, 90% { offset-distance:100%; opacity:1; } 100% { offset-distance:100%; opacity:0; } }
  @keyframes vg-light   { 0% { opacity:.28; transform:scale(.86); } 5% { opacity:1; transform:scale(1.14); } 10%, 56% { opacity:1; transform:none; } 70%, 100% { opacity:.28; transform:scale(.86); } }
  @keyframes vg-lift    { 0% { transform:none; } 9% { transform:translate(var(--x, 0), -24px) rotate(var(--r, 0deg)) scale(1.32); } 54% { transform:translate(var(--x, 0), -24px) rotate(var(--r, 0deg)) scale(1.32); } 66%, 100% { transform:none; } }

  /* through their eyes, three ways in; and whose voice */
  .vg-pass { animation:vg-pass 4.6s cubic-bezier(.45, 0, .55, 1) infinite; }
  .vg-qcard { fill:var(--paper-raised); stroke:var(--ink); stroke-width:.6; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .vg-qcard { fill:color-mix(in srgb, var(--pigment-ochre) 22%, var(--paper-raised)); }
  .vg-q { font-family:var(--font-read); font-size:9px; fill:var(--rubric); }
  .vg-flap { transform-box:fill-box; transform-origin:50% 0; animation:vg-flap 4.8s var(--ease-settling) infinite; }
  .vg-dot { fill:var(--ink); }
  .vg-arrive { animation:vg-arrive 5.2s var(--ease-settling) infinite; }
  .vg-wave { fill:none; stroke:var(--muted); stroke-width:1; stroke-linecap:round; opacity:0; animation:vg-wave 2.4s ease-in-out var(--d, 0s) infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .vg-wave { stroke:var(--pigment-lapis); }
  .vg-phone { fill:var(--paper-raised); stroke:var(--ink); stroke-width:.7; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .vg-phone { fill:color-mix(in srgb, var(--pigment-lapis) 18%, var(--paper-raised)); }
  .vg-link { fill:none; stroke:var(--rubric); stroke-width:1; stroke-dasharray:3 3; stroke-dashoffset:100; animation:vg-link 3.6s linear infinite; }
  @keyframes vg-pass   { 0%, 12% { transform:none; } 46%, 62% { transform:translate(30px, 1px) rotate(4deg); } 96%, 100% { transform:none; } }
  @keyframes vg-flap   { 0%, 20% { transform:none; } 40%, 80% { transform:scaleY(-1); } 100% { transform:none; } }
  @keyframes vg-arrive { 0% { opacity:0; transform:translate(10px, -26px) rotate(10deg); } 18% { opacity:1; transform:none; } 86% { opacity:1; transform:none; } 100% { opacity:0; transform:none; } }
  @keyframes vg-wave   { 0%, 100% { opacity:0; } 40% { opacity:1; } }
  @keyframes vg-link   { to { stroke-dashoffset:0; } }

  /* ── THROUGH THEIR EYES (A80): three ways in, chosen by the look of them ── */
  .eyes-pick { display:grid; grid-template-columns:1fr; gap:var(--s3); margin:0 0 var(--s6); }
  @media (min-width:720px) { .eyes-pick { grid-template-columns:repeat(3, minmax(0, 1fr)); gap:var(--s4); } }
  .eyes-block { position:relative; display:flex; flex-direction:column; align-items:flex-start; gap:var(--s1); width:auto; height:auto;
                padding:var(--s4); text-align:left; cursor:pointer; transition:transform .7s var(--ease-settling), border-color .4s var(--ease); }
  .eyes-block:is(:hover, :focus-visible) { transform:translateY(-3px); }
  .eyes-block[aria-checked="true"] { border-color:var(--rubric); }
  .eyes-block .make-art { margin:0 0 var(--s2); }
  .eyes-block-t { font-family:var(--font-read); font-size:var(--text-2xl); line-height:1.15; color:var(--ink); }
  .eyes-block-n { font-size:var(--text-sm); line-height:1.5; }
  .eyes-block-c { margin-top:var(--s1); font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.14em; text-transform:uppercase; color:var(--rubric); }
  @media (max-width:719px) {
    .eyes-block { display:grid; grid-template-columns:118px minmax(0, 1fr); column-gap:var(--s3); align-items:center; }
    .eyes-block .make-art { grid-row:1 / span 3; margin:0; }
  }
  .eyes-pick.chosen .eyes-block { padding:var(--s2) var(--s3); }
  @media (min-width:720px) {
    .eyes-pick.chosen .eyes-block { display:grid; grid-template-columns:84px minmax(0, 1fr); column-gap:var(--s3); align-items:center; }
    .eyes-pick.chosen .eyes-block .make-art { grid-row:1 / span 3; margin:0; }
    .eyes-pick.chosen .eyes-block-t { font-size:var(--text-xl); }
  }
  .eyes-pick.chosen .eyes-block-n { display:none; }
  .eyes-pane { animation:lens-in .7s var(--ease-settling) both; }
  .eyes-pane[hidden] { display:none !important; }
  .eyes-pane > .eyes-h { margin-top:0; }
  /* looking through their eyes, five ways (MarginLenses.EYES) */
  .eyes-ways { display:grid; grid-template-columns:repeat(auto-fit, minmax(200px, 1fr)); gap:var(--s3); margin:0 0 var(--s8); padding:0; list-style:none; }
  .eyes-ways li { padding:var(--s3) var(--s4); background:var(--paper-raised); border:1px solid var(--rule); }
  .eyes-ways b { display:block; margin-bottom:var(--s1); font-family:var(--font-annotate); font-size:var(--text-2xs); font-weight:400; letter-spacing:.14em; text-transform:uppercase; color:var(--rubric); }
  .eyes-ways span { font-family:var(--font-read); font-size:var(--text-lg); line-height:1.4; color:var(--ink); }
  .eyes-ways-k { margin:0 0 var(--s3); }
  @media (max-width:639px) {
    .eyes-ways { grid-template-columns:none; grid-auto-flow:column; grid-auto-columns:78%; overflow-x:auto; scroll-snap-type:x mandatory;
                 margin-inline:calc(var(--pad-x) * -1); padding:0 var(--pad-x) var(--s2); }
    .eyes-ways li { scroll-snap-align:start; }
  }
  .round-wide { display:grid; grid-template-columns:1fr; gap:var(--s6); }
  @media (min-width:860px) { .round-wide { grid-template-columns:minmax(0, 1fr) minmax(0, 1fr); align-items:start; } }


  /* ── THE BOOKS OF THE YEAR, FACE OUT (A80) ── */
  #shelf-books-row.season-row { justify-content:flex-start; align-items:flex-start; gap:var(--s6) var(--s8); flex-wrap:wrap; overflow:visible;
                                padding:var(--s6) var(--s4) var(--s2); min-height:0; }
  .sbook-slot { display:flex; flex-direction:column; align-items:center; gap:var(--s3); width:clamp(118px, 13vw, 158px); }
  .sbook { position:relative; display:block; width:100%; height:auto; padding:0; margin:0; background:none; border:0; border-radius:var(--radius-paper);
           cursor:pointer; color:var(--ink); transform-origin:50% 100%;
           transition:transform 1.1s var(--ease-settling), opacity .6s var(--ease); }
  .sbook-cover { position:relative; display:flex; flex-direction:column; gap:6px; padding:8px 8px 10px 12px;
                 background:var(--ink-pressed); border:1px solid var(--ink); box-shadow:var(--lift); }
  .sbook.open .sbook-cover { background:var(--paper-raised); border-color:var(--muted); }
  /* the hinge of the cover, where it is bound to the spine */
  .sbook-cover::before { content:''; position:absolute; left:4px; top:0; bottom:0; width:1px; background:color-mix(in srgb, var(--paper) 22%, transparent); }
  .sbook.open .sbook-cover::before { background:var(--rule); }
  .sbook-plate { border:1px solid color-mix(in srgb, var(--paper) 30%, var(--ink)); }
  .sbook.open .sbook-plate { border-color:var(--rule); }
  .sbook-title { display:block; font-family:var(--font-read); font-size:var(--text-xl); line-height:1.1; color:var(--paper); text-align:center; }
  .sbook-num { display:block; font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.18em; text-transform:uppercase;
               color:color-mix(in srgb, var(--paper) 62%, var(--ink)); text-align:center; }
  .sbook.open :is(.sbook-title) { color:var(--ink); } .sbook.open .sbook-num { color:var(--muted); }
  /* the block of pages, seen past the right edge of the board */
  .sbook-pages { position:absolute; top:3px; bottom:3px; right:-5px; width:5px; background:var(--paper-sunk);
                 border:1px solid var(--rule); border-left:0; }
  .sbook:is(:hover, :focus-visible), .sbook-slot:focus-within .sbook { transform:translateY(-12px) rotate(-1.2deg) scale(1.04); }
  .sbook.lent { opacity:.18; transform:translateY(-12px); }
  .sbook:focus-visible { outline:2px solid var(--rubric); outline-offset:6px; }
  .sbook-list { width:100%; margin:0; padding:0 0 0 1.2em; font-family:var(--font-read); font-size:var(--text-base); line-height:1.35; color:var(--ink);
                opacity:.0; transform:translateY(-6px); transition:opacity .8s var(--ease), transform .9s var(--ease-settling); }
  .sbook-list li { margin:0 0 var(--s1); }
  .sbook-slot:is(:hover, :focus-within) .sbook-list { opacity:1; transform:none; }
  @media (hover:none) { .sbook-list { opacity:.85; transform:none; } }
  @media (max-width:640px) {
    #shelf-books-row.season-row { flex-wrap:nowrap; overflow-x:auto; scroll-snap-type:x mandatory; padding-inline:var(--s3); gap:var(--s6); }
    .sbook-slot { flex:none; width:58vw; max-width:220px; scroll-snap-align:center; }
  }

  /* ── A BOOK, HELD, AND OPENED (A80) ── */
  .held { position:fixed; inset:0; z-index:60; display:flex; align-items:center; justify-content:center;
          padding:max(var(--s6), env(safe-area-inset-top, 0px)) max(var(--s4), env(safe-area-inset-right, 0px)) max(var(--s6), env(safe-area-inset-bottom, 0px)) max(var(--s4), env(safe-area-inset-left, 0px)); }
  .held-scrim { position:absolute; inset:0; background:color-mix(in srgb, var(--ink) 40%, transparent); opacity:0; transition:opacity .6s var(--ease); }
  .held.up .held-scrim { opacity:1; }
  .held-veil { position:absolute; inset:0; background:var(--paper); opacity:0; pointer-events:none; transition:opacity .65s var(--ease); }
  .held.filling .held-veil { opacity:1; }
  .held.gone { pointer-events:none; }
  .held.gone .held-veil { opacity:0; transition-duration:.7s; }
  .held.gone :is(.held-scrim, .held-card) { display:none; }
  .held-card { position:relative; display:grid; grid-template-columns:minmax(0, 15rem) minmax(0, 22rem); gap:var(--s8); align-items:center;
               max-width:100%; max-height:100%; overflow:auto; padding:var(--s8); background:var(--paper); border:1px solid var(--rule); box-shadow:var(--lift);
               opacity:0; transform:translateY(24px) scale(.96); transition:opacity .6s var(--ease), transform .9s var(--ease-settling); }
  .held.up .held-card { opacity:1; transform:none; }
  @media (max-width:640px) {
    .held { align-items:flex-end; padding:0; }
    .held-card { grid-template-columns:1fr; gap:var(--s4); width:100%; padding:var(--s6) var(--s4) calc(var(--s6) + env(safe-area-inset-bottom, 0px)); border-width:1px 0 0;
                 transform:translateY(100%); }
    .held-book { width:min(56vw, 210px); margin:0 auto; }
  }
  .held-book { position:relative; perspective:1200px; transition:transform .7s var(--ease-settling); }
  .held-cover { position:relative; z-index:2; display:flex; flex-direction:column; gap:8px; padding:10px 10px 12px 16px;
                background:var(--ink-pressed); border:1px solid var(--ink); box-shadow:var(--lift);
                transform-origin:0 50%; backface-visibility:hidden; transition:transform 1.1s var(--ease-turning); }
  .held-cover .sbook-title { font-size:var(--text-2xl); }
  .held-inside { position:absolute; inset:0; z-index:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--s2);
                 background:var(--paper-raised); border:1px solid var(--rule); }
  .held-inside-k { font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.2em; text-transform:uppercase; color:var(--rubric); }
  .held-inside-t { font-family:var(--font-read); font-size:var(--text-title); line-height:1; color:var(--ink); }
  .held-inside-orn { color:var(--muted); }
  .held-h { margin:var(--s2) 0 var(--s4); font-family:var(--font-read); font-weight:400; font-size:var(--text-title); line-height:1; }
  .held-list { margin:0 0 var(--s6); padding:0; list-style:none; counter-reset:held; }
  .held-list li { display:flex; justify-content:space-between; gap:var(--s3); padding:var(--s2) 0; border-top:1px solid var(--rule);
                  font-family:var(--font-read); font-size:var(--text-lg); line-height:1.3; }
  .held-list small { flex:none; font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.12em; text-transform:uppercase; color:var(--muted); padding-top:.3em; }
  .held-acts { display:flex; flex-wrap:wrap; align-items:center; gap:var(--s3) var(--s4); }
  .held-acts .btn-ink { width:auto; padding:var(--s3) var(--s8); }
  .held-acts .linkish { width:auto; margin:0; }
  /* opening: the words step back, the cover swings open on its hinge, the
     title page shows; then the page grows until it is the book's page */
  .held.opening .held-words { opacity:0; transition:opacity .4s var(--ease); }
  .held.opening .held-cover { transform:rotateY(-158deg); }
  .held.opening .held-card { background:transparent; border-color:transparent; box-shadow:none; transition:background .5s var(--ease), border-color .5s var(--ease); }
  .held.filling .held-book { transform:scale(1.6); }

  /* ── ONE BOOK, OPENED (A80): a real spread, filling the page ── */
  .spread { min-height:min(74vh, 760px); }
  .spread-left, .spread-right { position:relative; }
  .spread.has-season .spread-left { justify-content:flex-start; }
  .spread-front { display:block; width:min(62%, 220px); margin:0 auto var(--s6); padding:6px; background:var(--paper); border:1px solid var(--rule); box-shadow:var(--lift); }
  .spread-folio { position:absolute; bottom:var(--s4); font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.14em; color:var(--muted); }
  .spread-left .spread-folio { left:50%; } .spread-right .spread-folio { right:var(--s6); }
  .bk-row { animation:bk-rise .9s var(--ease-settling) calc(.5s + var(--i, 0) * .12s) both; }
  @keyframes bk-rise { from { opacity:0; transform:translateY(10px); } to { opacity:1; transform:none; } }

  /* ── SPINES, TAKEN DOWN SLOWLY (A80) ── */
  #lib-shelf .spine { transition:transform 1s var(--ease-settling), box-shadow .6s var(--ease); }
  #lib-shelf .spine:is(:hover, :focus-visible) { transform:translateY(-10px) rotate(0deg) !important; }

  /* ── LATELY, ON A WALL (A80): a picture rail, the frames hung from it on
     their wires, a deep ledge under them with its shadow, and the wainscot
     below; the walls and the wood all from the tokens. ── */
  .lately { position:relative; padding-top:calc(var(--s8) + 6px); border-color:var(--muted); }
  .lately::before { content:''; position:absolute; left:0; right:0; top:var(--s6); height:4px; background:var(--ink-pressed);
                    border-bottom:1px solid color-mix(in srgb, var(--paper) 30%, var(--ink-pressed)); }
  .lately-ledge { height:12px; margin:-3px calc(var(--s4) / -2) var(--s3); border-top:4px solid color-mix(in srgb, var(--paper) 28%, var(--ink-pressed));
                  box-shadow:0 2px 0 color-mix(in srgb, var(--ink) 18%, transparent); }
  .lately::after { content:''; display:block; height:var(--s6); margin:var(--s4) calc(var(--s6) * -1) calc(var(--s4) * -1);
                   background:color-mix(in srgb, var(--paper-sunk) 70%, var(--ink) 6%); border-top:3px double var(--muted); }
  @media (max-width:560px) { .lately::after { margin-inline:calc(var(--s3) * -1); margin-bottom:calc(var(--s3) * -1); } }


  .spread-right { display:flex; flex-direction:column; padding-bottom:calc(var(--s8) * 1.5); }
  .spread-right #bk-rows { flex:1; display:flex; flex-direction:column; }
  @media (min-width:760px) { .spread .bk-row { grid-template-columns:2rem clamp(96px, 10vw, 132px) 1fr; padding:var(--s4) 0; } }
  .bk-first { display:block; margin-top:var(--s2); font-family:var(--font-read); font-style:italic; font-size:var(--text-base); line-height:1.45; color:var(--muted);
              display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
  .bk-end { margin-top:auto; padding-top:var(--s8); animation:bk-rise 1s var(--ease-settling) 1.1s both; }
  .bk-quote { margin:0; padding-top:var(--s4); border-top:1px solid var(--rule); }
  .bk-quote blockquote { font-size:var(--text-lg); }


  /* ── THE PIGEONHOLES, in wood and afternoon light (A80) ── */
  .hub-art .i-sunbeam { fill:color-mix(in srgb, var(--pigment-ochre) 30%, var(--paper-raised)); stroke:none; opacity:0; transition:opacity 1.4s var(--ease) .3s; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-sunbeam { opacity:.42; }
  .hub-art .i-mote { fill:var(--paper-raised); stroke:none; opacity:0; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-mote { animation:dk-mote 4.8s cubic-bezier(.45, 0, .55, 1) var(--d, 0s) infinite; }
  @keyframes dk-mote { 0% { opacity:0; transform:translate(0, 0); } 25% { opacity:.9; } 75% { opacity:.9; } 100% { opacity:0; transform:translate(-4px, 6px); } }
  .hub-art .i-quill { fill:var(--paper-raised); stroke:var(--muted); stroke-width:.4; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-quill { fill:color-mix(in srgb, var(--pigment-lilac) 30%, var(--paper-raised)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-brass { fill:color-mix(in srgb, var(--pigment-ochre) 78%, var(--paper-raised)); }


  /* whose voice (A80): three drawn ways */
  .whose-pick { display:grid; grid-template-columns:1fr; gap:var(--s3); margin-top:var(--s4); }
  @media (min-width:760px) { .whose-pick { grid-template-columns:repeat(3, minmax(0, 1fr)); } }
  .whose-block { position:relative; text-align:left; }
  .whose-c { position:absolute; top:var(--s3); right:var(--s3); font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.14em; text-transform:uppercase; color:var(--rubric); }

  /* the lenses, about the app (A80) */
  .launch-who { display:block; margin-top:var(--s3); font-family:var(--font-annotate); font-size:var(--text-xs); font-style:normal; letter-spacing:.14em; text-transform:uppercase; color:var(--muted); }
  .desk-foot-more { display:flex; flex-wrap:wrap; justify-content:center; gap:var(--s2) var(--s6); margin-top:var(--s2); }
  .desk-foot-more { font-family:var(--font-annotate); font-size:var(--text-xs); color:var(--muted); }
  .desk-foot-more a { font:inherit; letter-spacing:inherit; color:inherit; text-decoration:none; }
  .desk-foot-more a:is(:hover, :focus-visible) { color:var(--rubric); }
  h2.eyebrow { font-weight:400; }
  .reader-lens-end { margin:calc(var(--s8) * 1.5) 0 0; padding-top:var(--s6); border-top:1px solid var(--rule); }
  .reader-lens-end .lens-quote { margin:var(--s3) 0 var(--s4); }
  .wl-way { margin:var(--s3) 0 0; }
  .wl-way b { font-family:var(--font-annotate); font-weight:400; font-size:var(--text-2xs); letter-spacing:.12em; text-transform:uppercase; color:var(--rubric); margin-right:.4em; }
  .wl-way span { font-family:var(--font-read); font-style:italic; font-size:var(--text-lg); color:var(--ink); }
  .ask-feel { width:100%; max-width:40rem; margin:var(--s6) auto; text-align:left; }
  .ask-feel > .note { margin:0 0 var(--s2); }

  /* ═══ A81 ═══════════════════════════════════════════════════════════════ */

  /* ── scroll motion: the parts rise into place (scroll-motion.js) ── */
  .sv { opacity:0; translate:0 12px; transition:opacity .7s var(--ease-settling), translate .8s var(--ease-settling); }
  .sv.sv-in { opacity:1; translate:none; }
  @media (prefers-reduced-motion:reduce) { .sv { opacity:1; translate:none; transition:none; } }

  /* ── why it's here, pictured ── */
  .intro-stage { aspect-ratio:auto; display:flex; flex-direction:column; background:var(--paper-sunk); }
  .intro-stage .intro-px { width:100%; }
  .intro-stage .intro-px canvas { aspect-ratio:192 / 108; }
  .intro-stage .intro-art { position:static; display:block; width:100%; height:auto; aspect-ratio:240 / 135; }
  .intro-beat { min-height:3.6em; margin:0; padding:var(--s3) var(--s4); display:flex; align-items:center;
    font-family:var(--font-read); font-style:italic; font-size:var(--text-xl); line-height:1.35; color:var(--ink);
    background:var(--paper-raised); border-top:1px solid var(--rule); }
  .intro-beat span { display:block; }
  .intro-beat span.in { animation:arrives .9s var(--ease-arriving) both; }
  .intro.still .intro-stage { padding:0; }
  .intro.still .intro-beat { font-size:var(--text-lg); }

  /* ── Through Their Eyes: two ways in, family mode apart ── */
  .eyes-pick.eyes-pick-2 { grid-template-columns:1fr; }
  @media (min-width:640px) { .eyes-pick.eyes-pick-2 { grid-template-columns:repeat(2, minmax(0, 1fr)); } }
  .family-mode { display:grid; grid-template-columns:auto minmax(0, 1fr) auto; align-items:center; gap:var(--s4);
    width:100%; margin:var(--s4) 0 0; padding:var(--s3) var(--s6) var(--s3) var(--s4); text-align:left; cursor:pointer;
    border:1px dashed var(--muted); background:var(--paper); }
  .family-mode[aria-checked="true"] { border-style:solid; border-color:var(--rubric); }
  .family-icon { display:block; width:72px; height:auto; aspect-ratio:64 / 56; overflow:visible; }
  .family-mode-words { display:flex; flex-direction:column; gap:2px; min-width:0; }
  .family-mode-words .eyebrow { margin:0; color:var(--rubric); }
  .family-mode-t { font-family:var(--font-read); font-size:var(--text-xl); line-height:1.25; color:var(--ink); }
  .family-mode-go { font-family:var(--font-annotate); font-size:var(--text-sm); letter-spacing:.08em; color:var(--rubric); }
  @media (max-width:520px) { .family-mode { grid-template-columns:auto minmax(0, 1fr); } .family-mode-go { display:none; } .family-icon { width:54px; } }
  .fam-win { fill:var(--paper-sunk); stroke:var(--muted); stroke-width:.6; transition:fill .6s var(--ease); }
  .fam-who { fill:var(--muted); opacity:0; transition:opacity .6s var(--ease); }
  .fam-smoke { fill:none; stroke:var(--muted); stroke-width:1; stroke-linecap:round; opacity:0; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .fam-win { fill:color-mix(in srgb, var(--pigment-ochre) 62%, var(--paper-raised)); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .fam-who { opacity:.85; fill:var(--ink); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .fam-who2 { animation:fam-nod 2.6s ease-in-out infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .fam-smoke { animation:fam-smoke 3.2s ease-out infinite; }
  @keyframes fam-smoke { 0% { opacity:0; transform:translateY(2px); } 30% { opacity:.7; } 100% { opacity:0; transform:translate(3px, -6px); } }
  @keyframes fam-nod { 50% { transform:translateY(.8px); } }
  .family-pane .family-head { display:grid; grid-template-columns:1fr; gap:var(--s4); margin:0 0 var(--s6); }
  @media (min-width:720px) { .family-pane .family-head { grid-template-columns:auto minmax(0, 1fr); align-items:start; } }
  .family-head-art { display:block; width:auto; padding:var(--s3); }
  .family-head-art .family-icon { width:120px; }
  .family-say { max-width:var(--measure); margin:var(--s2) 0; }
  .family-how { max-width:52ch; }

  .kind-row { display:flex; flex-wrap:wrap; gap:var(--s2); margin:0 0 var(--s2); }
  .kind-chip { display:inline-flex; align-items:center; gap:6px; width:auto; min-height:44px; margin:0; padding:0 var(--s3);
    font-family:var(--font-annotate); font-size:var(--text-sm); letter-spacing:.04em; color:var(--ink);
    background:var(--paper-raised); border:1px solid var(--rule); border-radius:var(--radius-button); cursor:pointer; }
  .kind-chip .glyph { width:18px; height:18px; }
  .kind-chip:hover, .kind-chip:focus-visible { border-color:var(--ink); }
  .kind-chip[aria-checked="true"] { border-color:var(--rubric); color:var(--rubric); background:var(--paper); }
  .kind-say { margin:0 0 var(--s4); max-width:56ch; }
  .deck-tone { display:inline-flex; align-items:center; gap:6px; }
  .deck-tone .glyph { width:16px; height:16px; }
  .deck-n { display:block; margin-top:var(--s3); font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.12em; color:var(--muted); }

  /* the two groups at the foot */
  .eyes-out { display:grid; grid-template-columns:1fr; gap:var(--s6); margin:var(--s8) 0 0; padding-top:var(--s6); border-top:1px solid var(--rule); }
  @media (min-width:960px) { .eyes-out { grid-template-columns:repeat(2, minmax(0, 1fr)); } }
  .out-group { display:flex; flex-direction:column; gap:var(--s3); min-width:0; padding:var(--s4); background:var(--paper-raised); border:1px solid var(--rule); }
  .out-head { display:flex; flex-direction:column; gap:2px; }
  .out-head .eyebrow { margin:0; color:var(--rubric); }
  .out-scene { border:1px solid var(--rule); background:var(--paper-sunk); line-height:0; }
  .out-scene canvas { aspect-ratio:200 / 64; }
  #back-scene canvas { aspect-ratio:200 / 72; }
  .out-list { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; }
  .out-row { display:grid; grid-template-columns:minmax(0, 1fr) auto; gap:2px var(--s3); align-items:baseline; padding:var(--s3) 0; border-top:1px solid var(--rule); }
  .out-row:first-child { border-top:0; }
  .out-who { font-family:var(--font-annotate); font-size:var(--text-xs); letter-spacing:.12em; text-transform:uppercase; color:var(--muted); }
  .out-q { grid-column:1; font-family:var(--font-read); font-size:var(--text-lg); line-height:1.35; color:var(--ink); }
  .out-state { grid-column:1; font-size:var(--text-sm); color:var(--muted); }
  .out-act { grid-column:2; grid-row:1 / span 3; align-self:center; width:auto; margin:0; }
  .out-row.here .out-state { color:var(--rubric); }
  .out-empty { padding:var(--s2) 0 0; }

  /* ── the Acknowledgments, read at a human pace ── */
  .ack-pace { display:flex; flex-wrap:wrap; gap:var(--s4); margin:var(--s3) 0 var(--s6); }
  .ack-pace .linkish { width:auto; margin:0; }
  .ack.paced .ack-b { opacity:0; translate:0 22px; transition:opacity 1.6s var(--ease-settling), translate 1.8s var(--ease-settling); }
  .ack.paced .ack-b.in { opacity:1; translate:none; }
  .ack.waiting .ack-pace { position:sticky; bottom:calc(env(safe-area-inset-bottom, 0px) + var(--s4)); z-index:3; width:max-content; max-width:100%;
    padding:var(--s2) var(--s4); background:var(--paper-raised); border:1px solid var(--rule); box-shadow:var(--lift); }
  .ack.whole .ack-pace { display:none; }
  .ack-q { margin:var(--s8) 0; }
  .ack-signers { display:flex; flex-wrap:wrap; align-items:flex-end; gap:var(--s4) var(--s8); }
  .ack-signer { display:block; width:min(220px, 44vw); }
  .sign { display:block; width:100%; height:auto; overflow:visible; }
  .sign-ink { fill:var(--ink); }
  .sign-hair path { fill:none; stroke:var(--ink); stroke-width:.32; stroke-linecap:round; stroke-linejoin:round; }
  .sign-reveal path { fill:none; stroke:var(--ink); stroke-width:var(--nib); stroke-linecap:round; stroke-linejoin:round;
    stroke-dasharray:var(--l) calc(var(--l) + 6); stroke-dashoffset:calc(var(--l) + 3); }
  mask { mask-type:alpha; }
  .sign.writing .sign-reveal path { animation:hand-write calc(var(--t) * 1ms) linear calc(var(--d) * 1ms + 200ms) forwards; }
  .sign.written .sign-reveal path { stroke-dashoffset:0; }
  .ack-dawn { margin:var(--s8) calc(var(--pad-x) * -.5) 0; }
  .ack-dawn-scene { line-height:0; border:1px solid var(--rule); background:var(--paper-sunk); }
  .ack-dawn-scene canvas { aspect-ratio:240 / 100; }
  .ack-dawn-line { margin:var(--s4) 0 0; font-family:var(--font-read); font-style:italic; font-size:var(--text-2xl); text-align:center; color:var(--ink); }
  .ack-dawn-acts { display:flex; flex-wrap:wrap; justify-content:center; align-items:center; gap:var(--s3) var(--s6); margin:var(--s4) 0 0; }
  .ack.whole .ack-sec, .ack.whole .ack-q { transition:opacity 1.2s var(--ease-settling); }
  .season-air.rising .sp { animation:sp-rise var(--dur) ease-in-out var(--d) infinite; }
  @keyframes sp-rise { 0% { opacity:0; transform:translate(0, 100vh); } 12% { opacity:.65; } 50% { transform:translate(4vw, 55vh) rotate(40deg); }
    88% { opacity:.55; } 100% { opacity:0; transform:translate(-3vw, -10vh) rotate(120deg); } }
  @media (prefers-reduced-motion:reduce) { .ack.paced .ack-b { opacity:1; translate:none; transition:none; } }

  /* ── the Studio: the producer, and the flowers ── */
  .i-pad { fill:var(--paper-sunk); stroke:var(--muted); stroke-width:.3; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-pad .i-pad { animation:dk-pad 1.6s steps(2, jump-none) var(--d) infinite; }
  @keyframes dk-pad { 0%, 100% { fill:var(--paper-sunk); } 50% { fill:var(--pg); } }
  .hub-art .dk-groove { transform-box:fill-box; transform-origin:50% 100%; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .dk-groove { animation:dk-groove .8s ease-in-out infinite; }
  @keyframes dk-groove { 0%, 100% { transform:none; } 50% { transform:translateY(.7px) rotate(-1.2deg); } }

  /* ── making it: the photographs first, a page of its own, a bar at the foot ── */
  @media (min-width:960px) { .make-photos .strip { grid-template-columns:repeat(8, minmax(0, 1fr)); } }
  .make-grid { display:grid; grid-template-columns:minmax(0, 1fr); gap:0 var(--s8); align-items:start; }
  /* minmax(0, …), not 1fr: a bare 1fr track is at least its content's min-content, and the feelings'
     sideways scroller below 960px is one unbroken row, so opening it widened the whole column to ~1500px
     at 380 and clipped every section of the page (QA, 28 Oct 2026). */
  @media (min-width:960px) { .make-grid { grid-template-columns:repeat(2, minmax(0, 1fr)); } .make-grid.scrap { grid-template-columns:minmax(0, 46rem); } }
  .feel-open { display:block; width:auto; margin:var(--s3) 0 0; text-align:left; }
  .feel-row { margin:var(--s3) 0 0; }
  .make-look .look { padding:var(--s3) var(--s4); }
  .look-more { margin:var(--s2) 0 0; }
  .look-more summary { width:auto; display:inline-block; cursor:pointer; }
  .look-more p { max-width:62ch; margin:var(--s2) 0 0; }
  .make-bar { position:sticky; bottom:0; z-index:4; display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:var(--s3) var(--s6);
    margin:var(--s8) calc(var(--pad-x) * -1) 0; padding:var(--s3) var(--pad-x) calc(var(--s3) + env(safe-area-inset-bottom, 0px));
    background:var(--paper); border-top:1px solid var(--rule); }
  .make-bar .make-go { margin:0; }
  .make-sum { margin:0; flex:1 1 18rem; max-width:60ch; }
  @media (max-width:600px) { .make-bar .make-go { width:100%; } }

  .page-cols { display:grid; grid-template-columns:1fr; gap:var(--s6); }
  @media (min-width:860px) { .page-cols { grid-template-columns:minmax(0, .85fr) minmax(0, 1.15fr); align-items:start; } }
  .page-preview { padding:var(--s6) var(--s6) var(--s4); background:var(--paper-sunk); border:1px solid var(--rule); }
  @media (min-width:860px) { .page-preview { position:sticky; top:calc(env(safe-area-inset-top, 0px) + 72px); } }
  .pp-sheet { padding:var(--s6) var(--s4) var(--s4); background:var(--paper-raised); border:1px solid var(--rule); box-shadow:var(--lift); rotate:-.6deg; }
  .pp-mat { margin:0 auto; max-width:300px; transition:padding .35s var(--ease); }
  .pp-mat img { max-height:220px; }
  .pp-well { height:150px !important; display:flex; align-items:center; justify-content:center; }
  .pp-words { max-width:230px; margin:var(--s4) 0 0 auto; rotate:-1.6deg; }
  figure.mat.mat-wide { padding:22px; }
  .page-choices { display:flex; flex-direction:column; gap:var(--s6); min-width:0; }
  .page-choice .eyebrow { display:block; margin:0 0 var(--s2); }
  .hold-row { display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:var(--s2); }
  .hold-opt { display:flex; flex-direction:column; gap:var(--s2); padding:var(--s2); }
  .hold-art { display:block; width:100%; height:auto; aspect-ratio:60 / 44; }
  @media (min-width:960px) { .make-page .hand-list { grid-template-columns:repeat(3, minmax(0, 1fr)); } }
  .make-page .hand-opt { grid-template-columns:1fr; align-items:start; }
  @media (min-width:600px) and (max-width:959px) { .make-page .hand-list { grid-template-columns:repeat(2, minmax(0, 1fr)); } }

  /* ── the books of the year: their own names ── */
  .sbook-title { font-size:var(--text-lg); line-height:1.15; text-wrap:balance; }
  .held-cover .sbook-title { font-size:var(--text-xl); }

  /* ── read the year as: the three drawings, playing ── */
  .hub-art .dk-tear2 { transform-origin:0 0; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .ed-art .dk-tear2 { animation:ed-tear 3.6s var(--ease-settling) .2s infinite; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .ed-art .dk-tear:not(.dk-tear2) { animation:ed-tear 3.6s var(--ease-settling) 1.6s infinite; }
  @keyframes ed-tear { 0% { transform:none; opacity:1; } 12% { transform:translate(3px, -5px) rotate(7deg); opacity:1; }
    55% { transform:translate(26px, 58px) rotate(44deg); opacity:0; } 56%, 100% { transform:none; opacity:0; } }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .ed-art .ed-paper { animation:ed-unroll 4.4s var(--ease-settling) infinite alternate; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .ed-art .dk-roll-down { animation:ed-roll 4.4s var(--ease-settling) infinite alternate; }
  @keyframes ed-unroll { 0%, 8% { transform:scaleY(.3); } 70%, 100% { transform:none; } }
  @keyframes ed-roll { 0%, 8% { transform:none; } 70%, 100% { transform:translateY(82px); } }
  .ed-art .ed-cover { transform-box:fill-box; transform-origin:0% 50%; transition:transform 1.1s var(--ease-settling); }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .ed-art .ed-cover { transform:scaleX(.12) skewY(-8deg); }
  .ed-art .ed-inside { opacity:.0; transition:opacity .8s var(--ease) .3s; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .ed-art .ed-inside { opacity:1; }
  .i-ring { fill:none; stroke:var(--muted); stroke-width:1.4; stroke-linecap:round; }
  :is(.hub-tile, .room-obj, .ed-obj):is(:hover, :focus-visible, .play) .i-ring { stroke:var(--ink); }
  @media (prefers-reduced-motion:reduce) { .ed-art .ed-cover { transition:none; } }

  /* ── the Gazette, as a paper ── */
  .gz-masthead { margin:0 0 var(--s4); padding:0 0 var(--s2); border-bottom:3px double var(--ink); }
  .gz-ears { display:flex; flex-wrap:wrap; justify-content:space-between; gap:var(--s2) var(--s4); padding:0 0 var(--s2); border-bottom:1px solid var(--ink);
    font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.14em; text-transform:uppercase; color:var(--muted); }
  .gz-name-row { display:flex; align-items:center; justify-content:space-between; gap:var(--s4); }
  .gz-name { margin:var(--s2) 0; font-size:calc(var(--text-display) * 1.15); letter-spacing:-.01em; }
  .gz-name-row .ed-head-art { flex:none; width:clamp(110px, 22vw, 200px); }
  .gz-dateline { display:flex; flex-wrap:wrap; justify-content:space-between; gap:var(--s1) var(--s4); padding:var(--s2) 0; border-top:1px solid var(--ink);
    font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.14em; text-transform:uppercase; color:var(--ink); }
  .gz-press { display:block; width:100%; height:18px; margin:var(--s1) 0 0; }
  .gz-press-sheet { fill:var(--paper-raised); stroke:var(--rule); stroke-width:.5; }
  .gz-roller > rect { fill:var(--ink-pressed); }
  .gz-stripes rect { fill:var(--muted); }
  .gz-stripes { transform:translateX(calc(var(--gz-roll, 0px) * -1)); }
  .gz-roller-b .gz-stripes { transform:translateX(var(--gz-roll, 0px)); }
  .gz-nav { position:sticky; top:env(safe-area-inset-top, 0px); z-index:5; display:flex; gap:var(--s1); overflow-x:auto; scrollbar-width:none;
    margin:0 calc(var(--pad-x) * -1) var(--s6); padding:var(--s2) var(--pad-x); background:var(--paper); border-bottom:1px solid var(--rule); }
  .gz-nav-b { flex:none; width:auto; min-height:44px; margin:0; padding:0 var(--s3); background:none; border:0; border-radius:0; border-bottom:2px solid transparent;
    font-family:var(--font-annotate); font-size:var(--text-xs); letter-spacing:.12em; text-transform:uppercase; color:var(--muted); cursor:pointer; }
  .gz-nav-b:hover, .gz-nav-b:focus-visible { color:var(--ink); }
  .gz-nav-b[aria-current="true"] { color:var(--rubric); border-bottom-color:var(--rubric); }
  .gz-sec { margin:0 0 var(--s8); padding:var(--s6) 0 0; border-top:1px solid var(--ink); scroll-margin-top:72px; }
  .gz-sec-head { display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between; gap:var(--s2) var(--s4); margin:0 0 var(--s4); }
  .gz-h { margin:0; font-family:var(--font-read); font-weight:400; font-size:var(--text-title); line-height:1.05; color:var(--ink); }
  .gz-kicker { display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--s3); margin:0 0 var(--s2); }
  .gz-kicker .eyebrow { margin:0; color:var(--rubric); }
  .gz-kind { font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.14em; text-transform:uppercase; color:var(--muted); }
  .gz-q { margin:0 0 var(--s2); font-family:var(--font-read); font-size:calc(var(--text-title) * 1.1); line-height:1.08; color:var(--ink); text-wrap:balance; }
  .gz-q-small { font-size:var(--text-2xl); margin-bottom:var(--s4); }
  .gz-qmark, .gz-amark { margin-right:.35em; font-family:var(--font-annotate); font-size:max(.42em, var(--text-xs)); letter-spacing:.08em; vertical-align:.38em; color:var(--rubric); }
  .gz-qnote { max-width:52ch; margin:0 0 var(--s6); }
  .gz-week-row { display:grid; grid-template-columns:1fr; gap:var(--s4); }
  @media (min-width:820px) { .gz-week-row { grid-template-columns:repeat(2, minmax(0, 1fr)); } }
  .gz-way { display:flex; flex-direction:column; gap:var(--s2); padding:var(--s4); background:var(--paper-raised); border:1px solid var(--rule); }
  .gz-way .eyebrow { margin:0; }
  .gz-way .note { margin:0; }
  .gz-closes { margin:var(--s4) 0 0; font-family:var(--font-annotate); font-size:var(--text-xs); letter-spacing:.12em; text-transform:uppercase; color:var(--rubric); }
  .gz-podium { display:grid; grid-template-columns:1fr; gap:var(--s6); }
  @media (min-width:900px) { .gz-podium { grid-template-columns:minmax(0, 1.25fr) minmax(0, 1fr); align-items:start; } }
  .gz-podium .gz-chosen { display:grid; grid-template-columns:1fr; gap:var(--s4); }
  .gz-story { position:relative; padding:var(--s4); background:var(--paper-raised); border:1px solid var(--rule); }
  .gz-story.gz-lead { padding:var(--s6); border-color:var(--ink); }
  .gz-story.gz-lead .gz-t { font-size:var(--text-title); }
  .gz-flag { display:flex; align-items:center; gap:var(--s2); margin:0 0 var(--s2); font-family:var(--font-annotate); font-size:var(--text-2xs);
    letter-spacing:.14em; text-transform:uppercase; color:var(--rubric); }
  .gz-rib { position:relative; flex:none; display:inline-block; width:16px; height:16px; border-radius:var(--radius-button); background:var(--rubric); }
  .gz-rib::after { content:''; position:absolute; left:3px; top:12px; width:10px; height:9px; background:inherit; clip-path:polygon(0 0, 100% 0, 100% 100%, 50% 65%, 0 100%); }
  .gz-rib-2 { background:var(--ink-pressed); } .gz-rib-3 { background:var(--muted); }
  .gz-won { display:flex; align-items:flex-start; gap:var(--s2); }
  .gz-won .gz-rib { margin-top:2px; }
  .gz-t { margin:0 0 var(--s2); font-family:var(--font-read); font-weight:400; font-size:var(--text-2xl); line-height:1.15; color:var(--ink); }
  .gz-by { margin:var(--s2) 0 0; }
  .gz-desk { margin:var(--s3) 0 0; padding:var(--s2) 0 0; border-top:1px dashed var(--rule); font-family:var(--font-read); font-style:italic; color:var(--ink); }
  .gz-desk span { display:block; font-family:var(--font-annotate); font-style:normal; font-size:var(--text-2xs); letter-spacing:.12em; text-transform:uppercase; color:var(--rubric); }
  .gz-cork { display:grid; grid-template-columns:repeat(auto-fill, minmax(min(100%, 16rem), 1fr)); gap:var(--s6) var(--s4); padding:var(--s6) var(--s4);
    background:var(--paper-sunk); border:1px solid var(--rule); }
  .gz-card { position:relative; padding:var(--s6) var(--s4) var(--s4); background:var(--paper-raised); border:1px solid var(--rule); box-shadow:var(--lift);
    rotate:var(--tilt, 0deg); transition:rotate .4s var(--ease); }
  .gz-card:hover, .gz-card:focus-within { rotate:0deg; }
  .gz-card::before { content:''; position:absolute; left:0; right:0; top:var(--s4); border-top:1px solid color-mix(in srgb, var(--rubric) 45%, transparent); }
  .gz-tack { position:absolute; top:6px; left:50%; width:10px; height:10px; margin-left:-5px; border-radius:var(--radius-button); background:var(--rubric); box-shadow:var(--lift); }
  .gz-card-q { margin:var(--s2) 0 var(--s2); font-size:var(--text-sm); color:var(--muted); }
  .gz-card .gz-t { font-size:var(--text-xl); }
  .gz-card.mine { border-color:var(--rubric); }
  .gz-notes { margin:var(--s3) 0 0; }
  .gz-notes-open { width:auto; margin:0; }
  .gz-notes-in { display:none; margin:var(--s3) 0 0; }
  .gz-notes.open .gz-notes-in { display:block; animation:arrives .5s var(--ease-arriving) both; }
  .gz-notes-list { list-style:none; margin:0 0 var(--s3); padding:0 0 0 var(--s3); border-left:1.5px solid color-mix(in srgb, var(--rubric) 55%, transparent); }
  .gz-note { padding:0 0 var(--s2); }
  .gz-note p { margin:0; font-family:var(--font-read); font-style:italic; font-size:var(--text-lg); color:var(--ink); }
  .gz-note-by { font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.1em; text-transform:uppercase; color:var(--muted); }
  .gz-kind-note { margin:0 0 var(--s2); max-width:48ch; font-family:var(--font-annotate); font-size:var(--text-2xs); line-height:1.6;
    letter-spacing:.1em; text-transform:uppercase; color:var(--rubric); }
  .gz-note-form { display:flex; flex-direction:column; gap:var(--s2); align-items:flex-start; }
  .gz-note-form textarea { width:100%; min-height:3em; resize:vertical; font-family:var(--font-read); font-size:var(--text-lg); }
  .gz-arch-k { margin:var(--s8) 0 var(--s2); }
  .gz-col .gz-ip { display:block; }

  /* ── the desk: today's page, on the way, and the depth behind ── */
  .on-way { margin:var(--s6) 0 0; padding:var(--s4) var(--s6) var(--s4); background:var(--paper-raised); border:1px solid var(--rule); }
  .on-way-head { display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between; gap:var(--s2) var(--s4); margin:0 0 var(--s3); }
  .on-way-head .eyebrow { margin:0; }
  .on-way-scene { line-height:0; border:1px solid var(--rule); background:var(--paper-sunk); }
  .on-way-scene canvas { aspect-ratio:240 / 64; }
  .on-way-list { list-style:none; margin:var(--s3) 0 0; padding:0; }
  .on-way-row { display:grid; grid-template-columns:minmax(0, 9rem) minmax(0, 1fr) auto; gap:var(--s1) var(--s4); align-items:baseline;
    padding:var(--s2) 0; border-top:1px solid var(--rule); }
  .on-way-row:first-child { border-top:0; }
  .on-way-who { font-family:var(--font-annotate); font-size:var(--text-xs); letter-spacing:.1em; text-transform:uppercase; color:var(--ink); }
  .on-way-what { font-family:var(--font-read); font-size:var(--text-lg); color:var(--ink); }
  .on-way-when { grid-column:2; font-size:var(--text-sm); color:var(--muted); }
  .on-way-go { grid-column:3; grid-row:1 / span 2; align-self:center; }
  .on-way-row.here .on-way-when { color:var(--rubric); }
  @media (max-width:560px) { .on-way-row { grid-template-columns:minmax(0, 1fr) auto; } .on-way-what, .on-way-when { grid-column:1; } .on-way-go { grid-column:2; grid-row:1 / span 3; } .on-way { padding:var(--s4); } }
  .on-way-more { display:flex; flex-wrap:wrap; gap:var(--s4); margin:var(--s3) 0 0; }
  .room-depth { pointer-events:none; }
  .room-hill { stroke:none; }
  .room-hill.far { fill:var(--paper-sunk); opacity:.55; }
  .room-hill.mid { fill:var(--rule); opacity:.42; }
  .room-far { transform:translateY(calc(var(--home-sy, 0) * .1px)); }
  .room-mid { transform:translateY(calc(var(--home-sy, 0) * .05px)); }
  .room-mist { fill:var(--paper-raised); opacity:.55; animation:room-mist calc(48s + var(--i) * 9s) ease-in-out infinite alternate; }
  @keyframes room-mist { from { transform:translateX(-30px); } to { transform:translateX(30px); } }
  .room-bird path { fill:none; stroke:var(--muted); stroke-width:.8; stroke-linecap:round; }
  .room-bird { animation:room-bird calc(70s + var(--i) * 25s) linear calc(var(--i) * -30s) infinite; }
  @keyframes room-bird { from { transform:translateX(-40px); } to { transform:translateX(620px); } }
  @media (prefers-reduced-motion:reduce) { .room-mist, .room-bird { animation:none; } .room-far, .room-mid { transform:none; } }

  /* ── signing in: a borrower's card ── */
  .pad.signin { max-width:calc(62rem + 2 * var(--pad-x)); }
  .signin-card { display:grid; grid-template-columns:1fr; gap:var(--s6); padding:var(--s6); background:var(--paper-raised); border:1px solid var(--rule); box-shadow:var(--lift); }
  @media (min-width:860px) { .signin-card { grid-template-columns:minmax(0, .9fr) minmax(0, 1.1fr); gap:var(--s8); padding:var(--s8); } }
  .signin-side { display:flex; flex-direction:column; gap:var(--s2); min-width:0; }
  .signin-h { margin:var(--s2) 0 0; }
  .signin-say { margin:0; max-width:40ch; }
  .lib-card-art { display:block; width:100%; max-width:360px; height:auto; margin:var(--s4) 0 0; aspect-ratio:200 / 132; overflow:visible; }
  .lc-h { font-family:var(--font-annotate); font-size:5px; letter-spacing:.14em; fill:var(--ink); }
  .lc-k { font-family:var(--font-annotate); font-size:4px; letter-spacing:.14em; fill:var(--muted); }
  .lc-date { font-family:var(--font-annotate); font-size:4.6px; letter-spacing:.08em; fill:var(--rubric); }
  .lc-pk { font-family:var(--font-annotate); font-size:4.2px; letter-spacing:.14em; fill:var(--ink); opacity:.6; }
  .lc-rule { fill:none; stroke:var(--ink); stroke-width:.6; }
  .lc-line { fill:none; stroke:var(--rule); stroke-width:.5; }
  .lc-ring { fill:none; stroke:var(--rubric); stroke-width:1.1; }
  .lc-st { font-family:var(--font-annotate); font-size:3.6px; letter-spacing:.06em; fill:var(--rubric); }
  .lc-pocket { fill:var(--paper-sunk); stroke:var(--muted); stroke-width:.6; }
  .lc-pocket-lip { fill:var(--rule); stroke:var(--muted); stroke-width:.6; }
  .lib-card-art .lc-card { animation:lc-rise 1.1s var(--ease-settling) .2s both; }
  .lib-card-art .lc-date { animation:arrives .4s var(--ease-arriving) calc(.9s + var(--i) * .18s) both; }
  .lib-card-art .lc-stamp { transform-box:fill-box; transform-origin:center; animation:lc-stamp .5s cubic-bezier(.3, 1.5, .5, 1) 1.9s both; }
  @keyframes lc-rise { from { transform:translateY(34px); } to { transform:none; } }
  @keyframes lc-stamp { from { opacity:0; transform:scale(1.6); } to { opacity:.92; transform:none; } }
  @media (prefers-reduced-motion:reduce) { .lib-card-art * { animation:none !important; } }
  .signin-form { display:flex; flex-direction:column; gap:var(--s4); min-width:0; }
  .signin-group { display:flex; flex-direction:column; gap:var(--s2); }
  .signin-group > .eyebrow { margin:0; }
  .signin-doors { display:grid; grid-template-columns:1fr; gap:var(--s2); }
  .signin-form .rule-or span { font-size:var(--text-xs); }
  .signin-door { display:flex; align-items:center; justify-content:center; gap:9px; margin:0; }
  .signin-lines { padding:var(--s4); background:var(--paper); border:1px solid var(--rule); }
  .signin-lines .eyebrow { margin:var(--s2) 0 0; }
  .signin-lines .eyebrow:first-child { margin-top:0; }
  .signin-msg { min-height:1.6em; margin:var(--s1) 0 0; }
  .signin-alt { width:auto; margin:0; align-self:flex-start; }
  .signin-new { padding-top:var(--s4); border-top:1px solid var(--rule); }
  .signin-new-row { display:flex; flex-wrap:wrap; align-items:center; gap:var(--s2) var(--s4); }
  .signin-new-row > * { width:auto; margin:0; }

  /* ══ A82 ═══════════════════════════════════════════════════════════════
     A GLOSS: the sentence under the main thing — a page's lede, a quote's
     plain reading, what a choice is for — said in the reading face's
     italic. It was set in the annotating mono, which is for labels and
     status lines; an explanation is read (D2), so it is set to be read. */
  .gloss { font-family:var(--font-read); font-style:italic; font-size:var(--text-xl); line-height:1.42; letter-spacing:0;
           color:var(--muted); text-wrap:pretty; }
  h1.display + p.note:not([id]) { font-family:var(--font-read); font-style:italic; font-size:var(--text-xl); line-height:1.42;
                                  letter-spacing:0; color:var(--muted); text-wrap:pretty; }
  .lens-plain { font-family:var(--font-read); font-style:italic; font-size:var(--text-lg); line-height:1.45; }
  .lens-plain b { font-style:normal; }
  .voice-note.gloss, .hear-cell .gloss { font-size:var(--text-lg); line-height:1.38; }
  .hear-cell .gloss { margin:var(--s1) 0 0; }
  /* the same for every place's "why it's here" rows, the Gazette's Inkling
     and the question over a pinned card: they were the smallest type on
     their pages, and the most worth reading */
  .intro-rows dd { font-style:italic; font-size:var(--text-lg); line-height:1.4; }
  .intro-rows div { grid-template-columns:minmax(0, 9em) minmax(0, 1fr); }
  .gz-desk { font-size:var(--text-lg); line-height:1.4; }
  .gz-desk span { margin:0 0 2px; color:var(--rubric); }
  .gz-card-q { font-style:italic; font-size:var(--text-base); }

  /* ── THE ALMANAC on the desk: today's leaf, held by its rings, the next
     leaf's edge showing under it so it reads as a pad on the desk rather
     than a box in the air ── */
  .alm { position:relative; margin:var(--s4) 0 var(--s8); padding:0; }
  .alm::before { content:''; position:absolute; left:4px; right:-4px; top:6px; bottom:-5px; background:var(--paper-sunk); border:1px solid var(--rule); }
  .alm-rings { position:absolute; z-index:2; top:-9px; left:var(--s6); right:var(--s6); display:flex; justify-content:space-between; pointer-events:none; }
  .alm-rings i { display:block; width:7px; height:20px; border:2px solid var(--ink-pressed); border-radius:var(--radius-button); }
  .alm-rings i:nth-child(n+9) { display:none; }
  @media (min-width:720px) { .alm-rings i:nth-child(n+9) { display:block; } }
  .alm-leaf { position:relative; padding:var(--s8) var(--s4) var(--s4); background:var(--paper-raised); border:1px solid var(--rule); box-shadow:var(--lift); }
  @media (min-width:640px) { .alm-leaf { padding:var(--s8) var(--s6) var(--s6); } }
  .alm-strip { display:flex; flex-wrap:wrap; justify-content:space-between; gap:var(--s1) var(--s4); padding:0 0 var(--s2); border-bottom:1px solid var(--ink);
               font-family:var(--font-annotate); font-size:var(--text-xs); letter-spacing:.16em; text-transform:uppercase; color:var(--muted); }
  .home-head .alm-head { margin:var(--s4) 0 var(--s1); text-wrap:balance; }
  .alm-hello { margin:0 0 var(--s6); }
  .alm-grid { display:grid; gap:var(--s6); grid-template-columns:minmax(0, 1fr); grid-template-areas:'q' 'win' 'says';
              padding:var(--s6) 0 0; border-top:1px solid var(--rule); }
  @media (min-width:640px) { .alm-grid { grid-template-columns:minmax(0, .8fr) minmax(0, 1.2fr); grid-template-areas:'win q' 'says says'; } }
  @media (min-width:1000px) { .alm-grid { grid-template-columns:minmax(0, .85fr) minmax(0, 1.25fr) minmax(0, 1fr); grid-template-areas:'win q says'; } }
  .alm-window { grid-area:win; margin:0; }
  .alm-pic { display:block; line-height:0; border:1px solid var(--rule); }
  .alm-pic canvas { aspect-ratio:96 / 60; }
  .alm-window figcaption { margin-top:var(--s2); font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.1em; text-transform:uppercase; color:var(--muted); }
  .alm-q { grid-area:q; }
  .alm-q .eyebrow { margin:0 0 var(--s2); color:var(--rubric); }
  .alm-qq { margin:0 0 var(--s2); font-family:var(--font-read); font-size:clamp(26px, 3vw, 36px); line-height:1.1; color:var(--ink); text-wrap:balance; }
  .alm-why { margin:0 0 var(--s4); font-size:var(--text-lg); }
  .alm-acts { display:flex; flex-wrap:wrap; gap:var(--s2) var(--s3); }
  .alm-acts > * { width:auto; margin:0; }
  .alm-says { grid-area:says; display:flex; flex-direction:column; gap:var(--s4); }
  @media (min-width:640px) and (max-width:999px) { .alm-says { display:grid; grid-template-columns:minmax(0, 1fr) minmax(0, 1.5fr); align-items:start; gap:var(--s6); } }
  .alm-moon { display:flex; gap:var(--s3); align-items:center; }
  .alm-moon-pic { flex:none; width:clamp(76px, 8vw, 96px); line-height:0; border:1px solid var(--rule); }
  .alm-moon-pic canvas { aspect-ratio:48 / 40; }
  .alm-moon .eyebrow { margin:0 0 2px; }
  .alm-moon-n { display:block; font-family:var(--font-read); font-size:var(--text-2xl); line-height:1.1; color:var(--ink); }
  .alm-moon-l { display:block; font-size:var(--text-lg); line-height:1.3; }
  .alm-dl { margin:0; display:flex; flex-direction:column; }
  .alm-dl > div { display:grid; grid-template-columns:6.6em minmax(0, 1fr); gap:var(--s3); padding:var(--s2) 0; border-top:1px dashed var(--rule); }
  .alm-dl dt { padding-top:.3em; font-family:var(--font-annotate); font-size:var(--text-2xs); letter-spacing:.12em; text-transform:uppercase; color:var(--rubric); }
  .alm-dl dd { margin:0; font-family:var(--font-read); font-style:italic; font-size:var(--text-lg); line-height:1.35; color:var(--ink); }
  .alm-dl dd::first-letter { text-transform:uppercase; }
  /* a page of their own, at the foot of the leaf */
  .alm-mem { display:grid; grid-template-columns:minmax(0, 1fr); gap:var(--s3) var(--s6); align-items:center; margin:var(--s6) 0 0; padding:var(--s4) 0 0; border-top:1px solid var(--ink); }
  @media (min-width:640px) { .alm-mem:has(.recall-pin) { grid-template-columns:minmax(0, 1fr) clamp(120px, 20vw, 190px); } .alm-mem-k { grid-column:1 / -1; } }
  .alm-mem-k { margin:0; color:var(--rubric); }
  @media (max-width:639px) { .alm-window { max-width:300px; } .alm-mem .recall-pin { justify-self:end; width:min(64%, 220px); } }
  .alm-mem .recall { position:relative; margin:0; max-width:none; padding:var(--s3) var(--s4) var(--s3) calc(var(--s6) + 10px);
                     border-left:0; background:var(--paper); border:1px solid var(--rule); transform:rotate(-.4deg); transition:transform .6s var(--ease-settling); }
  .alm-mem .recall::before { content:''; position:absolute; top:0; bottom:0; left:var(--s6); border-left:1.5px solid var(--rubric); opacity:.7; }
  .alm-mem .recall-when { padding-bottom:var(--s2); border-bottom:1px solid var(--rule); }
  .alm-mem .recall:is(:hover, :focus-visible) { transform:translateY(-2px) rotate(-.4deg); }
  .alm-mem:hover .recall-photo { transform:rotate(0); }

  /* ── THE STUDIO'S FLOWERS: a note from one of the makers, folding away ── */
  .fl-from { margin:0; color:var(--muted); }
  .flowers { margin:var(--s8) 0 0; padding:var(--s3) var(--s4); background:var(--paper-raised); border:1px solid var(--rule); overflow:hidden; }
  @media (min-width:640px) { .flowers { padding:var(--s4) var(--s8); } .flowers[open] { padding-bottom:var(--s6); } }
  .fl-sum { display:flex; align-items:center; gap:var(--s4); min-height:44px; cursor:pointer; list-style:none; }
  .fl-sum::-webkit-details-marker { display:none; }
  .fl-sum:focus-visible { outline:2px solid var(--rubric); outline-offset:4px; }
  .fl-sum-pic { flex:none; width:40px; line-height:0; }
  .fl-sum-pic canvas { aspect-ratio:44 / 48; }
  .fl-sum-words { flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:2px; }
  .fl-sum-words .eyebrow { margin:0; color:var(--rubric); }
  .fl-title { margin:0; font-family:var(--font-read); font-weight:400; font-size:clamp(24px, 3.4vw, 36px); line-height:1.08; color:var(--ink); text-wrap:balance; }
  .flowers[open] .fl-title { font-size:var(--text-title); }
  .fl-toggle { flex:none; display:flex; align-items:center; gap:var(--s2); font-family:var(--font-annotate); font-size:var(--text-xs);
               letter-spacing:.12em; text-transform:uppercase; color:var(--rubric); }
  .fl-chev { display:inline-block; font-size:var(--text-xl); line-height:1; transform:rotate(90deg); transition:transform .3s var(--ease); }
  .flowers[open] .fl-chev { transform:rotate(-90deg); }
  .flowers[open] .fl-when-shut, .flowers:not([open]) .fl-when-open { display:none; }
  @media (max-width:479px) { .fl-toggle > span:not(.fl-chev) { display:none; } }
  .fl-body { display:flex; flex-direction:column; gap:var(--s6); margin:var(--s4) 0 0; padding:var(--s6) 0 0; border-top:1px solid var(--rule); }
  .flowers[open] .fl-body { animation:arrives .6s var(--ease-arriving) both; }
  .fl-cols { display:grid; grid-template-columns:minmax(0, 1fr); gap:var(--s6); }
  @media (min-width:860px) { .fl-cols { grid-template-columns:minmax(0, 1fr) minmax(0, 1fr); gap:var(--s8); align-items:start; } }
  .fl-note p { margin:0 0 var(--s4); max-width:60ch; font-family:var(--font-read); font-size:var(--text-xl); line-height:1.55; color:var(--ink); }
  .fl-note p:last-child { margin-bottom:0; }
  .fl-note .fl-lede { font-size:var(--text-2xl); line-height:1.42; }
  .fl-song { display:flex; flex-direction:column; gap:var(--s4); }
  .fl-comes { margin:0; max-width:52ch; }
  .flowers .flowers-q { margin:0; }
  .flowers .flowers-q blockquote { font-size:clamp(28px, 3.6vw, 42px); line-height:1.08; }
  .fl-ask { margin:0; max-width:52ch; padding:var(--s1) 0 var(--s1) var(--s4); border-left:2px solid var(--rubric);
            font-family:var(--font-read); font-size:var(--text-2xl); line-height:1.36; color:var(--ink); text-wrap:pretty; }
  .fl-keep { margin:0; max-width:56ch; font-family:var(--font-read); font-size:var(--text-xl); line-height:1.55; color:var(--ink); }
  .fl-earth { margin:var(--s2) calc(var(--s4) * -1) 0; }
  @media (min-width:640px) { .fl-earth { margin:var(--s2) calc(var(--s8) * -1) 0; } }
  .fl-earth-pic { display:block; line-height:0; border-block:1px solid var(--ink); }
  .fl-earth-pic canvas { aspect-ratio:240 / 100; }
  .fl-earth figcaption { display:flex; justify-content:center; padding:var(--s6) var(--s4) 0; text-align:center; }
  .fl-rock { margin:0; max-width:24ch; font-family:var(--font-read); font-size:clamp(26px, 3.6vw, 40px); line-height:1.12; color:var(--ink); text-wrap:balance; }
  .fl-signed { display:flex; flex-direction:column; align-items:center; gap:var(--s2); text-align:center; }
  .fl-sign { margin:0; max-width:44ch; font-size:var(--text-lg); }

  /* ── THE GAZETTE, moving ── */
  .gz-round { margin:var(--s2) 0 0; line-height:0; border:1px solid var(--ink); }
  .gz-round canvas { aspect-ratio:320 / 48; }
  @media (max-width:639px) { .gz-round canvas { aspect-ratio:170 / 48; object-fit:cover; } }  /* the middle of the street, big enough to see */
  .gazette .gz-name { animation:gz-ink 1.3s var(--ease) .1s both; }
  .gz-nav-b[aria-current="true"] { border-bottom-color:transparent; }
  .gz-nav-ink { position:absolute; left:0; bottom:var(--s2); width:0; height:2px; background:var(--rubric); pointer-events:none;
                transition:left .45s var(--ease), width .45s var(--ease); }
  .gz-w { display:inline-block; }
  .gz-week .gz-set .gz-w { animation:gz-set .55s var(--ease) both; animation-delay:calc(.35s + var(--k, 0) * 90ms); }
  .gz-sec.sv:not(.sv-in) .gz-q-small .gz-w { opacity:0; translate:0 -.3em; }
  .gz-sec.sv .gz-q-small .gz-w { transition:opacity .4s var(--ease), translate .5s var(--ease); }
  .gz-sec.sv-in .gz-q-small .gz-w { transition-delay:calc(.15s + var(--k, 0) * 70ms); }
  .gz-clock { color:var(--muted); }
  .gz-rib { transform-origin:50% 0; }
  .gz-flag { transform-origin:0 50%; }
  .gz-story.sv-in .gz-rib { animation:gz-swing 1.8s var(--ease-settling) .2s both; }
  .gz-story.sv-in .gz-flag { animation:gz-stamp .5s var(--ease) .1s both; }
  .gz-card.sv:not(.sv-in) { translate:0 -18px; }
  .gz-card.sv { transition:opacity .5s var(--ease-settling), translate .7s var(--ease-settling), rotate .6s var(--ease-settling); transition-delay:calc(var(--n, 0) * 90ms); }
  .gz-card.sv-in .gz-tack { animation:gz-tack .45s var(--ease) calc(.3s + var(--n, 0) * 90ms) both; }
  .gz-col.sv:not(.sv-in) { translate:24px 0; }
  .gz-col.sv { transition-delay:calc(var(--n, 0) * 110ms); }
  @keyframes gz-ink   { from { clip-path:inset(0 100% 0 0); } to { clip-path:inset(0 0 0 0); } }
  @keyframes gz-set   { from { opacity:0; transform:translateY(-.35em) scale(1.06); } to { opacity:1; transform:none; } }
  @keyframes gz-swing { 0% { transform:rotate(12deg); } 35% { transform:rotate(-6deg); } 65% { transform:rotate(2deg); } 100% { transform:none; } }
  @keyframes gz-stamp { from { opacity:0; transform:scale(1.4) rotate(-3deg); } to { opacity:1; transform:none; } }
  @keyframes gz-tack  { from { opacity:0; transform:scale(2.2); } to { opacity:1; transform:none; } }
  @media (prefers-reduced-motion:reduce) {
    .gazette .gz-name, .gz-week .gz-set .gz-w, .gz-story .gz-rib, .gz-story .gz-flag, .gz-card .gz-tack { animation:none; }
    .gz-nav-ink { transition:none; }
  }

  /* ── the essay: a thought followed where it goes ── */
  .vg-back { transform-origin:40px 20px; animation:vg-back 6s linear infinite; }
  .vg-q { font-family:var(--font-read); font-size:9px; fill:var(--rubric); }
  @keyframes vg-back { to { transform:rotate(-360deg); } }

}

@layer utilities {
  /* ── accessibility furniture ──
     Visually hidden but still announced. Not display:none, which removes it
     from the accessibility tree along with everything else. */
  .visually-hidden {
    position:absolute; width:1px; height:1px; margin:-1px; padding:0;
    overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0;
  }
  /* Off-screen until focused, then it lands on the paper like anything else. */
  .skip-link {
    position:absolute; left:var(--s2); top:-100px; z-index:100;
    background:var(--paper-raised); color:var(--ink);
    border:1px solid var(--ink); border-radius:var(--radius-paper);
    font-family:var(--font-annotate); font-size:var(--text-base);
    padding:var(--s2) var(--s3); transition:top var(--dur) var(--ease);
  }
  .skip-link:focus { top:var(--s2); }
  #screen:focus { outline:none; }   /* focus moves here on route change; the heading carries it */

  /* ═══════════════════ framed preview — mockups only, never the app ═════════
     The one literal left below is the gallery's own backdrop, which is deliberately
     NOT paper: it is the desk the phone sits on, and a token for it would be a
     sixth colour in a palette of five. It is preview scaffolding the README
     already lists for deletion before production — see DESIGN.md open item 5.
     The two greys that used to sit here were just --muted written out longhand,
     twice, and are now --muted. */
  body.framed { background:#E4DBCB; display:flex; flex-direction:column;
                align-items:center; gap:20px; padding:34px 20px 56px; min-height:100vh; }
  body.framed .canvas-head { display:flex; align-items:baseline; gap:var(--s3); color:var(--muted); }
  body.framed .canvas-head .wordmark { font-family:var(--font-read); font-style:italic;
                                       font-size:24px; color:var(--ink); }
  body.framed .canvas-head .canvas-label { font-family:var(--font-annotate); font-size:var(--text-sm);
                                           letter-spacing:.22em; text-transform:uppercase; }
  body.framed .phone { width:414px; max-width:100%; background:var(--ink);
                       border-radius:46px; padding:11px; box-shadow:0 18px 50px rgba(34,29,21,.28); }
  body.framed .screen { position:relative; width:100%; height:812px; background:var(--paper);
                        border-radius:36px; overflow:hidden; display:flex; flex-direction:column; }
  body.framed .notch { position:absolute; top:0; left:50%; transform:translateX(-50%);
                       width:150px; height:26px; background:var(--ink);
                       border-radius:0 0 var(--s4) var(--s4); z-index:20; }
  body.framed .head { padding:20px 22px 11px; }
  body.framed .pad { max-width:none; margin:0; padding:30px 26px 40px; }
  body.framed .home-indicator { flex:none; height:26px; display:grid; place-items:center;
                                background:var(--paper); }
  body.framed .home-indicator span { width:120px; height:var(--s1); border-radius:2px;
                                     background:var(--ink); opacity:.5; }
  .home-indicator { display:none; }

  /* Desktop gallery — a page of paper, no chassis. */
  body.desk { background:var(--paper); }
  body.desk .gallery-label { font-family:var(--font-annotate); font-size:var(--text-sm);
    letter-spacing:.22em; text-transform:uppercase; color:var(--muted);
    padding:20px 48px 0; }

  .canvas-notes { max-width:660px; margin:28px auto 0; padding:0 var(--s6);
                  font-family:var(--font-annotate); font-size:var(--text-base);
                  line-height:1.75; color:var(--muted); }
  .canvas-notes b { color:var(--rubric); font-weight:400; }
  .canvas-notes ul { margin:6px 0 0; padding-left:var(--s4); }
  body.framed .canvas-notes { max-width:414px; margin-top:0; }
}

/* ── the tally ───────────────────────────────────────────────────────────────
   Three counts a reader already owns, between two hairlines.

   On the contents it says what the volume IS — a list of chapters that never
   mentioned the thing it was a list OF is most of why that screen read as
   empty. On the shelf it says how THICK the thing is: an offer of three
   bindings, with no indication of how much is being bound, asks somebody to
   choose a form for a quantity they cannot see.

   One class for both, because two screens showing the same three facts in two
   shapes is two tallies, and the second one drifts. */
.tally    { display:flex; align-items:stretch;
            border-top:1px solid var(--rule); border-bottom:1px solid var(--rule) }
.tally-f  { flex:1; text-align:center; padding:13px 0 }
/* The divider is a border on the neighbour, not a spacer element — an empty
   div between facts is furniture a screen reader has to walk past. */
.tally-f + .tally-f { border-left:1px solid var(--rule) }
.tally-v  { display:block; font-family:var(--font-read); font-size:21px; color:var(--ink) }
.tally-l  { display:block; margin-top:3px; font-family:var(--font-annotate);
            font-size:var(--text-2xs); letter-spacing:.12em;
            text-transform:uppercase; color:var(--muted) }

/* ── a bound book, seen edge-on ───────────────────────────────────────────────
   The phone drew its editions as bound books — head and tail bands, a title
   panel, raised cords, a board edge, the block of pages showing past the
   boards — and the web drew a coloured rectangle with the title turned
   sideways. Three screens' worth: the library's volumes, the shelf's editions,
   and a volume's books.

   Every mark here is something a book HAS, drawn in tokens. No image, no
   gradient, nothing D12 refuses: the bands are rules, the panel is an inset
   field, the fore-edge is a paper-sunk sliver.

   Sized by two custom properties so one class serves a volume, an edition and
   a book: --sp-w and --sp-h. --sp-s scales the furniture inside, so a tablet
   gets a bigger BOOK rather than a bigger box with the same small details. */
.spine {
  position:relative; flex:0 0 auto; cursor:pointer;
  width:var(--sp-w); height:var(--sp-h);
  display:flex; align-items:stretch;
  background:var(--paper-raised); border:1px solid var(--rule);
  /* EXPLICIT, because the bands and cords are drawn in currentColor and this
     is an anchor — which inherits the rubric that links are set in, so every
     band on a light spine came out pink. Rubric is for where the reader acts,
     not for the ruling on a book's spine. */
  color:var(--ink);
  box-shadow:var(--lift);
  transform-origin:bottom right;
  transition:transform var(--dur) var(--ease);
}
/* Bound in cloth. The Codex, and any closed book or volume. */
.spine.dark { background:var(--ink); border-color:transparent; color:var(--paper); }

/* The block of pages, showing past the boards on the side you are not
   looking at. */
.spine-fore {
  flex:0 0 auto; width:calc(4px * var(--sp-s, 1)); min-width:2px;
  background:var(--paper-sunk); border-right:1px solid var(--rule);
}
.spine-body {
  flex:1; min-width:0; display:flex; flex-direction:column;
  align-items:center; justify-content:space-between;
  padding:calc(12px * var(--sp-s, 1)) 0;
  border-left:1px solid rgba(34,29,21,.18);
}
.spine.dark .spine-body { border-left-color:rgba(246,241,231,.18); }

/* A ruled band near the head or the tail, and the ridges a sewn binding makes
   across a spine. */
.spine-band, .spine-raised { width:calc(100% - 16px); flex:0 0 auto; }
.spine-band  { height:3px; border-top:1px solid currentColor; border-bottom:1px solid currentColor; opacity:.42 }
.spine-raised{ height:calc(3px * var(--sp-s, 1)); background:currentColor; opacity:.10;
               margin:calc(5px * var(--sp-s, 1)) 0 }

/* The title, running up the spine as a bound book carries it. */
.spine-panel {
  flex:1; width:calc(100% - 10px); margin:0 5px;
  display:flex; align-items:center; justify-content:center;
  background:rgba(34,29,21,.04); outline:1px solid rgba(34,29,21,.18);
  outline-offset:-1px;
}
.spine.dark .spine-panel { background:rgba(246,241,231,.07); outline-color:rgba(246,241,231,.18) }
.spine-title {
  writing-mode:vertical-rl; transform:rotate(180deg);
  font-family:var(--font-read); font-size:calc(17px * var(--sp-s, 1));
  color:var(--ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  /* Measured from the SPINE's own height, not 100% of a flex panel whose
     height is indefinite — that resolved short and cut "January" to "Janua…"
     on every book on the phone's shelf (overnight UI audit). The subtraction
     is the bands, raised rules and padding above and below the panel. */
  max-height:calc(var(--sp-h, 100%) - 56px * var(--sp-s, 1));
}
.spine.dark .spine-title { color:var(--paper) }

/* In the reader's hand: straightened, lifted, and marked in rubric — rubric
   follows where the reader acts. */
.spine.taken { transform:translateY(-18px) rotate(0deg) !important; box-shadow:var(--lift-high, var(--lift)) }
.spine.taken::after {
  content:''; position:absolute; inset:0 0 auto 0; height:3px; background:var(--rubric);
}

/* The plank they stand on. Furniture, not content — it runs past the column
   the type is set in, because a shelf is wider than the books on it. */
.shelf-floor-top { height:3px; background:var(--ink) }
.shelf-floor-top + .shelf-floor-lip { height:7px; background:var(--paper-sunk) }
.shelf-floor-deep { height:4px; background:var(--ink) }
.shelf-floor-deep + .shelf-floor-lip { height:10px; background:var(--paper-sunk) }

/* A margin card's label (reader.js marginLabel): the source's kind, in the rubric, above the note. */
.margin-note .margin-label { display:block; margin-bottom:4px; color:var(--rubric); }

/* A SCRAPBOOK PAGE MADE FROM A CHAPTER'S PHOTOGRAPHS (A81; 28 Oct 2026): every
   photograph mounted on one page, each with its own line. Spans the spread,
   because a page of eight is not one of two pages side by side. One to eight
   photographs: one sits alone at a readable width; on a phone two or three
   go one under another and four or more two up; wider, two up for two and
   four, three up for three, five, six and seven (seven opens with one across
   the page), four up for eight. The mats keep their own aspect (D5). */
.edition-scrapbook .sb-page-sheet { grid-column:1 / -1; }
.sb-sheet { display:grid; grid-template-columns:minmax(0, 1fr); gap:var(--s6) var(--s4); align-items:start; }
.sb-sheet figure.mat { margin:0; }
.sb-sheet figure.mat img { max-height:min(48vh, 420px); }
.sb-sheet[data-count="1"] { max-width:36rem; margin-inline:auto; }
@media (max-width:559px) {
  .sb-sheet:is([data-count="4"], [data-count="5"], [data-count="6"], [data-count="7"], [data-count="8"]) { grid-template-columns:repeat(2, minmax(0, 1fr)); gap:var(--s4) var(--s3); }
  .sb-sheet:is([data-count="5"], [data-count="7"]) > figure:first-child { grid-column:1 / -1; }
  .sb-sheet:not([data-count="1"], [data-count="2"], [data-count="3"]) figure.mat { padding:var(--s2); }
  .sb-sheet:not([data-count="1"], [data-count="2"], [data-count="3"]) figure.mat.mat-wide { padding:var(--s3); }
  .sb-sheet:not([data-count="1"], [data-count="2"], [data-count="3"]) figure.mat figcaption { font-size:var(--text-sm); margin-top:var(--s2); }
  .sb-sheet:not([data-count="1"], [data-count="2"], [data-count="3"]) .corner { width:var(--s3); height:var(--s3); }
}
@media (min-width:560px) {
  .sb-sheet:not([data-count="1"]) { grid-template-columns:repeat(2, minmax(0, 1fr)); }
  .sb-sheet:is([data-count="3"], [data-count="5"], [data-count="7"]) > figure:first-child { grid-column:1 / -1; }
}
@media (min-width:1024px) {
  .sb-sheet:is([data-count="3"], [data-count="5"], [data-count="6"], [data-count="7"]) { grid-template-columns:repeat(3, minmax(0, 1fr)); }
  .sb-sheet:is([data-count="3"], [data-count="5"], [data-count="6"]) > figure:first-child { grid-column:auto; }
  .sb-sheet[data-count="8"] { grid-template-columns:repeat(4, minmax(0, 1fr)); }
  .sb-sheet:is([data-count="6"], [data-count="7"], [data-count="8"]) figure.mat figcaption { font-size:var(--text-sm); }
}
/* The same page in the maker's preview: small, two up whatever the screen. */
.pp-sheet .sb-sheet.pp-photos { grid-template-columns:repeat(2, minmax(0, 1fr)); gap:var(--s3); }
.pp-sheet .sb-sheet.pp-photos > figure:first-child { grid-column:auto; }
.pp-sheet .sb-sheet.pp-photos[data-count="3"] > figure:first-child,
.pp-sheet .sb-sheet.pp-photos[data-count="5"] > figure:first-child,
.pp-sheet .sb-sheet.pp-photos[data-count="7"] > figure:first-child { grid-column:1 / -1; }
.pp-sheet .sb-sheet.pp-photos .pp-mat { max-width:none; padding:var(--s2); }
.pp-sheet .sb-sheet.pp-photos .pp-mat.mat-wide { padding:var(--s3); }
.pp-sheet .sb-sheet.pp-photos .pp-mat img { max-height:140px; }
.pp-sheet .sb-sheet.pp-photos .corner { width:var(--s3); height:var(--s3); }
.pp-say { text-align:center; margin:var(--s3) 0 0; }
