/* vic.law main page: Home -> About -> Learn -> Start with the one-actor Hoji motion.
   Ported from the approved prototype (design/proofs/hoji-motion, round 11); its README records the round-by-round
   reasoning behind the numbers below. Brand fonts and colours come from ../../brand/tokens.css. */
:root {
  --paper: var(--hoji-paper); --wax: var(--hoji-light-paper); --ink: var(--hoji-ink); --cobalt: var(--hoji-cobalt); --red: var(--hoji-vermilion);
  --ed: var(--hoji-font-editorial); --rd: var(--hoji-font-reading); --folder: #E9D6B4;
  /* One design unit = 14.4px on the 1440x900 reference. The whole composition is a 100u x 46.2u frame,
     scaled to fit the window and centred, so wide or tall windows add paper around it rather than stretching it. */
  --u: min(1vw, 1.588vh);
  --hdr: calc(var(--u) * 9.79);
  --stripes: calc(var(--u) * .7);
  --band: calc(var(--u) * 3.2);
  --ftr: calc(var(--u) * 3.06);
  --col: calc((100vw - var(--u) * 100) / 2);
  --edge: calc(var(--col) + var(--u) * 4.375);
  --speck: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='s'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.3' numOctaves='1' seed='9'/%3E%3CfeColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 9 -6.2'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23s)'/%3E%3C/svg%3E");   /* white lithograph speckle, laid over flat fills */
  --speck-soft: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='s'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.3' numOctaves='1' seed='9'/%3E%3CfeColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 9 -7.4'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23s)'/%3E%3C/svg%3E");   /* a lighter speckle for buttons */
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; background: var(--paper); color: var(--ink); font-family: var(--rd); overflow: hidden; }
a { color: inherit; text-decoration: none; }
body::after { content: ""; position: fixed; inset: 0; z-index: 90; pointer-events: none; mix-blend-mode: multiply; opacity: .34;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='320'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' seed='4' stitchTiles='stitch'/%3E%3CfeColorMatrix values='1.7 0 0 0 -.25 1.7 0 0 0 -.25 1.7 0 0 0 -.25 0 0 0 0 .3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E"); }

/* ---------- Locked chrome ---------- */
.hdr { position: fixed; top: 0; left: 0; right: 0; height: var(--hdr); background: var(--paper); z-index: 60; }
.hdr .mark { position: absolute; left: var(--edge); top: calc(var(--u) * 2.01); width: calc(var(--u) * 25.97); }
.nav { position: absolute; right: calc(var(--col) + var(--u) * 4.44); top: calc(var(--u) * 3.4); height: calc(var(--u) * 3.54); display: flex; align-items: flex-end; gap: calc(var(--u) * 2.64); font-size: calc(var(--u) * 1.7); }
.nav a[data-go]:not(.btn) { padding-bottom: calc(var(--u) * .55); }
.nav a.on:not(.btn) { box-shadow: inset 0 calc(var(--u) * -.2) 0 var(--cobalt); }
.nav .btn { width: calc(var(--u) * 11.6); height: 100%; display: grid; place-items: center; background: var(--red); color: #fff; font-weight: 600; border-radius: 4px; }
.nav .btn.on { background: #B9231B; }
.stripes { position: fixed; left: 0; right: 0; top: var(--hdr); height: var(--stripes); z-index: 61; display: grid; align-content: space-between; }
.stripes i { display: block; height: max(1px, calc(var(--u) * .1)); background: var(--red); }
.ftr { position: fixed; left: 0; right: 0; bottom: 0; height: var(--ftr); background: var(--paper); z-index: 60; font-size: max(11px, calc(var(--u) * .83)); }
.ftr .row { position: absolute; left: var(--edge); right: calc(var(--col) + var(--u) * 4.44); top: 0; bottom: 0; display: flex; align-items: center; }
.ftr .mark { width: calc(var(--u) * 5.7); }
.ftr .legal { margin-left: calc(var(--u) * 27.5); display: flex; gap: calc(var(--u) * 2.5); }
.ftr .social { margin-left: auto; display: flex; gap: calc(var(--u) * 2.5); }

/* The wrapper band: White Rabbit's line system, set in the brand's own type. */
.band { position: fixed; left: 0; right: 0; bottom: var(--ftr); height: var(--band); z-index: 61; background: var(--paper);
  display: grid; grid-template-rows: auto 1fr auto; --pl: max(1px, calc(var(--band) * .034)); --pg: max(1px, calc(var(--band) * .05)); }
.pins { display: grid; gap: var(--pg); }
.pins i { display: block; height: var(--pl); background: var(--red); }
.track { margin: var(--pg) 0; background: var(--wax); overflow: hidden; position: relative; }
.run { position: absolute; left: 0; top: 0; bottom: 0; display: flex; align-items: center; white-space: nowrap; will-change: transform; }
.run > * { flex: none; margin-right: calc(var(--band) * .62); }
.band .ed { font: 900 calc(var(--band) * .43)/1 var(--ed); letter-spacing: -.02em; color: var(--cobalt); text-box: trim-both cap alphabetic; }
.band .in { font: 600 calc(var(--band) * .3)/1 var(--rd); letter-spacing: -.005em; color: var(--ink); text-box: trim-both cap alphabetic; }
.band .blk { align-self: stretch; display: flex; align-items: center; padding: 0 calc(var(--band) * .34); background: var(--cobalt); position: relative; margin-left: calc(var(--band) * .9); margin-right: calc(var(--band) * 1.5); }
.band .blk .in { color: var(--wax); }
.band .blk::before, .band .blk::after { content: ""; position: absolute; top: 0; bottom: 0; width: calc(var(--band) * .9); background: repeating-linear-gradient(180deg, var(--cobalt) 0 var(--pl), transparent var(--pl) calc(var(--pl) * 2.6)); }
.band .blk::before { right: 100%; -webkit-mask: linear-gradient(90deg, transparent, #000); mask: linear-gradient(90deg, transparent, #000); }
.band .blk::after { left: 100%; -webkit-mask: linear-gradient(270deg, transparent, #000); mask: linear-gradient(270deg, transparent, #000); }
.band .lz { width: calc(var(--band) * .13); height: calc(var(--band) * .13); background: var(--red); transform: rotate(45deg); }
.band .wm { height: calc(var(--band) * .36); display: block; }

/* ---------- Stage, frame and chapters ---------- */
.stage { position: fixed; left: 0; right: 0; top: calc(var(--hdr) + var(--stripes)); bottom: calc(var(--ftr) + var(--band)); overflow: hidden; }
.chap { position: absolute; inset: 0; visibility: hidden; }
.chap.on { visibility: visible; }
.home .frame { top: max(0px, calc((100% - var(--u) * 46.2) * .4)); }   /* loop 5: tall windows put more of the spare height under the desk (feet on a ground line), less above the headline */
/* The composition is one 100u x 46.2u frame, centred in whatever height the window gives it. */
.frame { position: absolute; top: max(0px, calc((100% - var(--u) * 46.2) * .5)); height: calc(var(--u) * 46.2); left: var(--col); width: calc(var(--u) * 100); }
.frame > * { position: absolute; }
.seam { position: absolute; left: 0; right: 0; height: calc(var(--u) * .8); z-index: 5; display: grid; align-content: space-between; pointer-events: none; opacity: 0; }
.seam i { height: max(1px, calc(var(--u) * .12)); background: var(--red); }
.red { color: var(--red); font-family: var(--ed); font-weight: 900; margin: 0; }
[tabindex="-1"]:focus { outline: none; }

.home h1 { left: calc(var(--u) * 4.375); bottom: calc(var(--u) * 13.2); font-size: calc(var(--u) * 11); line-height: .86; letter-spacing: -.04em; }
.home .dek { left: calc(var(--u) * 4.375); bottom: calc(var(--u) * 8.3); margin: 0; font-weight: 600; font-size: calc(var(--u) * 2.625); letter-spacing: -.02em; }
.dek b { color: var(--cobalt); font-weight: 600; }
.m-hero { position: static !important; }
.cta { position: absolute; left: calc(var(--u) * 4.375); bottom: 0; width: calc(var(--u) * 51.6); height: calc(var(--u) * 6.25); display: grid; place-items: center; background: var(--red); color: #fff; font-weight: 600; font-size: calc(var(--u) * 2.5); letter-spacing: -.02em; border-radius: 4px 4px 0 0; transition: background .08s, transform .08s; z-index: 3; }
.cta.pressed, .cta:active { background: #B9231B; transform: translateY(2px); }
a:focus-visible, button:focus-visible, .cta:focus-visible, .field input:focus-visible, .field textarea:focus-visible, .tab:has(input:focus-visible) { outline: 2px solid var(--ink); outline-offset: 4px; }

.learn .head { left: calc(var(--u) * 31); top: calc(var(--u) * 4); display: flex; align-items: flex-end; gap: calc(var(--u) * 2.4); }
.learn h2 { font-size: calc(var(--u) * 7.5); line-height: .84; letter-spacing: -.045em; }
.perch { display: block; flex: none; position: relative; }
/* Round 8: the red book (Learn) and the typewriter (Start) are fixed props in the perch, under Hoji; a mask on Hoji
   (propMask) hides him wherever the prop stands in front of him, so only the cat ever changes. */
.perch .prop-fixed { position: absolute; inset: 0; width: 100%; height: 100%; }
.learn .perch { width: calc(var(--u) * 15); aspect-ratio: 1412 / 1000; margin-bottom: calc(var(--u) * -.4); }
.feed { left: calc(var(--u) * 13.9); right: calc(var(--u) * 13.9); top: calc(var(--u) * 15); font-size: calc(var(--u) * 1.11); }
.feed .row { display: flex; justify-content: space-between; font-weight: 600; padding-bottom: calc(var(--u) * 1.4); border-bottom: 1px solid var(--ink); }
.feed .row a { box-shadow: inset 0 -2px 0 var(--cobalt); padding-bottom: calc(var(--u) * .5); }
.feed h3 { font: 700 calc(var(--u) * 3.05)/1.05 var(--ed); margin: calc(var(--u) * 1.9) 0 calc(var(--u) * 1.1); }
.feed p { margin: 0 0 calc(var(--u) * 1.8); }
.feed .yt { color: var(--cobalt); font-size: calc(var(--u) * .97); display: block; padding-bottom: calc(var(--u) * 2.6); border-bottom: 1px solid var(--ink); }
/* Round 11: the first video. A thumbnail facade (no YouTube script until the visitor presses play), framed like a print
   in ink with a vermilion play stamp; pressing play swaps in the privacy-enhanced player. */
.vid { display: grid; grid-template-columns: calc(var(--u) * 36) minmax(0, 1fr); gap: calc(var(--u) * 3); align-items: end;
       margin-top: calc(var(--u) * 2.2); padding-bottom: calc(var(--u) * 2.2); border-bottom: 1px solid var(--ink); }
.vplay, .vid iframe { display: block; width: 100%; aspect-ratio: 16 / 9; border: 1.5px solid var(--ink); border-radius: 4px; padding: 0; background: var(--ink); cursor: pointer; position: relative; overflow: hidden; }
.vplay img { width: 100%; height: 100%; object-fit: cover; display: block; filter: saturate(.92) contrast(1.02); transition: transform .4s cubic-bezier(.2,.8,.2,1); }
.vplay:hover img, .vplay:focus-visible img { transform: scale(1.025); }
.vplay .pb { position: absolute; left: 50%; top: 50%; width: calc(var(--u) * 6); aspect-ratio: 1; translate: -50% -50%; border-radius: 50%;
             background: var(--red); box-shadow: 0 0 0 calc(var(--u) * .35) var(--paper, #F4EBDE); transition: scale .2s; }
.vplay .pb::after { content: ""; position: absolute; left: 54%; top: 50%; translate: -50% -50%; border-style: solid; border-color: transparent transparent transparent var(--paper, #F4EBDE);
                    border-width: calc(var(--u) * 1.15) 0 calc(var(--u) * 1.15) calc(var(--u) * 1.9); }
.vplay:hover .pb { scale: 1.08; }
.vplay:focus-visible { outline: 3px solid var(--cobalt); outline-offset: 3px; }
.vmeta h3 { margin-top: 0; }
.vmeta .yt { border-bottom: 0; padding-bottom: 0; }

.about .portrait { left: calc(var(--u) * 4.375); bottom: 0; height: min(100%, var(--u) * 46.2); aspect-ratio: 1121 / 1361; }
.about .portrait > img { display: block; width: 100%; height: 100%; }
.about .copy { top: calc(var(--u) * 3.4); right: calc(var(--u) * 4.44); left: calc(var(--u) * 45.5); }
.about h2 { font-size: calc(var(--u) * 7.95); line-height: .86; letter-spacing: -.04em; margin-bottom: calc(var(--u) * 1.6); }
/* Round 8: the story is justified (with hyphenation and pretty wrapping), on a fixed measure, in a stepped type scale:
   the size changes in a few steps with the window instead of continuously, so the lines stop reflowing as it resizes. */
.about p { font-size: 16px; line-height: 1.5; margin: 0 0 .8em; max-width: 62ch; text-align: justify; hyphens: auto; -webkit-hyphens: auto; text-wrap: pretty; }
/* Round 9: one step larger throughout, so the story holds its own beside the headline (18px at 1440x900) */
@media (max-width: 960px), (max-height: 680px) { .about p { font-size: 15px; } }
@media (min-width: 1280px) and (min-height: 780px) { .about p { font-size: 18px; } }
@media (min-width: 1600px) and (min-height: 940px) { .about p { font-size: 20px; } }
@media (min-width: 2200px) and (min-height: 1250px) { .about p { font-size: 23px; } }

/* Start: the folder, printed in the same flat lithograph manner as Hoji: no black outlines,
   flat fills with a white speckle, thin white contour lines, and a faint off-register plate behind. */
.start .top { left: calc(var(--u) * 27.5); top: calc(var(--u) * 1.4); display: flex; align-items: flex-end; gap: calc(var(--u) * 1.6); }
.start h2 { font-size: calc(var(--u) * 5.1); line-height: .9; letter-spacing: -.035em; }
.start .perch { width: calc(var(--u) * 14); aspect-ratio: 1388 / 1103; }
.start .soon { left: calc(var(--u) * 27.5); top: calc(var(--u) * 12.4); margin: 0; font-size: calc(var(--u) * 1.62); }
.start .soon b { color: var(--cobalt); font-weight: 600; }
/* Round 10: the expanding accordion file. A kraft wallet in the desk's own three steps (#CFAE72 front, #B08A4E pleats,
   back panel and seams, #7E5D31 recesses), drawn as SVG at the folder's measured pixel size by drawFolder(), so the
   pleats, cord and grommet keep their proportions at any width (no stretched raster). The back SVG (.wb: back panel and
   the left/right gussets) sits under the tabs; the front SVG (.wf: flap, cord and button) sits under the fields. */
.folder { left: calc(var(--u) * 11.3); width: calc(var(--u) * 77.4); top: calc(var(--u) * 15.4); --manila: #CFAE72; --tab-off: #E4CC99; --tab-hover: #D9BD85; --ring: var(--red); --core: #F8F1E4;
  filter: drop-shadow(calc(var(--u) * .35) calc(var(--u) * .35) 0 rgba(19, 76, 187, .16)); }
.folder .wb, .folder .wf { position: absolute; overflow: visible; pointer-events: none; }
.folder .wb { z-index: 0; }
.folder .wf { left: 0; top: 0; z-index: -1; }
.tabs { border: 0; margin: 0; min-width: 0; display: flex; height: calc(var(--u) * 4.7); position: relative; z-index: 1; margin-bottom: calc(var(--u) * -.55); padding: 0 calc(var(--u) * .9); }
.tab { width: 45%; position: relative; display: flex; gap: calc(var(--u) * .9); padding: 0 calc(var(--u) * 3) calc(var(--u) * .45) calc(var(--u) * 2); cursor: pointer; line-height: 1.2; color: var(--ink); --fill: var(--tab-off); isolation: isolate; }
.tab + .tab { margin-left: calc(var(--u) * -1.2); padding-left: calc(var(--u) * 3); }
.tab .shape { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; overflow: visible; }
.tab .shape path { fill: var(--fill); }
.tab .shape .line { fill: none; stroke: rgba(250, 249, 246, .7); stroke-width: 1.2; vector-effect: non-scaling-stroke; }
.tab.on { --fill: var(--cobalt); color: #fff; z-index: 3; }
.tab:not(.on) { --fill: var(--tab-off); }
.tab:not(.on):hover { --fill: var(--tab-hover); }
.tab:not(.on) .shape .line { stroke: rgba(126, 93, 49, .45); }
.tab strong { display: block; font-size: calc(var(--u) * 1.55); font-weight: 600; }
.tab small { font-size: calc(var(--u) * 1.05); opacity: .85; }
.tab .chk { width: calc(var(--u) * 1.7); height: calc(var(--u) * 1.7); border-radius: 50%; box-shadow: inset 0 0 0 1.5px currentColor; flex: none; display: grid; place-items: center; font-size: calc(var(--u) * 1.05); }
.tab.on .chk { background: #fff; color: var(--cobalt); box-shadow: none; }
.sheet { position: relative; z-index: 2; isolation: isolate; padding: calc(var(--u) * 3.35) calc(var(--u) * 2.4) calc(var(--u) * 1.6); border-radius: calc(var(--u) * .7); background: var(--speck), var(--manila); background-size: 180px, auto; }
.folder.drawn .sheet { background: none; }   /* until drawFolder() has run, the flat kraft sheet stands in */
.fields { display: grid; grid-template-columns: 1fr 1fr; gap: calc(var(--u) * .9) calc(var(--u) * 1.4); position: relative; z-index: 1; }
.field { display: grid; gap: calc(var(--u) * .45); font-weight: 600; font-size: calc(var(--u) * 1.2); }
.field.wide { grid-column: 1 / -1; }
.field input, .field textarea { font: 400 calc(var(--u) * 1.1)/1.4 var(--rd); background: #F8F1E4; border: 0; border-bottom: 2px solid rgba(19, 76, 187, .55); border-radius: 3px 3px 0 0; padding: calc(var(--u) * .6) calc(var(--u) * .8); color: var(--ink); resize: none; }
.field input:focus, .field textarea:focus { outline: none; border-bottom-color: var(--cobalt); box-shadow: inset 0 -1px 0 var(--cobalt); background: #FCF8F0; }
.field input { height: calc(var(--u) * 3); }
.field textarea { height: calc(var(--u) * 6.2); }
.act { display: flex; gap: calc(var(--u) * 1.4); align-items: center; margin-top: calc(var(--u) * 1.2); position: relative; z-index: 1; }
.act p { margin: 0; font-size: calc(var(--u) * .97); line-height: 1.4; flex: 1; }
.send { position: relative; width: calc(var(--u) * 22.9); height: calc(var(--u) * 3.3); background: var(--speck-soft), var(--red); background-size: 180px, auto; color: #fff; border: 0; font: 600 calc(var(--u) * 1.55)/1 var(--rd); border-radius: 3px; cursor: pointer; flex: none; }
.send::after { content: ""; position: absolute; inset: 4px; border: 1px solid rgba(250, 249, 246, .6); border-radius: 2px; }
.send:active { transform: translateY(1px); }

/* ---------- Hoji, the one actor ---------- */
#hoji { position: fixed; left: 0; top: 0; z-index: 40; pointer-events: none; transform-origin: 50% 100%; will-change: transform; user-select: none; }
#hoji.behind-chrome { z-index: 30; }
#hoji img { position: absolute; inset: 0; width: 100%; height: 100%; display: none; }
#hoji img.on { display: block; }
#hoji .marks { position: absolute; right: 2%; top: 4%; width: 6%; height: 24%; overflow: visible; opacity: 0; }

/* The study: a Shanghai writing desk in the Ming manner (everted ends, cloud-scroll spandrels), a red typewriter and law books on it,
   and the old Bund skyline printed faintly on the wall behind. Everything is placed from measured anchors, so it holds at any size. */
.study { position: absolute; inset: 0; z-index: 0; pointer-events: none; display: none; }
body[data-set="study"] .study { display: block; }
.study > * { position: absolute; }
.skyline { opacity: .18; -webkit-mask: linear-gradient(90deg, transparent, #000 var(--skf, 38%)); mask: linear-gradient(90deg, transparent, #000 var(--skf, 38%)); }
/* Round 8: the campaign desk, a lithograph print in three pieces (src/desk_r8.py): the two ends keep the turned legs and
   the pulls at their drawn proportions, and the plain middle is a seamless tile, so the board stretches to any width. */
.desk > i { position: absolute; top: 0; height: 100%; }
.desk:not(.ready) > i { visibility: hidden; }   /* production: shown once the print pieces are decoded (WebKit mask repaint) */
/* Round 9: recoloured as a flat brand print (src/desk_r9.py): the Start folder's kraft, one darker step of the same hue
   for the apron, drawer and legs, cream contour lines, and the folder's white speckle laid on at screen scale (masked
   to the print's own silhouette, so no speckle falls on the paper). */
.desk .dl, .desk .dr, .desk .dm { background-image: var(--speck), var(--desk-img); background-size: 180px, 100% 100%; background-repeat: repeat, no-repeat;
  -webkit-mask: var(--desk-img) 0 0 / 100% 100% no-repeat; mask: var(--desk-img) 0 0 / 100% 100% no-repeat; }
.desk .dl { left: 0; --desk-img: url(assets/hoji/set/desk-l.webp); }
.desk .dr { right: 0; --desk-img: url(assets/hoji/set/desk-r.webp); }
.desk .dm { --desk-img: url(assets/hoji/set/desk-m.webp); background-repeat: repeat, repeat-x; -webkit-mask-repeat: repeat-x; mask-repeat: repeat-x; }
.desk .dg { top: auto; height: 3px; left: 0; right: 0; background: #BF9C62; border-radius: 2px; display: none; }
.desk.grounded .dg { display: block; }
.prop { height: auto; }
.prop-shadow { border-radius: 50%; background: radial-gradient(closest-side, rgba(22, 23, 24, .22), rgba(22, 23, 24, 0)); }
#shade { position: fixed; z-index: 39; pointer-events: none; overflow: hidden; display: none; }
body[data-set="study"][data-chap="home"] #shade.on { display: block; }
#shade .contact { position: absolute; border-radius: 50%; background: radial-gradient(closest-side, rgba(22, 23, 24, .28), rgba(22, 23, 24, 0)); }
#ghost { position: fixed; z-index: 39; pointer-events: none; opacity: 0; }
#ghost img { width: 100%; height: 100%; display: block; }
#trail img { position: fixed; z-index: 38; pointer-events: none; opacity: 0; }
#trail img.flip { transform: scaleX(-1); }
#hoji.flip img { transform: scaleX(-1); }

/* ---------- Phones: still, scroll-snapped, with small entrances ---------- */
.m-only { display: none !important; }
@media (max-width: 820px) {
  :root { --u: calc(100vw / 27.1); --col: 0px; --edge: 17px; }
  .hdr { height: 61px; }
  .hdr .mark { left: 17px; top: 15px; width: 124px; }
  .nav { right: 17px; top: 8px; height: 44px; gap: 12px; font-size: 14.8px; align-items: center; }
  .nav a[data-go]:not(.btn) { padding-bottom: 0; }
  .nav .btn { width: 66px; height: 44px; border-radius: 5px; }
  .stripes { top: 61px; height: 7px; }
  .band { height: 34px; bottom: 92px; --band: 34px; }
  .ftr { height: 92px; font-size: 12px; }
  .ftr .row { left: 0; right: 0; flex-direction: column; justify-content: center; gap: 9px; }
  .ftr .legal, .ftr .social { margin: 0; gap: 16px; }
  .stage { top: 68px; bottom: 126px; overflow-y: auto; scroll-snap-type: y mandatory; overscroll-behavior: contain; }
  .chap { position: relative; min-height: 100%; visibility: visible; scroll-snap-align: start; scroll-snap-stop: always; }
  .frame, .home .frame { position: absolute; inset: 0; width: auto; height: auto; }
  .home .frame { display: flex; flex-direction: column; padding: clamp(20px, 4vh, 40px) 17px 0; }   /* loop 4: the headline never touches the stripes */
  .home .frame > * { position: static; }
  .home h1 { letter-spacing: -.045em; margin-bottom: 14px; }   /* "character." ink stays inside the 17px gutters */
  .home .dek { font-size: min(23px, 5.9vw); line-height: 1.18; text-wrap: balance; }
  .m-gap { flex: 0 0 clamp(14px, 3vh, 28px); }        /* the peek sits just under the dek; spare height goes above the headline */
  .m-hero { position: relative !important; }
  /* Round 8: the peek's face is cut flat 56/884 of its width above the image bottom (the paws hang lower). The bottom of
     the face is locked 1.5px behind the button's top edge, so he always reads as tucked behind it, in every eye frame. */
  .m-peek { display: block; width: var(--pkw); margin: 0 auto calc(var(--pkw) * -.0633 - 1.5px); position: relative; z-index: 1; }
  .cta { position: relative; left: auto; width: 100%; height: 62px; font-size: 19px; border-radius: 6px 6px 0 0; z-index: 2; }
  /* Loop 3 (kept in loop 4): Learn on a phone is one composition (title, reading cat, feed) centred between the header
     and the band, so the spare height surrounds the group instead of pooling under it. */
  .learn .frame { display: flex; flex-direction: column; padding: 16px 17px; }
  .learn .frame > * { position: relative; left: auto; right: auto; top: auto; }
  .learn .head { grid-template-columns: minmax(0, 1fr); }
  .learn h2 { font-size: min(64px, 16.4vw); }
  .feed { font-size: 15px; margin-top: clamp(8px, 2vh, 20px); }
  .feed .row { padding-bottom: 8px; }
  .feed h3 { font-size: 28px; }
  .about .frame, .start .frame { position: relative; padding: 14px 17px 14px; height: auto; top: auto; }
  .about .frame > *, .start .frame > * { position: relative; left: auto; right: auto; top: auto; bottom: auto; width: auto; }
  /* About on a phone: the title and the portrait (head, shoulders and Hoji, cropped at the chest) share the top row,
     like Learn's title and reading cat; the story runs full width below, so all of it sits above the band. */
  .about .frame { align-content: center; }
  .about h2 { font-size: min(48px, 12.2vw); }
  /* Loop 4: the portrait is a little larger (Hoji reads on his shoulder) and ends at the collar in a short paper fade
     instead of a hard slice through the shirt. */
  .about .portrait { height: auto; aspect-ratio: 1121 / 1361;
    -webkit-mask-image: linear-gradient(to bottom, #000 56%, transparent 70%); mask-image: linear-gradient(to bottom, #000 56%, transparent 70%); }
  .about .portrait > img:first-child { width: 100%; height: 100%; object-fit: contain; object-position: 0 100%; }
  .about p { font-size: 15px; line-height: 1.45; max-width: none; margin: 0 0 10px; }
  .start .top { display: flex; justify-content: space-between; align-items: flex-end; gap: 8px; }
  .start h2 { font-size: min(42px, 10.4vw); }
  .start .perch { width: min(118px, 29vw); flex-shrink: 1; min-width: 0; }   /* shrinks rather than pushing 3px past the gutter at 390 */
  .start .soon { margin: 2px 0 8px; font-size: 15px; }
  .start .frame { padding-top: 10px; }
  .folder { filter: drop-shadow(3px 3px 0 rgba(19, 76, 187, .16)); }
  .tabs { height: 52px; margin-bottom: -5px; padding: 0 5px; }
  .tab { width: 53%; padding: 0 18px 5px 14px; gap: 0; } .tab + .tab { margin-left: -6%; padding: 0 10px 5px 24px; }
  .tab strong { font-size: 15px; } .tab small { font-size: 11px; } .tab .chk { display: none; }
  .sheet { padding: 25px 14px 14px; border-radius: 6px; }   /* round 10: room above the fields for the cord and its button */
  .fields { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px 10px; }
  .field input, .field textarea { min-width: 0; width: 100%; }
  .field { font-size: 13.5px; gap: 4px; } .field input { height: 40px; font-size: 16px; } .field textarea { height: 62px; font-size: 16px; }
  .act { flex-direction: column; align-items: stretch; gap: 10px; margin-top: 10px; } .act p { font-size: 11.5px; line-height: 1.35; } .send { width: 100%; height: 46px; font-size: 17px; }
  .m-only { display: block !important; }
  .d-only, #hoji, .study, #shade, #ghost, #trail { display: none !important; }
  /* He rises from behind the button once, with no overshoot, so no gap ever opens above it; after that only his eyes move. */
  .m-hero { overflow: hidden; padding-top: 4px; }
  .chap.seen .m-peek { animation: m-peek 420ms steps(5, end) both; }
}
/* Loop 5, phones: one vertical rule for all four chapters. Each chapter's group (Home: headline, dek, peek, button;
   Learn: title, cat, feed; About: title, portrait, story; Start: title, folder) sits in the spare height between the
   header and the band, split 40% above and 60% below. */
@media (max-width: 820px) {
  .home .frame, .learn .frame { justify-content: flex-start; }
  .home .frame::before, .learn .frame::before { content: ""; flex: 2 1 0; }
  .home .frame::after, .learn .frame::after { content: ""; flex: 3 1 0; }
  .chap.about, .chap.start { display: flex; flex-direction: column; }
  .chap.about::before, .chap.start::before { content: ""; flex: 2 1 0; }
  .chap.about::after, .chap.start::after { content: ""; flex: 3 1 0; }
  .about .frame, .start .frame { flex: 0 0 auto; }
  /* Round 8, About: the portrait on the LEFT with the title beside it, and the justified story full width below, so no
     justified line is ever set in a narrow column beside the portrait. */
  .about .frame { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 14px; padding-top: 10px; --pw: min(42vw, 196px, 27vh); }
  .about .copy { display: contents; }
  .about .portrait { grid-column: 1; grid-row: 1; width: var(--pw); margin: 0 0 calc(var(--pw) * -.36) -6px; }
  .about h2 { grid-column: 2; grid-row: 1; align-self: center; margin: 0; line-height: .9; }
  .about p { grid-column: 1 / -1; }
  .about p:first-of-type { margin-top: 0; }
  .about .frame::after { display: none; }
}
@media (max-width: 359px) { .about p { font-size: 14px; } }
@media (max-width: 359px) { .hdr .mark { width: 94px; top: 20px; } .nav { gap: 9px; font-size: 13.5px; } .nav .btn { width: 58px; } }
@keyframes m-peek { 0% { transform: translateY(70%); } 100% { transform: none; } }
@media (prefers-reduced-motion: reduce) { .chap.seen .m-peek { animation: none !important; } }

/* ---------- Production additions (not in the prototype) ---------- */
[hidden] { display: none !important; }
.skip-link { position: fixed; left: var(--edge); top: -100px; z-index: 100; padding: 10px 16px; background: var(--paper); font-weight: 600; border: 2px solid var(--ink); }
.skip-link:focus { top: 12px; }
.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
.stage:focus { outline: none; }
.ftr .row > a:first-child { display: flex; }
/* The header wordmark link carries the mark's position, so the link itself has a box (focus ring, hit target). */
.hdr > a[data-go="home"] { position: absolute; left: var(--edge); top: calc(var(--u) * 2.01); width: calc(var(--u) * 25.97); }
.hdr > a[data-go="home"] .mark { position: static; display: block; width: 100%; }
@media (max-width: 820px) { .hdr > a[data-go="home"] { left: 17px; top: 15px; width: 124px; } }
@media (max-width: 359px) { .hdr > a[data-go="home"] { width: 94px; top: 20px; } }   /* the footer wordmark is a link here; no inline baseline gap */

/* The contact form keeps start.html's delivery states (start.js drives both pages). */
.contact-honeypot { display: none; }
.tab:has(input:disabled) { cursor: default; }
.field [aria-invalid="true"] { border-bottom-color: var(--red); }
.field input:disabled, .field textarea:disabled { opacity: .72; }
.send:disabled { cursor: not-allowed; opacity: .6; }
.act p a { text-decoration: underline; text-underline-offset: 2px; }
.delivery-notice { position: relative; z-index: 1; margin: calc(var(--u) * .5) 0 0; font-size: calc(var(--u) * .97); }
.contact-status { position: relative; z-index: 1; margin: calc(var(--u) * .6) 0 0; font-size: calc(var(--u) * 1.1); line-height: 1.35; color: #A81F18; font-weight: 600; }
.contact-status:empty { display: none; }
.folder[aria-busy="true"] .contact-status { color: var(--ink); }
.contact-success { position: relative; z-index: 1; min-height: calc(var(--u) * 14.5); display: flex; flex-direction: column; justify-content: center; align-items: flex-start; }
.contact-success h2 { margin: calc(var(--u) * 1.2) 0 calc(var(--u) * .6); font: 700 calc(var(--u) * 3.4)/1.05 var(--ed); letter-spacing: -.03em; }
.contact-success p { margin: 0; font-size: calc(var(--u) * 1.3); }
.received-stamp { display: inline-block; border: 2px solid var(--cobalt); color: var(--cobalt); border-radius: 4px; padding: 3px 14px; text-transform: uppercase; font-size: calc(var(--u) * 1); font-weight: 600; letter-spacing: .12em; transform: rotate(-4deg); }
.vid.empty { grid-template-columns: minmax(0, 1fr); }
@media (max-width: 820px) {
  .delivery-notice { font-size: 11.5px; margin-top: 6px; }
  .contact-status { font-size: 13.5px; margin-top: 8px; }
  .contact-success { min-height: 170px; }
  .contact-success h2 { font-size: 30px; margin: 14px 0 8px; }
  .contact-success p { font-size: 15px; }
  .received-stamp { font-size: 12px; }
}

/* Without JavaScript the header links still reach each chapter (:target), and the form posts natively. */
@media (min-width: 821px) {
  html:not(.js) .chap:target { visibility: visible; }
  html:not(.js) .stage:has(.chap:target) .chap.home:not(:target) { visibility: hidden; }
}
html:not(.js) .folder .sheet { background: var(--speck), var(--manila); }

/* Short or landscape windows under 821px wide (outside the prototype's approved 390x844, 375x667, 320x700 and 430x932
   phones, whose geometry these rules leave unchanged): the peek and the headline also scale with the window's height,
   and very short windows drop the peek, so "Start a conversation" always sits above the band. */
@media (max-width: 820px) { .m-peek { --pkw: min(88%, 40vh); } .home h1 { font-size: min(76px, 18.4vw, 9.4vh); } }
@media (max-width: 820px) and (max-height: 560px) { .m-peek { display: none !important; } }
/* Learn grows with its content like About and Start (identical when it fits), so a short window scrolls to the video
   instead of spilling it over the Start chapter. */
@media (max-width: 820px) { .chap.learn { display: flex; flex-direction: column; } .learn .frame { position: relative; inset: auto; flex: 1 0 auto; } }

/* Round 12, phones: every chapter fits one screen at real browser heights (Safari's bars leave about 660px of an
   844px iPhone), so nothing ever scrolls inside a chapter. Sizes key off svh (the small viewport, bars showing).
   The About story is justified again, with hyphenation, at every phone width. */
@media (max-width: 820px) {
  .about p { text-align: justify; hyphens: auto; -webkit-hyphens: auto; text-wrap: pretty; }
}
@media (max-width: 820px) and (max-height: 780px) {
  .vmeta .yt { font-size: 12.5px; }
  .home h1 { font-size: min(62px, 15.6vw, 9.4svh); margin-bottom: 10px; }
  .m-peek { --pkw: min(74%, 38svh); }
  .start .top h2 { font-size: min(36px, 10vw); } .start .perch { width: min(96px, 26vw); }
  .start .soon { margin-bottom: 6px; }
  .tabs { height: 44px; }
  .sheet { padding-top: 22px; }
  .field input { height: 36px; } .field textarea { height: 54px; }
  .act { gap: 8px; margin-top: 8px; } .act p { font-size: 11px; } .send { height: 42px; }
}
@media (max-width: 820px) and (max-height: 600px) {
  .learn h2 { font-size: min(52px, 14vw); }
  .about .frame { --pw: min(34vw, 150px, 24svh); }
  .about h2 { font-size: min(40px, 11vw); }
  .start .soon { display: none; }
  .fields { gap: 6px 8px; } .field { font-size: 12.5px; gap: 3px; }
}
@media (max-width: 820px) and (max-height: 660px) {
  .about p { font-size: 14px; line-height: 1.4; margin-bottom: 8px; }
  .start .top h2 { font-size: min(32px, 9.4vw); } .start .perch { width: min(84px, 24vw); }
  .field textarea { height: 50px; }
}
@media (max-width: 820px) and (max-height: 600px) {
  .start .frame { padding-top: 6px; padding-bottom: 6px; }
  .tab strong { font-size: 14px; }
  .sheet { padding: 20px 12px 10px; }
  .act { margin-top: 6px; }
  .about p { font-size: 13px; line-height: 1.34; margin-bottom: 6px; }
  .start .perch { width: min(74px, 22vw); }
  .field textarea { height: 36px; }
  .home h1 { margin-bottom: 6px; }
}

/* Round 13. Tabs: title and subline sit as one tight block, clear of the tab's top edge. */
.tab { align-items: center; padding-top: calc(var(--u) * .55); padding-bottom: calc(var(--u) * .2); }
.tab strong { line-height: 1.08; }
.tab small { display: block; line-height: 1.15; margin-top: calc(var(--u) * .2); }
@media (max-width: 820px) {
  .tab { padding-top: 4px; }
  /* Learn on a phone: the title and the reading cat share one row (cat beside the title, baselines aligned), which
     frees the cat's old row for a full-width video. */
  .learn .head { display: flex; align-items: flex-end; justify-content: space-between; gap: 8px; }
  .learn .perch { width: min(170px, 42vw, 16svh * 1.412); margin: 0 -4px 0 0; flex: none; }
  .learn .frame::before { flex: 1 1 0; } .learn .frame::after { flex: 2 1 0; }
  .vid { grid-template-columns: minmax(0, 1fr); align-items: start; gap: 10px; margin-top: 12px; padding-bottom: 12px; }
  .vid .pb { width: 52px; box-shadow: 0 0 0 4px var(--paper, #F4EBDE); }
  .vid .pb::after { border-width: 10px 0 10px 16px; }
  .vmeta h3 { font-size: 20px; line-height: 1.08; margin: 0 0 4px; }
  /* Start on a phone: the folder takes the spare height and the note box grows into it, instead of a short box
     floating in empty paper. */
  .chap.start::before { flex: 0 0 clamp(6px, 2.5svh, 24px); } .chap.start::after { flex: 0 0 clamp(6px, 2svh, 18px); }
  .start .frame { flex: 1 1 auto; display: flex; flex-direction: column; }
  .folder { flex: 1 1 auto; display: flex; flex-direction: column; }
  .sheet { flex: 1 1 auto; display: flex; flex-direction: column; }
  #form-fields { flex: 1 1 auto; display: flex; flex-direction: column; }
  .fields { flex: 1 1 auto; grid-template-rows: auto minmax(0, 1fr); }
  .field.wide { grid-template-rows: auto minmax(0, 1fr); }
  .field.wide textarea { max-height: 260px; }
}
@media (max-width: 820px) and (max-height: 660px) {
  .vmeta h3 { font-size: 17px; }
  .learn .perch { width: min(140px, 36vw, 14svh * 1.412); }
}
@media (max-width: 820px) and (max-height: 600px) {
  .learn .perch { width: min(118px, 32vw); }
}
@media (max-width: 820px) {
  .vid .vplay, .vid iframe { width: min(100%, calc(27svh * 16 / 9)); }   /* the video never pushes Learn past the band */
  .start .frame, .folder, .sheet, #form-fields, .fields { min-height: 0; }
  .field.wide textarea { min-height: 44px; }
}
@media (max-width: 820px) and (max-height: 600px) {
  .vid { grid-template-columns: 46% minmax(0, 1fr); align-items: center; gap: 10px; }
  .vid .vplay, .vid iframe { width: 100%; }
  .vid .pb { width: 36px; box-shadow: 0 0 0 3px var(--paper, #F4EBDE); } .vid .pb::after { border-width: 7px 0 7px 11px; }
  .vmeta h3 { font-size: 15px; }
  .field.wide textarea { min-height: 34px; }
}
@media (max-width: 820px) {
  .field.wide textarea { height: auto !important; align-self: stretch; }   /* rows="1" keeps its intrinsic size small; the grid row stretches it */
}
@media (max-width: 820px) and (max-height: 660px) { .act { gap: 6px; } .act p { font-size: 10.5px; line-height: 1.3; } .send { height: 40px; } .start .soon { margin-bottom: 4px; } }
@media (max-width: 820px) and (max-height: 600px) { .send { height: 36px; font-size: 15px; } .sheet { padding-top: 18px; } .tabs { height: 36px; } .field input { height: 30px; } .start .top h2 { font-size: min(28px, 8.6vw); } .chap.start::before, .chap.start::after { flex-basis: 4px; } }
@media (max-width: 820px) and (max-height: 780px), (max-width: 399px) { .tab small { display: none; } }   /* phones: tab titles only where sublines would crowd */
/* Round 14: only the note box may give up height. The tab row, title, "coming soon" line, name/email row and the
   send row never shrink, so a tight window can't squeeze the tabs off the folder (seen in Chrome at ~410px wide). */
@media (max-width: 820px) {
  .start .top, .start .soon, .folder > .tabs, .act, .tab { flex-shrink: 0; }
  .folder > .tabs { min-height: 36px; overflow: visible; }
  .fields > .field:not(.wide) { min-height: max-content; }
}
