/* Self-hosted type (Open Font License, files from Fontsource): no third-party request. */
@font-face{font-family:"Fraunces";font-style:normal;font-weight:600;font-display:swap;src:url(../fonts/fraunces-latin-600-normal.woff2) format("woff2")}
@font-face{font-family:"Fraunces";font-style:italic;font-weight:600;font-display:swap;src:url(../fonts/fraunces-latin-600-italic.woff2) format("woff2")}
@font-face{font-family:"Figtree";font-style:normal;font-weight:400;font-display:swap;src:url(../fonts/figtree-latin-400-normal.woff2) format("woff2")}
@font-face{font-family:"Figtree";font-style:normal;font-weight:600;font-display:swap;src:url(../fonts/figtree-latin-600-normal.woff2) format("woff2")}
@font-face{font-family:"DM Mono";font-style:normal;font-weight:400;font-display:swap;src:url(../fonts/dm-mono-latin-400-normal.woff2) format("woff2")}
/* Mandy's Deli. Tokens sampled from the shop's own world: pastry cream, crust amber,
   the navy shop front, the walnut sign board, the neon tube. */
:root{
  --canvas:#f6efe3;
  --panel:#fbf6ec;
  --ink:#1d2333;
  --text-primary:#1d2333;
  --text-secondary:#5a5347;
  --accent:#d9962b;
  --accent-hover:#c07f1c;
  --accent-text:#824e06;          /* amber tuned for text on cream: 6:1 on cream, and 4.9:1 or more where the
                                     page-wide glow warms the cream (it was #9a5f0a: 3.8:1 there, audit F077) */
  --accent-muted:rgba(217,150,43,.18);
  --neon:#ffd166;
  --walnut:#5c4124;
  --walnut-deep:#3d2a16;
  --line:rgba(29,35,51,.14);
  --line-strong:rgba(29,35,51,.55); /* interactive borders, the only edge of a field: 3.5:1 on cream, 3.7:1 against
                                     the panel. At .42 it was 2.5:1, whatever this comment said (audit F079). */
  --focus:var(--ink);             /* the keyboard focus ring; the neon's yellow on dark ground, below */
  /* viewport-fit=cover lets the page run under a sideways iPhone's notch, so every inset keeps text clear of it
     (env() is 0 everywhere else, which leaves these values as they were) */
  --gutter:max(16px,5vw,env(safe-area-inset-left) + 16px,env(safe-area-inset-right) + 16px);
  --ease-out:cubic-bezier(.2,.7,.2,1);
  --ease-inout:cubic-bezier(.65,0,.35,1);
  --tshadow:0 1px 2px rgba(5,5,10,.95),0 3px 12px rgba(5,5,10,.78),0 10px 44px rgba(5,5,10,.8);
  --display:"Fraunces",Georgia,serif;
  --body:"Figtree",system-ui,sans-serif;
  --mono:"DM Mono",ui-monospace,Menlo,monospace;
}
*,*::before,*::after{box-sizing:border-box}
/* html only: the root's overflow goes to the viewport. On body, Safari before 16 (no clip) would fall back
   to hidden, make body the sticky stage's scroller, and the film would scroll away instead of pinning. */
html{overflow-x:hidden;overflow-x:clip}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
/* Whatever the browser scrolls into view (a focused control, a #fragment, a notice) lands clear of the nav:
   keyboard focus had scrolled FAQ questions, Find us buttons and form fields in under it (audit 2026-09-28,
   F075). The browser scrolls the focused control, not its wrapper, so this is the one place for it. The nav is
   64 to 81px tall across widths, and the scripts measure it into --navh, so a jump lands flush under it: a
   fixed 88px had left a strip of the section above showing (regression round 2). Without them, 88px clears
   every height. A control keeps room above it for its focus ring, and what the form brings into view (a notice,
   a field's label, the line above the fields) the same room below the nav's edge. */
html{scroll-padding-top:var(--navh,88px)}
:is(a,button,summary,input,select,textarea,label,.notice,.need){scroll-margin-top:12px}
body{margin:0;background:var(--canvas);color:var(--text-primary);font-family:var(--body);font-size:17px;line-height:1.55;animation:pagein .9s var(--ease-out) both}
@keyframes pagein{from{opacity:0}to{opacity:1}}
/* the fade-in is the home page's opening; on the buffet form and WordPress's own pages it only made the first
   paint wait another .9 s on a slow connection (audit 2026-09-28, F094; the council's item 33) */
body.page-buffet,body.page-plain{animation:none}
img{max-width:100%;height:auto;display:block}
a{color:inherit}
h1,h2,h3{font-family:var(--display);font-weight:600;line-height:1.05;margin:0;letter-spacing:-.01em}
h2{font-size:clamp(34px,4.6vw,60px)}
h3{font-size:clamp(22px,2.4vw,30px)}
/* balanced lines, so no headline ends on one word ("Rammed / full.", "Say the / word." at every desktop width,
   audit 2026-09-28, F096); browsers without it wrap as before */
h2,h3{text-wrap:balance}
p{margin:0}
.kicker{font-family:var(--mono);font-size:12px;letter-spacing:.16em;text-transform:uppercase;color:var(--accent-text)}
/* Find us's kicker is its section's heading, so heading navigation reaches the address and hours (audit 2026-09-28,
   F103); it looks as it did. The quotes' heading is for screen readers only (.sr). */
h2.kicker{font-weight:400;line-height:inherit}
.lede{font-size:clamp(18px,1.6vw,21px);color:var(--text-secondary);max-width:58ch}
.em{font-style:italic;color:var(--accent-text)}
.nw{white-space:nowrap} /* keeps a phrase such as "· Birchington", an address or a phone number on one line (F091) */
/* the hidden attribute always wins: .enquiry{display:grid} was overriding it, so the empty form stayed on
   screen under "Sent." and invited a second send (T-020) */
[hidden]{display:none!important}
.sr{position:absolute!important;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.skip{position:absolute;left:12px;top:-60px;z-index:100;background:var(--ink);color:#fff;padding:10px 14px;border-radius:8px;transition:top .2s}
.skip:focus{top:12px}
:focus-visible{outline:3px solid var(--focus);outline-offset:3px;border-radius:4px}
/* The ring must stand 3:1 from what it sits on (WCAG 1.4.11). Amber was 2.2:1 on cream (audit 2026-09-28,
   F076), and on the catering block's textured walnut 2.9:1; ink is 13.7:1 on cream, and the neon's yellow
   6.5:1 on walnut and 9.5:1 on the dark walnut. The skip link straddles the film or the cream nav and the
   dark page head below it, so its ring sits on a halo of its own ink wherever it is. Measured pixel by pixel
   on every control by the a11y mode of build/test/cdp.mjs. */
.stage,.nav:not(.solid),.find,.enquire,.pagehead,.foot,.notice--sent,.skip{--focus:var(--neon)}
.skip:focus-visible{box-shadow:0 0 0 7px var(--ink)}

/* One environment: a fixed warm-light drift behind everything, 70 s cycle. */
.hero-on .env{animation-play-state:paused} /* behind the film it drew for nothing (F070); site.js sets hero-on */
.env{position:fixed;inset:-10%;z-index:-1;pointer-events:none;background:
  radial-gradient(60% 50% at 20% 20%,rgba(217,150,43,.16),transparent 70%),
  radial-gradient(50% 45% at 85% 80%,rgba(92,65,36,.14),transparent 70%);
  animation:envdrift 70s var(--ease-inout) -23s infinite alternate}
@keyframes envdrift{from{transform:translate3d(-2%,-1%,0) scale(1)}to{transform:translate3d(2%,2%,0) scale(1.04)}}

/* Buttons */
.btn{display:inline-block;font-family:var(--body);font-weight:600;font-size:16px;padding:14px 22px;border-radius:999px;background:var(--accent);color:var(--ink);text-decoration:none;border:2px solid transparent;transition:transform .35s var(--ease-out),background .35s var(--ease-out),box-shadow .35s var(--ease-out)}
/* hover effects only where hover exists: on a touch screen a tap leaves :hover stuck on, a button lifted */
@media (hover:hover){.btn:hover{background:var(--accent-hover);transform:translateY(-2px);box-shadow:0 10px 24px -12px rgba(154,95,10,.6)}}
.btn--ghost{background:transparent;border-color:var(--line-strong);color:var(--ink)}
@media (hover:hover){.btn--ghost:hover{background:var(--panel);border-color:var(--ink);box-shadow:none}}
.btn--light{background:transparent;border-color:rgba(255,255,255,.6);color:#fff}
.btn--cream{background:var(--canvas);color:var(--ink)}
/* Facebook's own blue, #0866ff (its brand colour since 2023): white on it is 4.8:1, where the older #1877f2
   gives 4.2:1 and fails for text this size */
.btn--fb{display:inline-flex;align-items:center;gap:10px;background:#0866ff;color:#fff}
.btn--fb svg{width:20px;height:20px;flex:none;fill:currentColor}
@media (hover:hover){.btn--fb:hover{background:#0753d4;box-shadow:0 10px 24px -12px rgba(8,102,255,.65)}}
@media (hover:hover){.btn--cream:hover{background:#fff;box-shadow:0 10px 24px -12px rgba(0,0,0,.5)}}
.nav-actions{display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:flex-end}
.nav:not(.solid) .btn--ghost{border-color:rgba(255,255,255,.6);color:#fff}
@media (hover:hover){.nav:not(.solid) .btn--ghost:hover{background:rgba(255,255,255,.12);border-color:#fff}} /* the cream hover fill put its white label on cream */
.cafe .row,.hampers .row{display:flex;gap:12px;flex-wrap:wrap;margin-top:clamp(28px,4vw,44px)}
.cafe .row,.hampers .row{margin-top:24px}
@media (hover:hover){.btn--light:hover{background:rgba(255,255,255,.12);box-shadow:none}}
/* A press shows, after any hover, where a tap had shown nothing at all (F094); the grey tap flash of iOS goes
   where the control draws its own */
.btn:active{transform:translateY(1px) scale(.98);transition-duration:.08s}
.btn,.slides .dots button{-webkit-tap-highlight-color:transparent}
@media (pointer:coarse){.btn{min-height:44px;display:inline-flex;align-items:center;justify-content:center}}
/* Every other link a finger meets is a 44px target too (audit 2026-09-28, F093): the nav's mark and links and the
   Find us phone number were 17 to 34px tall (the footer's links are buttons now). Padding with a matching negative margin, so
   nothing moves; checked on both pages at 390x844, 1024x768 and 932x430 by the a11y mode. */
@media (pointer:coarse){
  .nav .mark{min-height:44px}
  .nav ul a{display:inline-block;padding:13px 6px;margin:-13px -6px}
  .nav ul a::after{left:6px;right:6px;bottom:7px}
  .find dd a{display:inline-block;padding:10px 0;margin:-10px 0}
}

/* Nav */
.nav{position:fixed;top:0;left:0;right:0;z-index:50;display:flex;flex-wrap:wrap;row-gap:8px;align-items:center;justify-content:space-between;gap:16px;padding:14px var(--gutter);color:#fff;transition:background .5s var(--ease-out),color .5s var(--ease-out),box-shadow .5s var(--ease-out)}
/* Near-opaque (audit 2026-09-28, F078): at .86 the dark sections and the film's white settle showed through as
   ghost text and took the mark's words to 3.5:1. The prefixed blur is for iOS Safari 16 and 17, which ignore
   the unprefixed one. It turns solid as the film starts to leave, not after: a clear nav over the settle as it
   scrolls up would lay white words on white words. */
.nav.solid{background:rgba(246,239,227,.96);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);color:var(--ink);box-shadow:0 1px 0 var(--line)}
.nav .mark{display:flex;align-items:center;gap:10px;text-decoration:none;color:var(--neon)}
.nav.solid .mark{color:var(--accent-text)}
.nav .mark svg{height:34px;width:auto;filter:drop-shadow(0 0 6px rgba(255,209,102,.55))}
.nav.solid .mark svg{filter:none}
.nav .mark span{font-family:var(--mono);font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:currentColor}
.nav ul{display:flex;gap:26px;list-style:none;margin:0;padding:0}
.nav ul a{text-decoration:none;font-weight:600;font-size:15px;opacity:.9;position:relative;text-shadow:0 1px 3px rgba(5,5,10,.6)}
.nav.solid ul a{text-shadow:none}
.nav:not(.solid) .mark span,.nav:not(.solid) .btn--ghost{text-shadow:0 1px 3px rgba(5,5,10,.6)} /* as the links, over the hero */
.nav ul a::after{content:"";position:absolute;left:0;right:0;bottom:-6px;height:2px;background:currentColor;transform:scaleX(0);transform-origin:left;transition:transform .35s var(--ease-out)}
@media (hover:hover){.nav ul a:hover::after{transform:scaleX(1)}}
.nav ul a:active{opacity:.6}
.nav .btn{padding:10px 18px;font-size:15px}
/* The nav fits on one line at every width (audit 2026-09-28, F049, F050, F063): the home page's actions are
   "Call the shop" and "Plan a buffet" (the list has "Find us"), and on the buffet page the ghost "Find us"
   goes wherever the list shows it. From 861 to 1023px the list fits only without the mark's words; under
   861 there is no list; up to 640 the nav is compact and the call is a "Call" pill; sideways phones get no
   list and a thin bar (F065). Checked link by link by the nav mode of build/test/cdp.mjs. */
.nav .btn,.nav .mark span,.nav ul a{white-space:nowrap}
@media (min-width:861px) and (max-width:1023.98px){.nav .mark span{display:none}}
@media (max-width:860.98px){.nav ul{display:none}} /* .98: max-width:860px and min-width:861px both missed 860.5, which zoom and display scaling reach (a 1076px window at 125%), and the nav showed everything at once and ran off the edge (code review of 2026-10-02); 520 likewise */
@media (min-width:861px){.nav-actions .findus{display:none}}
@media (max-width:640px){.nav{padding:10px max(16px,env(safe-area-inset-right)) 10px max(16px,env(safe-area-inset-left))}.nav .mark svg{height:28px}.nav .mark span{display:none}.nav .btn{padding:9px 14px;font-size:14px}.nav .call-long{display:none}}
@media (max-width:520.98px){.nav-actions .findus{display:none}}
/* A 390px phone zoomed to 150% is 260px wide, where "Plan a buffet" ran 18px off the screen. Under 300px the
   mark, the gaps and the buttons' sides shrink so all three still fit on one line, 44px tall. */
@media (max-width:300px){.nav{gap:10px}.nav .mark svg{height:22px}.nav .btn{padding:9px 10px}.nav-actions{gap:6px}}
@media (orientation:landscape) and (max-height:500px){.nav ul{display:none}.nav{padding-top:6px;padding-bottom:6px}.nav .btn{padding:8px 14px}}
/* With the list gone on a sideways phone, the buffet page's ghost "Find us" stays at every width: from 861px it
   had gone with the list's, leaving a 896 or 932px wide phone held sideways only the logo to get home by */
@media (orientation:landscape) and (max-height:500px) and (min-width:521px){.nav-actions .findus{display:inline-block}}

/* ---------- Hero: a tall pinned region, a sticky stage ---------- */
.hero{position:relative;height:520vh;background:var(--walnut-deep)}
/* The stage fills the large viewport (lvh). Both heights are constant while a phone's toolbar collapses,
   so progress (hero minus stage) never shifts under the thumb, and the film runs under the toolbar with no
   gap. Captions sit inside the small viewport (svh), clear of the toolbar. vh first for older browsers,
   where vh is already the large viewport. The static hero's image comes from the head style assemble.py writes. */
.stage{position:sticky;top:0;height:100vh;overflow:hidden;background:var(--walnut-deep);color:#fff}
/* The film's last frame fades into the cream page rather than ending on a straight edge (F094). Film only: over
   the static hero it would wash out the buttons at its foot. At most 8vh, clear of the settle on short screens. */
html.scrub .hero::after{content:"";position:absolute;left:0;right:0;bottom:0;height:clamp(24px,8vh,72px);pointer-events:none;background:linear-gradient(to bottom,rgba(246,239,227,0),var(--canvas))}
@supports (height:1lvh){.hero{height:520lvh}.stage{height:100lvh}}
/* Touch pacing. A swipe is measured in pixels, not viewports, so on touch screens the pinned range is a fixed
   3000px whatever the screen's height: six of a reader's ~580px swipes until the page shows. It was 7000px,
   which no hard fling could skip a caption in, and it took Sam 12 swipes on a phone; he asked for 5 to 7
   (2026-10-01). There the captions follow on with no gap, each about a quarter of the range, wider than a
   reader's swipe, so a swipe cannot pass one; a hard ~1200px fling may pass some. They change by time
   (site.js), so wherever any swipe stops a whole caption shows (build/test/cdp.mjs touch,
   docs/design-package.md section 20). No scroll-snap: it bent flings by up to
   800px. A fixed range also keeps progress through a rotation. */
@media (pointer:coarse){
  .hero{height:calc(100vh + 3000px)}
  @supports (height:1lvh){.hero{height:calc(100lvh + 3000px)}}
}
.stage .poster,.stage video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:50% 50%}
.stage .poster{background:center/cover no-repeat} /* the static hero's ending frame, from the head style */
.stage .poster img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover} /* the film's poster, placed by site.js */
html:not(.scrub) .stage .poster img{display:none}
.stage video{opacity:0;transition:opacity .8s var(--ease-out);will-change:transform;transform:translateZ(0)}
.stage video.on{opacity:1}
/* The top of the scrim carries the nav while it is clear over the hero: dark enough under the nav's
   height for its 12px neon words and white links at 4.5:1, and its mark at 3:1, over the palest pastry
   (measured with the band text by the audit mode of build/test/cdp.mjs), then gone by 180px. */
.stage{--scrim-top:linear-gradient(to bottom,rgba(10,10,18,.72) 0,rgba(10,10,18,.66) 56px,rgba(10,10,18,0) 180px)}
.stage .scrim{position:absolute;inset:0;pointer-events:none;background:var(--scrim-top),radial-gradient(ellipse 120% 90% at 50% 45%,rgba(10,10,18,0) 35%,rgba(10,10,18,.62) 100%)}
/* pastry flakes, whisper level, hero only */
.flakes{position:absolute;inset:0;pointer-events:none;overflow:hidden;-webkit-mask-image:linear-gradient(to bottom,transparent 0,transparent 64px,#000 150px);mask-image:linear-gradient(to bottom,transparent 0,transparent 64px,#000 150px)} /* they drift in below the nav, never across its words */
.flakes i{position:absolute;top:-4%;width:5px;height:3px;border-radius:50%;background:rgba(255,224,160,.55);animation:flake 14s linear infinite;opacity:0}
@keyframes flake{0%{transform:translate3d(0,0,0) rotate(0);opacity:0}8%{opacity:.7}92%{opacity:.5}100%{transform:translate3d(var(--dx,20px),108vh,0) rotate(160deg);opacity:0}}
.stage.rest .flakes i{animation-play-state:paused}

/* Loading ring: the film's download progress, on every screen */
.ring{position:absolute;left:50%;bottom:max(26px,env(safe-area-inset-bottom) + 12px);width:36px;height:36px;margin-left:-18px;color:var(--neon);transform:rotate(-90deg);opacity:.9;transition:opacity .6s}
.ring circle{transition:stroke-dashoffset .15s linear}
.stage.video-ready .ring,.stage.no-film .ring{opacity:0} /* no-film: the film failed with nothing on screen */
/* short screens (sideways phones) download the film too, so they keep the ring, smaller and lower */
@media (max-height:560px){.ring{width:28px;height:28px;margin-left:-14px;bottom:max(12px,env(safe-area-inset-bottom) + 8px)}}
/* The stage is 100lvh, so with a phone's toolbar showing its foot is below the window or behind the bar: the ring and
   the cue are lifted by that strip, as the upright captions and ring are (code review of 2026-10-02: on Chrome for
   Android the cue sat in the 56px under the screen, so a phone visitor never saw it, and sideways the ring did too).
   On a desktop svh and lvh are the same, and nothing moves. */
@supports (height:1svh){@media (max-height:560px){.ring{bottom:calc(100% - 100svh + max(12px,env(safe-area-inset-bottom) + 8px))}}}
/* The scroll cue (audit 2026-09-28, F048): once the film is ready and the visitor has not scrolled, a word
   and a chevron where the ring was, fading in only once the ring has gone; gone on the first scroll, back
   at the top (site.js sets cue-on). Its own soft scrim keeps the 11px word at 4.5:1 over the palest frame
   (the audit mode measures it). Not in the static hero, so never under reduced motion. */
.cue{position:absolute;left:50%;bottom:max(18px,env(safe-area-inset-bottom) + 10px);transform:translateX(-50%);display:flex;flex-direction:column;align-items:center;gap:5px;color:#fff;font-family:var(--mono);font-size:11px;line-height:1;letter-spacing:.22em;text-transform:uppercase;text-shadow:0 1px 3px rgba(5,5,10,.9);opacity:0;transition:opacity .5s var(--ease-out);pointer-events:none}
.cue span{margin-right:-.22em} /* the letter-spacing after the last letter, so the word sits centred over the chevron */
.cue::before{content:"";position:absolute;inset:-80% -90%;z-index:-1;background:radial-gradient(ellipse 50% 50% at 50% 50%,rgba(5,5,10,.8) 0,rgba(5,5,10,.72) 45%,rgba(5,5,10,.3) 75%,rgba(5,5,10,0) 100%)}
.cue svg{width:14px;height:9px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;animation:cue 2.4s var(--ease-inout) infinite}
@keyframes cue{0%,100%{transform:translateY(0)}50%{transform:translateY(4px)}}
.stage.video-ready.cue-on .cue{opacity:1;transition-delay:.6s}
.stage.rest .cue svg{animation-play-state:paused}
html:not(.scrub) .cue{display:none}
@media (max-height:560px){.cue{bottom:max(10px,env(safe-area-inset-bottom) + 6px)}}
@supports (height:1svh){.cue{bottom:calc(100% - 100svh + max(18px,env(safe-area-inset-bottom) + 10px))}@media (max-height:560px){.cue{bottom:calc(100% - 100svh + max(10px,env(safe-area-inset-bottom) + 6px))}}}

/* Caption bands. Opacity and --k are written by JS, delta-gated. */
.band{position:absolute;max-width:min(40vw,34ch);padding:2vh 2vw;text-shadow:var(--tshadow);opacity:0;will-change:opacity}
.band .btn{text-shadow:none}
/* invisible until site.js shows them: before it ran, the end caption's buttons took a tap at opacity 0 (verification
   of 2026-10-01). site.js sets each link's own pointer-events from then on. */
html.scrub .band :is(a,button){pointer-events:none}
.band::before{content:"";position:absolute;inset:-48% -52%;pointer-events:none;z-index:-1;opacity:calc(.25 + .75*var(--k,1));background:radial-gradient(ellipse 50% 50% at 50% 50%,rgba(5,5,10,var(--peak,.78)) 0%,rgba(5,5,10,calc(var(--peak,.78)*.94)) 56%,rgba(5,5,10,calc(var(--peak,.78)*.42)) 80%,rgba(5,5,10,0) 100%)}
.band .kicker{color:var(--neon);text-shadow:0 1px 3px rgba(5,5,10,.9);margin-bottom:12px;display:block}
.band h1,.band .line{font-family:var(--display);font-weight:600;line-height:1.02;letter-spacing:-.01em;margin:0}
.band h1{font-size:clamp(44px,7vw,108px)}
.band .line{font-size:clamp(28px,3.6vw,72px)} /* grows past 52px above 1440 (F061); the portrait and short-screen rules below set their own */
.band--lane{left:max(5vw,env(safe-area-inset-left) + 16px);top:50%;transform:translateY(-50%)}
.band--logo{max-width:min(44vw,600px)}
.band--logo h1{margin:0 0 18px;line-height:0}
.band--logo .kicker{margin:0;font-size:13px}
.neon--hero{display:block;width:100%;height:auto;color:var(--neon);fill:none;stroke:currentColor;opacity:calc(.15 + .85*var(--k,0));filter:drop-shadow(0 0 8px rgba(255,209,102,calc(.75*var(--k,0)))) drop-shadow(0 0 28px rgba(255,180,60,calc(.5*var(--k,0))))}
.neon--hero path{stroke-dasharray:1;stroke-dashoffset:clamp(0,1 - (var(--k,0)*8 - var(--n,0)),1)}
.neon--hero path:nth-child(1){--n:0}.neon--hero path:nth-child(2){--n:1}.neon--hero path:nth-child(3){--n:2}.neon--hero path:nth-child(4){--n:3}.neon--hero path:nth-child(5){--n:4}.neon--hero path:nth-child(6){--n:5}.neon--hero path:nth-child(7){--n:6}.neon--hero path:nth-child(8){--n:7}
.band--lane2{left:max(5vw,env(safe-area-inset-left) + 16px);top:52%;transform:translateY(-50%)}
.band--mid{left:max(8vw,env(safe-area-inset-left) + 16px);top:50%;transform:translateY(-50%);max-width:min(46vw,30ch);--peak:.8}
.band--settle{left:50%;top:50%;transform:translate(-50%,-50%);max-width:min(80vw,40ch);text-align:center;--peak:.82;--ks:clamp(0,(var(--k,0) - .66)*4,1);--kb:clamp(0,(var(--k,0) - .78)*5,1)}
.band--settle::before{inset:-64% -50%;background:radial-gradient(ellipse 50% 50% at 50% 50%,rgba(5,5,10,var(--peak)) 0%,rgba(5,5,10,calc(var(--peak)*.94)) 56%,rgba(5,5,10,calc(var(--peak)*.42)) 80%,rgba(5,5,10,0) 100%)}
.band--settle .sub{font-size:clamp(17px,1.5vw,21px);margin:18px auto 0;max-width:38ch;opacity:var(--ks,0);transform:translateY(calc((1 - var(--ks,0))*10px))}
.band--settle .row{display:flex;gap:12px;justify-content:center;flex-wrap:wrap;margin-top:26px;opacity:var(--kb,0);transform:translateY(calc((1 - var(--kb,0))*12px))}
.band--settle .btn{text-shadow:none}

/* ---------- Portrait: phones and tablets held upright ----------
   The portrait films are centred crops with no calm lane, so bands one to three move to the lower part
   of the small viewport, over a bottom gradient added to the base scrim plus each band's own scrim, and
   the settle sits centred in what the visitor can see. Lines are capped in em on the text itself. The
   bottom offset keeps text above the steel rim's highlight along the bottom edge in the opening seconds
   (the portrait encode notes) and above the home bar. */
@media (orientation: portrait){
  html.scrub .stage .scrim{background:var(--scrim-top),linear-gradient(to top,rgba(5,5,10,var(--foot,.8)) 0,rgba(5,5,10,calc(var(--foot,.8)*.78)) 24%,rgba(5,5,10,calc(var(--foot,.8)*.38)) 42%,rgba(5,5,10,0) 60%),radial-gradient(ellipse 120% 90% at 50% 45%,rgba(10,10,18,0) 35%,rgba(10,10,18,.62) 100%)}
  .band:not(.band--settle){left:var(--gutter);right:var(--gutter);top:auto;bottom:max(64px,10vh);max-width:none;transform:none;padding:0}
  .stage{--foot:.66}
  .band:not(.band--settle){--peak:.7}
  .band:not(.band--settle)::before{inset:-70% -26% -55%}
  .band--logo h1{width:min(78vw,480px);margin:0 0 14px}
  .band--logo .kicker{font-size:12px;letter-spacing:.14em;max-width:30em}
  .band .line{font-size:clamp(30px,8.2vw,48px);max-width:12em;text-wrap:balance}
  .band.band--settle{left:50%;right:auto;top:48%;bottom:auto;width:calc(100% - 2*var(--gutter));max-width:34rem;padding:0;transform:translate(-50%,-50%);--peak:.74}
  .band--settle .line{font-size:clamp(38px,10.5vw,64px);max-width:none;margin:0 auto}
  .band--settle .sub{font-size:clamp(17px,2.4vw,20px);max-width:24em;text-wrap:balance}
  .ring{bottom:max(22px,3vh,env(safe-area-inset-bottom) + 12px)}
}
@supports (height:1svh){
  @media (orientation: portrait){
    .band:not(.band--settle){bottom:calc(100% - 100svh + max(64px,10svh))}
    .band.band--settle{top:48svh}
    .ring{bottom:calc(100% - 100svh + max(22px,3svh,env(safe-area-inset-bottom) + 12px))}
  }
}

/* ---------- Landscape under 1200px (tablets, landscape phones): the desktop lanes, with line caps in px
   rather than the body font's ch, and balanced wrapping, so no line ends on a lone word ---------- */
@media (orientation: landscape) and (max-width: 1199.98px){
  .band--lane2,.band--mid{max-width:min(46vw,460px)}
  .band .line,.band--settle .sub{text-wrap:balance}
}

/* ---------- Wide screens (sideways, 1200px and wider) and every sideways touch screen: the same lanes, capped
   in px, with balanced lines (audit 2026-09-28, F047). The caps had been the body font's ch with vw padding
   inside them, so the columns narrowed as screens widened: six and seven line stacks from 1440px, and the
   settle ending on a lone "it.". A sideways iPad Pro (1366x1024) had it worse than the smaller iPads. ---------- */
@media (orientation: landscape) and (min-width: 1200px), (orientation: landscape) and (pointer: coarse){
  .band{padding:2vh clamp(16px,2vw,28px)}
  .band--lane2,.band--mid{max-width:min(34vw,560px)}
  .band--settle{max-width:min(60vw,760px)}
  .band .line,.band--settle .sub{text-wrap:balance}
}
@media (orientation: landscape) and (pointer: coarse){.band--lane2,.band--mid{max-width:min(46vw,560px)}}
/* Above 1440 the type keeps growing, to 72px, and the lanes with it (F061): at 2560 the climax had been a
   334px block in a 2560px screen. The nav grows a step at 1920. */
@media (orientation: landscape) and (min-width: 1700px){.band--lane2,.band--mid{max-width:min(34vw,760px)}.band--settle{max-width:min(60vw,1000px)}}
@media (min-width: 1920px){.nav ul a,.nav .btn{font-size:16px}.nav .mark svg{height:40px}}
/* On a wide screen the per-band scrims fall off gradually (F062): the plateau-then-drop read as a dark oval
   with a hard edge on the pale table at 1920 to 2560. Just as dark under the text; softer beyond it. */
@media (orientation: landscape) and (min-width: 1200px){
  .band::before,.band--settle::before{background:radial-gradient(ellipse 50% 50% at 50% 50%,rgba(5,5,10,var(--peak,.78)) 0%,rgba(5,5,10,calc(var(--peak,.78)*.92)) 38%,rgba(5,5,10,calc(var(--peak,.78)*.7)) 56%,rgba(5,5,10,calc(var(--peak,.78)*.42)) 72%,rgba(5,5,10,calc(var(--peak,.78)*.17)) 86%,rgba(5,5,10,0) 100%)}
  .band::before{inset:-70% -66%}
  .band--settle::before{inset:-84% -62%}
}

/* ---------- Landscape phones: the desktop lanes, compact ---------- */
@media (orientation: landscape) and (max-height: 500px){
  .band{padding:1vh 2vw}
  /* the band is wide enough for the kicker to run as two clean lines, and the neon keeps its old size: in a
     193px lane at 568x320 the kicker broke into three ragged lines and its last ran off the scrim (F051) */
  .band--logo{max-width:min(62vw,440px)}
  .band--logo h1{margin-bottom:10px;width:min(30vw,265px)} /* calc(min(34vw,300px) - 4vw) shrank past 880px wide: 146px at 3840 (code review of 2026-10-02) */
  .band--logo .kicker{text-wrap:balance}
  .band .line{font-size:clamp(24px,3.4vw,34px)}
  .band--lane2,.band--mid{max-width:min(46vw,420px)}
  .band--settle{top:calc(50% + 22px);max-width:min(84vw,600px)}
  .band--settle .line{font-size:clamp(28px,4.4vw,40px)}
  .band--settle .sub{font-size:16px;margin-top:10px}
  .band--settle .row{margin-top:14px}
  .band--settle .btn{padding:10px 18px}
  html .static-copy{padding-bottom:max(18px,4vh,env(safe-area-inset-bottom) + 12px)} /* html: these precede the static rules in the file */
  html .static-copy h1{font-size:clamp(28px,11vh,48px);max-width:16ch}
  html .static-copy p{font-size:16px;margin-top:8px}
  html .static-copy .row{margin-top:14px}
}

/* Text choreography: transform and opacity only, driven by --k. */
.w{display:inline-block;white-space:pre}
.c{display:inline-block}
/* (a) word-by-word rise */
.rise .w{--kc:clamp(0,(var(--k,0) - var(--th,0))*3,1);opacity:var(--kc);transform:translateY(calc((1 - var(--kc))*.35em))}
/* (b) drift-down: words start above and settle down, echoing the descent */
.drift .w{--kc:clamp(0,(var(--k,0) - var(--th,0))*2.8,1);opacity:var(--kc);transform:translateY(calc((1 - var(--kc))*-26px))}
/* (c) blur-to-sharp: two stacked copies crossfaded */
[data-blur]{position:relative} /* the line, not the band: a positioned band would leave the absolute layout */
.blur .soft{position:absolute;inset:0;filter:blur(10px);opacity:calc(1 - var(--k,0));pointer-events:none}
.blur .sharp{opacity:var(--k,0);transform:scale(calc(.97 + .03*var(--k,0)))}
/* mask breathing room for descenders */
.mask{overflow:hidden;padding:.12em 0 .18em;margin:-.12em 0 -.18em}

/* The static hero: reduced motion, a data saver or 2g, a failed film, or no JavaScript. The head script sets
   html.scrub for the film before the first paint and site.js keeps it live; without that class this layout
   shows. The reduced-motion query repeats it as a backup should the live switch ever miss a change. */
.static-copy{display:none;position:absolute;left:0;right:0;bottom:0;padding:0 var(--gutter) max(28px,6vh,env(safe-area-inset-bottom) + 16px);text-shadow:var(--tshadow);isolation:isolate} /* its own stacking context, or the scrim below paints under the poster (the sticky stage is the context) */
/* strong enough at the block's top edge for the 12px neon kicker over pale pastry (measured by the static modes of build/test/cdp.mjs) */
.static-copy::before{content:"";position:absolute;inset:auto 0 0 0;height:170%;pointer-events:none;z-index:-1;background:linear-gradient(to top,rgba(5,5,10,.86) 0,rgba(5,5,10,.8) 58%,rgba(5,5,10,.45) 80%,rgba(5,5,10,0))}
.static-copy .kicker{color:var(--neon);display:block;margin-bottom:10px}
.static-mark{width:min(62vw,320px);margin:0 0 14px;line-height:0}
.neon--static{display:block;width:100%;height:auto;color:var(--neon);fill:none;stroke:currentColor;filter:drop-shadow(0 0 6px rgba(255,209,102,.7)) drop-shadow(0 0 22px rgba(255,180,60,.45))}
.neon--static path{stroke-dasharray:1;stroke-dashoffset:1;animation:neondraw 1.3s var(--ease-inout) forwards}
.neon--static path:nth-child(2){animation-delay:.35s}.neon--static path:nth-child(3){animation-delay:.6s}.neon--static path:nth-child(4){animation-delay:.8s}.neon--static path:nth-child(5){animation-delay:.95s}.neon--static path:nth-child(6){animation-delay:1.05s}.neon--static path:nth-child(7){animation-delay:1.15s}.neon--static path:nth-child(8){animation-delay:1.25s}
@keyframes neondraw{to{stroke-dashoffset:0}}
@media (max-height:560px){.static-mark{display:none}}
.static-copy h1{font-size:clamp(38px,9vw,64px);max-width:12ch}
.static-copy p{margin-top:12px;max-width:34ch;font-size:17px}
.static-copy .row{display:flex;gap:10px;flex-wrap:wrap;margin-top:20px}
.static-copy .btn{text-shadow:none}
/* Under 320px (a 390px phone zoomed to 150% is 260px wide; a Galaxy Fold's cover screen 280px) the phrases kept on one
   line were wider than the column and cut off: "and plenty of it.", the hours. They are sized to the column
   instead, and nothing changes from 320px up (code review of 2026-10-02). The shop's headline, with "And the catering."
   on one line, has its own rule under 420px, with the shop's other rules. */
@media (max-width:319.98px){
  .static-copy h1{font-size:min(38px,(100vw - 32px)/7.5)}
  .static-copy p,.band--settle .sub{font-size:min(17px,(100vw - 32px)/15.3)}
}
html:not(.scrub) .hero,html:not(.scrub) .stage{height:100vh;height:100svh}
html:not(.scrub) .stage video,html:not(.scrub) .stage .band,html:not(.scrub) .stage .ring,html:not(.scrub) .flakes{display:none}
html:not(.scrub) .static-copy{display:block}
/* Very short screens (audit 2026-09-28, F052): the static hero grows with its copy, which starts below the
   nav, instead of pushing the copy up under the nav inside a screen-high stage (a small phone sideways with
   reduced motion, 568x320; a laptop at 400%, 320x256). Where there is room the copy still sits at the foot. */
@media (max-height: 420px){
  html:not(.scrub) .hero,html:not(.scrub) .stage{height:auto;min-height:100vh;min-height:100svh}
  html:not(.scrub) .stage{display:flex;flex-direction:column;justify-content:flex-end}
  html:not(.scrub) .static-copy{position:relative;padding-top:84px}
}
@media (max-height: 420px) and (orientation: landscape){html:not(.scrub) .static-copy{padding-top:64px}} /* the thin sideways nav */
@media (prefers-reduced-motion: reduce){
  html .hero,html .stage{height:100vh;height:100svh}
  html .stage video,html .stage .band,html .stage .ring,html .stage .cue,html .flakes{display:none}
  html .static-copy{display:block}
}

/* ---------- Below the fold ---------- */
.section{position:relative;padding:clamp(72px,10vw,140px) var(--gutter)}
.wrap{max-width:1200px;margin:0 auto}
.head{display:grid;gap:18px;max-width:64ch}
.head .kicker{display:block}

/* Entrances: choreography, container-prefixed so the cascade cannot cancel them */
.js .reveal .part{opacity:0;transform:translateY(20px)}
.reveal.in .part{opacity:1;transform:none;transition:opacity .8s var(--ease-out),transform .8s var(--ease-out)}
.reveal.in .part:nth-child(2){transition-delay:.09s}
.reveal.in .part:nth-child(3){transition-delay:.18s}
.reveal.in .part:nth-child(4){transition-delay:.27s}
.reveal.in .part:nth-child(5){transition-delay:.36s}
.reveal.in .part:nth-child(6){transition-delay:.45s}
/* retire the stagger once the entrance is done, at matching specificity */
.reveal.in.done .part:nth-child(n){transition-delay:0s!important}
/* keyboard focus inside a section shows it at once: Tab reached its links while the entrance still had them
   at opacity 0, the ring with them (audit 2026-09-28, F105) */
.reveal:focus-within .part{opacity:1;transform:none;transition:none}

/* One caption layout on every photo: the name, and the note under it. Side by side, a note that did not fit
   wrapped to a right-aligned second line on one card and not the next (F053, F054). */
.board-photo figcaption,.plate figcaption{font-family:var(--mono);font-size:12.5px;letter-spacing:.06em;color:var(--text-secondary);display:grid;justify-items:start;gap:2px}
.board-photo figcaption{padding:14px 16px 16px}
.board-photo figcaption b,.plate figcaption b{font-family:var(--display);font-weight:600;font-size:18px;letter-spacing:0;color:var(--ink)}
.section:not(.live) .steam i,.section:not(.live) .flicker::before{animation-play-state:paused}

/* Headlines (2026-10-03, the taste-skill review, Stanley): the same face, larger and tighter, so each section opens
   on one strong line; the leading leaves the italic descenders (y, g, p) clear of the line below */
.counter h2,.buffet .head h2,.how-head h2,.hampers h2{font-size:clamp(38px,5.2vw,72px);letter-spacing:-.025em;line-height:1.08}
/* at 38px, under 332px wide, "room? Say / the word." and "basket. Pick / what goes in." split their phrases; sized to
   the column they are two lines again (review of 2026-10-03) */
@media (max-width:340px){.buffet .head h2,.hampers h2{font-size:min(38px,(100vw - 32px)/7.9)}}

/* The shop: what Mandy's is, in four photographs (2026-09-30, Stanley: the first section is the whole shop, not only
   the pastry). The deli counter stands tall on the left; the café and the coffee sit side by side; the catering
   runs wide beneath them. The grid fills the wrap at every width.
   From 2026-10-03 (the taste-skill review) the headline has its words and the button under it, where a small
   paragraph had floated beside it, and the photographs are open: no box and no shadow round the words, the photo
   carrying the elevation, the words on the page under it. */
.counter{background:var(--canvas)}
.head--shop{max-width:none;gap:20px}
.head--shop .lede{max-width:52ch}
.head--shop .row{display:flex;gap:12px;flex-wrap:wrap;margin-top:2px}
/* "And the catering." is kept on one line, so on a narrow phone the headline is sized to the column */
@media (max-width:420px){.head--shop h2{font-size:min(38px,(100vw - 32px)/8.6)}}
/* each kept phrase drops whole to the next line and wraps inside itself only when it is wider than the column: with a
   reader's own text spacing (WCAG 1.4.12) nowrap had pushed "And the catering.", and the words under it, past the
   screen's edge at 375 to 400px (review of 2026-10-03) */
@media (max-width:420px){.head--shop h2 .nw{display:inline-block;white-space:normal}}
.bento{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(14px,2vw,24px);margin-top:clamp(36px,5vw,64px)}
/* A tile is a figure, which keeps the browser's 40px side margins: they squeezed cards to 72% of a phone's column
   and to 106px on a sideways phone, so every tile fills its column at every width (audit 2026-09-28, F053, F054). */
.tile{display:flex;flex-direction:column;min-width:0;margin:0}
/* the photos fill what the grid gives them; on desktop the tiles beside them set the heights */
.bento .tile .ph{position:relative;aspect-ratio:4/3;border-radius:20px;overflow:hidden;box-shadow:0 24px 48px -34px rgba(61,42,22,.55)}
.bento .tile .ph img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transform:scale(1.02);transition:transform 1.4s var(--ease-out)}
@media (hover:hover){.bento .tile:hover .ph img{transform:scale(1.06)}}
.bento .tile--deli .ph img{object-position:50% 28%} /* the food, not the fridge's base */
.counter .tile figcaption{padding:16px 2px 0;display:grid;justify-items:start;align-content:start;gap:6px;font-family:var(--body);font-size:15.5px;letter-spacing:0;line-height:1.5;color:var(--text-secondary)}
.counter .tile figcaption b{font-family:var(--display);font-weight:600;font-size:clamp(20px,1.7vw,24px);line-height:1.15;color:var(--ink)}
/* each tile says where its link goes; the arrow is decoration, with empty alternative text for screen readers */
.tile .go{margin-top:4px;display:inline-flex;align-items:center;gap:8px;font-weight:600;color:var(--accent-text);text-decoration:none}
.tile .go::after{content:"\2192";content:"\2192" / "";transition:transform .35s var(--ease-out)}
@media (hover:hover){.tile .go:hover{text-decoration:underline;text-underline-offset:3px}.tile .go:hover::after{transform:translateX(4px)}}
@media (pointer:coarse){.tile .go{min-height:44px}}
.tile .go:active{opacity:.7}
/* tablets and big phones sideways: two columns, the deli and the catering across both */
@media (min-width:521px){.bento{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.tile--deli,.tile--catering{grid-column:1/-1}.bento .tile--deli .ph,.bento .tile--catering .ph{aspect-ratio:16/9}}
/* from 640px the catering's words sit beside its photo, which at full width had stood taller than the screen allows */
@media (min-width:640px){.tile--catering{flex-direction:row}.bento .tile--catering .ph{aspect-ratio:auto;flex:1.15 1 0;min-height:240px}.counter .tile--catering figcaption{flex:1 1 0;align-content:center;padding:8px 0 8px clamp(20px,2.6vw,36px)}}
/* desktop: the deli counter two rows tall, the catering a wide tile with its words beside the photo */
@media (min-width:861px){
  .bento{grid-template-columns:minmax(0,1.15fr) minmax(0,1fr) minmax(0,1fr)}
  .tile--deli{grid-column:1;grid-row:1/span 2}
  .bento .tile--deli .ph{aspect-ratio:auto;flex:1 1 0;min-height:320px}
  .bento .tile--deli .ph img{top:-4%;height:116%} /* a little closer in: the counter's top rail and its base out of the frame */
  .tile--catering{grid-column:2/-1}
  .bento .tile--catering .ph{min-height:260px}
}

/* Regulars: one quote large, the other two beneath it and set in from the left (2026-10-03, the taste-skill review:
   three quotes of one size, staggered left, right, left). Their heading is kept for screen readers and heading
   navigation (F103) without a label over the quotes, which say what they are. */
.regulars{background:var(--panel);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
/* The browser's blockquote margins (1em, 50px on a desktop, and 40px to the left) had set the quotes at 40, 471 and
   264px, lining up with nothing (audit 2026-09-28, F086): every quote's margin is 0 and the grid places them. */
.quotes{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:clamp(32px,4.4vw,64px) clamp(20px,3vw,40px)}
.quote{position:relative;margin:0;grid-column:span 6;font-family:var(--display);font-style:italic;font-weight:600;font-size:clamp(24px,2.6vw,36px);line-height:1.12;padding-left:clamp(28px,4vw,56px);text-wrap:balance}
.quote--big{grid-column:1/-1;max-width:15ch;font-size:clamp(40px,6.6vw,96px);line-height:1.04;padding-left:clamp(36px,5vw,76px)}
.quote:nth-child(2){grid-column:3/span 5}
.quote:nth-child(3){grid-column:8/span 5}
@media (max-width:760px){.quote:nth-child(n){grid-column:1/-1}}
.quote .flicker{position:absolute;left:0;top:-.1em;font-style:normal;color:var(--accent);font-size:1.4em;line-height:1}
.quote .flicker::before{content:"“";position:absolute;inset:0;color:var(--neon);opacity:0;animation:flick 7s steps(1,end) -3s infinite;filter:blur(1px)}
@keyframes flick{0%,86%,100%{opacity:0}88%{opacity:.8}90%{opacity:.1}92%{opacity:.9}94%{opacity:0}}
.quote cite{display:block;font-family:var(--mono);font-style:normal;font-weight:400;font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--text-secondary);margin-top:14px}

/* Catering, the section the page funnels to */
.buffet{background:var(--canvas);overflow:hidden}
/* What goes on a platter, as tags under the lede (2026-10-03, the taste-skill review): five rows, each with a dot and
   a hairline above and below, had made a long list of a short one */
.tags{list-style:none;margin:6px 0 0;padding:0;display:flex;flex-wrap:wrap;gap:8px 10px}
.tags li{padding:8px 14px;border-radius:999px;background:var(--panel);border:1px solid var(--line);font-size:15px;line-height:1.3;color:var(--ink)}
/* The four platters in one row, every other one set lower, photographs open like the shop's; two by two from 900px
   down, on a phone too. A row to swipe on a phone was tried first: keyboard focus tucked it under the nav, where
   Chrome on a phone ignores the scroll margin of a focused scroller, and it hid three of the four photos. */
.plates{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:clamp(14px,2vw,24px);margin-top:clamp(36px,5vw,64px);align-items:start}
.plate{margin:0;min-width:0} /* a figure's 40px side margins (F053, F054) */
.plate .ph{border-radius:20px;overflow:hidden;aspect-ratio:4/5;box-shadow:0 24px 48px -34px rgba(61,42,22,.55)}
.plate:nth-child(1) .ph,.plate:nth-child(4) .ph{aspect-ratio:3/4}
/* the sandwich tray at 4:3, where its three handwritten labels, which the caption names, all fit the window (x 136 to
   1428 of 1920, with .labels-left): upright, only the middle one showed (F056) */
.plate:nth-child(2) .ph{aspect-ratio:4/3}
.plate:nth-child(even){margin-top:clamp(28px,4vw,64px)}
.plate .ph img{width:100%;height:100%;object-fit:cover;transform:scale(1.02);transition:transform 1.4s var(--ease-out)}
@media (hover:hover){.plate:hover .ph img{transform:scale(1.07)}}
.plate figcaption{padding:14px 2px 0}
/* two by two, the ploughman's board framed 4:3 beside the 4:3 tray, as the buffet page frames it: at 3:4 it left a hole
   up to 250px tall under the tray (review of 2026-10-03) */
@media (max-width:900px){.plates{grid-template-columns:repeat(2,minmax(0,1fr))}.plate:nth-child(1) .ph{aspect-ratio:4/3}.plate:nth-child(1) .ph img{object-position:center 40%}}
.plate figcaption span{text-wrap:pretty} /* "next to a tray of / cakes": no note ends on one word */
.board-photo{margin:clamp(28px,4vw,44px) 0 0;border-radius:20px;overflow:hidden;background:var(--panel);box-shadow:0 20px 50px -30px rgba(29,35,51,.45)}
.board-photo .ph{aspect-ratio:4/3;overflow:hidden}
.board-photo .ph img{width:100%;height:100%;object-fit:cover;object-position:center 40%}
.onplatter{list-style:none;margin:22px 0 0;padding:0;display:grid;gap:0}
.onplatter li{padding:12px 0;border-top:1px solid var(--line);font-size:17px;display:flex;gap:14px;align-items:baseline}
.onplatter li::before{content:"";flex:none;width:8px;height:8px;border-radius:50%;background:var(--accent);position:relative;top:-2px}
.onplatter li:last-child{border-bottom:1px solid var(--line)}
.enquire{margin-top:clamp(36px,5vw,64px);padding:clamp(24px,3.4vw,40px);border-radius:24px;background:var(--walnut);color:#fff;display:grid;grid-template-columns:1.2fr auto;gap:22px;align-items:center;position:relative;overflow:hidden}
.enquire::before{content:"";position:absolute;inset:0;background:center/cover;opacity:.1;mix-blend-mode:luminosity}
/* A faint texture from Mandy's own sausage roll photo, 38 KB, fetched once the section is near (F045): the
   260 KB generated film frame was fetched by every device at load, ahead of the hero's poster. At .1 the
   small print keeps 4.5:1 over its palest pixel; at the old .22 it read 3.5:1 (measured by layout mode). */
.buffet.in .enquire::before,html:not(.js) .enquire::before{background-image:url(../img/texture-pastry.jpg)}
.enquire>*{position:relative}
.enquire h3{font-size:clamp(24px,2.8vw,36px);max-width:22ch}
.enquire p{margin-top:8px;color:rgba(255,255,255,.88);max-width:44ch}
.enquire .row{display:flex;gap:12px;flex-wrap:wrap;justify-content:flex-end}
.enquire small{display:block;margin-top:10px;font-family:var(--mono);font-size:12px;letter-spacing:.06em;color:rgba(255,255,255,.88)} /* .7 and .82 left the small print at 4.5:1 over the texture's palest pixel, no margin (F077) */
@media (max-width:900px){.enquire{grid-template-columns:1fr}.enquire .row{justify-content:flex-start}}
/* on a phone the allergy line is a sentence to read, not a label: the body face at 14px, where 12px mono was
   the smallest type on the page with the footer's 11.7px (audit 2026-09-28, F095) */
@media (max-width:640px){.enquire small{font-family:var(--body);font-size:14px;letter-spacing:0}.foot small{font-size:14px}}

/* How a buffet happens (2026-10-03, the taste-skill review: three equal cards in a row, the order tickets of the same
   morning). The heading is held on the left while the three steps read down the right, each a large number in the
   headline's amber italic, the drawn motif in a warm disc and the step, the counter ticket's dashed tear between them.
   The motifs say what each step is: a form, a price tag, a bag, and the numbers are in a type face, not DM Mono (audit
   2026-09-28, F098): a phone between two carets and a board that read as a switch, in 1.6px strokes, and DM Mono's
   slashed zeros, which read the numbers as code. Drawn at 3.4 in a 64-unit box shown at 40px, on a phone too, the
   strokes are about 2.1px: the motif is smaller in its disc than it was alone, and the stroke thicker to keep it from
   thinning. */
.how{background:var(--panel);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.how-cols{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);gap:clamp(28px,6vw,96px);align-items:start}
.how-head{position:sticky;top:calc(var(--navh,88px) + 40px)}
.how-head h2{max-width:9ch}
.flow{list-style:none;margin:0;padding:0;counter-reset:step}
.flow-step{display:grid;grid-template-columns:auto auto minmax(0,1fr);align-items:center;gap:clamp(16px,2.4vw,32px);padding:clamp(22px,3vw,34px) 0;border-top:2px dashed rgba(130,78,6,.3)}
.flow-step:first-child{border-top:0;padding-top:0}
.flow-step:last-child{padding-bottom:0}
/* every row's number column one width, .62em holding the widest numeral: each step is its own grid, and its column
   had taken its own numeral's width, so the motifs and the words stepped 8 to 13px from row to row (review of
   2026-10-03) */
.flow-step::before{counter-increment:step;content:counter(step);min-width:.62em;font-family:var(--display);font-style:italic;font-weight:600;font-size:clamp(52px,5.4vw,80px);line-height:.85;color:var(--accent-text)}
.flow-step svg{display:block;width:60px;height:60px;padding:10px;border-radius:50%;background:var(--accent-muted);color:var(--accent-text);overflow:visible}
.flow-step svg path,.flow-step svg circle,.flow-step svg rect{fill:none;stroke:currentColor;stroke-width:3.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:1;stroke-dashoffset:0;transition:stroke-dashoffset 1.6s var(--ease-inout)}
/* undrawn only where the script will draw them: without it the discs had stayed empty (since the tickets) */
.js .flow-step svg path,.js .flow-step svg circle,.js .flow-step svg rect{stroke-dashoffset:1}
.how.in .flow-step svg path,.how.in .flow-step svg circle,.how.in .flow-step svg rect{stroke-dashoffset:0}
.how.in .flow-step:nth-child(2) svg *{transition-delay:.3s}
.how.in .flow-step:nth-child(3) svg *{transition-delay:.6s}
.flow-step p{font-size:clamp(18px,1.7vw,22px);line-height:1.45;color:var(--ink);text-wrap:balance;max-width:30ch}
@media (max-width:800px){.how-cols{grid-template-columns:1fr}.how-head{position:static}.how-head h2{max-width:none}}
@media (max-width:420px){.flow-step{gap:14px}.flow-step svg{width:52px;height:52px;padding:6px}}

/* The café: the photograph wide, its words on a panel laid over the photograph's edge (2026-10-03, the taste-skill
   review: the café and the hampers had been two mirrored splits, the same layout twice running) */
.overlap{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));align-items:center}
.overlap .ph{grid-column:1/span 8;grid-row:1;border-radius:22px;overflow:hidden;position:relative;box-shadow:0 30px 60px -36px rgba(29,35,51,.5)}
.overlap .ph img{width:100%;aspect-ratio:16/10;object-fit:cover}
.overlap-card{grid-column:7/-1;grid-row:1;position:relative;z-index:1;background:var(--panel);border:1px solid var(--line);border-radius:22px;padding:clamp(24px,3.4vw,48px);box-shadow:0 30px 60px -30px rgba(61,42,22,.38)}
.overlap-card h2{font-size:clamp(34px,4vw,56px);letter-spacing:-.02em;line-height:1.08}
.overlap-card .lede{margin-top:14px}
.overlap-card .row{display:flex;gap:12px;margin-top:24px}
@media (max-width:800px){.overlap{grid-template-columns:1fr}.overlap .ph,.overlap-card{grid-column:1;grid-row:auto}.overlap-card{margin:-56px 14px 0}}
/* The hampers: a split, the photo on the right */
.split2{display:grid;grid-template-columns:1fr 1fr;gap:clamp(28px,5vw,72px);align-items:center}
.split2.rev .ph{order:2}
.split2 .ph{border-radius:22px;overflow:hidden;position:relative;box-shadow:0 30px 60px -36px rgba(29,35,51,.5)}
.split2 .ph img{width:100%;height:100%;object-fit:cover;aspect-ratio:4/3} /* the hamper photo is the top of the original, above a sticker pasted on it (F055) */
.split2 .txt{max-width:52ch}
.split2 .txt .lede{margin-top:16px}
.cafe + .hampers{padding-top:0} /* two sections' padding read as a missing section between the photos (F068) */
.steam{position:absolute;left:12%;top:18%;width:60px;height:80px;pointer-events:none}
.steam i{position:absolute;bottom:0;left:50%;width:14px;height:40px;border-radius:50%;background:rgba(255,255,255,.55);filter:blur(6px);animation:steam 4.6s var(--ease-inout) infinite}
.steam i:nth-child(2){left:30%;animation-delay:-1.6s;width:10px}
.steam i:nth-child(3){left:70%;animation-delay:-3.1s;width:12px}
@keyframes steam{0%{transform:translate3d(-50%,0,0) scaleX(1);opacity:0}30%{opacity:.7}100%{transform:translate3d(-30%,-56px,0) scaleX(1.6);opacity:0}}
@media (max-width:800px){.split2{grid-template-columns:1fr}.split2.rev .ph{order:0}}

/* Questions: every answer open, set like a menu card, the hours and the call in the first cell (2026-10-03, the
   taste-skill review: five questions behind a click each, which hid the answers from anyone skimming). The hours
   and a call had been put beside the questions for the same reason they stay: a heading alone left the column
   empty (F085). */
.qa{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(32px,4vw,56px) clamp(24px,3.4vw,48px)}
.qa-head h2{font-size:clamp(34px,3.8vw,52px);letter-spacing:-.02em}
.qa-head .hours{margin-top:16px;color:var(--text-secondary)}
.qa-head .row{display:flex;gap:12px;flex-wrap:wrap;margin-top:22px}
.qa-item{padding-top:20px;border-top:2px solid var(--ink)}
.qa-item h3{font-size:clamp(20px,1.8vw,24px);line-height:1.2}
.qa-item p{margin-top:10px;color:var(--text-secondary);max-width:40ch}
@media (max-width:900px){.qa{grid-template-columns:repeat(2,minmax(0,1fr))}} /* six cells, three rows of two: with the first across both columns, the last question had stood alone */
@media (max-width:600px){.qa{grid-template-columns:1fr}}

/* Find us: address, hours, the neon lit large */
.find{background:var(--walnut-deep);color:#fff}
.find .kicker{color:var(--neon)}
.find .cols{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:clamp(28px,5vw,72px);align-items:center} /* minmax: the neon's width no longer widens its column and squeezes the photo (F066) */
.find .ph{border-radius:22px;overflow:hidden}
.find .ph img{aspect-ratio:4/5;object-fit:cover;width:100%}
.find dl{display:grid;grid-template-columns:auto 1fr;gap:10px 22px;margin:26px 0 0;font-size:17px}
.find dt{font-family:var(--mono);font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.65);padding-top:4px}
.find dd{margin:0}
.find dd a{color:#fff;text-decoration-color:var(--accent)}
.find .row{display:flex;gap:12px;flex-wrap:wrap;margin-top:26px}
.neon{color:var(--neon);width:min(420px,70vw,100%);height:auto;filter:drop-shadow(0 0 8px rgba(255,209,102,.7)) drop-shadow(0 0 26px rgba(255,180,60,.45))}
.neon path{stroke-dasharray:1;stroke-dashoffset:1;transition:none}
.neon.lit path{stroke-dashoffset:0;transition:stroke-dashoffset 1.8s var(--ease-inout)}
.neon.lit path:nth-child(2){transition-delay:.5s}.neon.lit path:nth-child(3){transition-delay:.8s}.neon.lit path:nth-child(4){transition-delay:1.05s}.neon.lit path:nth-child(5){transition-delay:1.2s}.neon.lit path:nth-child(6){transition-delay:1.35s}.neon.lit path:nth-child(7){transition-delay:1.5s}.neon.lit path:nth-child(8){transition-delay:1.65s}
.neon.lit{animation:hum 5s var(--ease-inout) -1.2s infinite}
.section:not(.live) .neon.lit{animation-play-state:paused} /* once seen, it hummed on off screen for good (F070) */
@keyframes hum{0%,100%{opacity:.92}50%{opacity:1}}
@media (max-width:800px){.find .cols{grid-template-columns:1fr}}

/* Sideways phones: every photo fits the screen below the nav, and less air between sections, where most photos
   had been taller than the screen and two sections' padding took 169px of a 315px view (F064, F065) */
@media (orientation:landscape) and (max-height:500px){
  .section{padding-top:clamp(40px,12vh,72px);padding-bottom:clamp(40px,12vh,72px)}
  .tile .ph,.plate .ph,.board-photo .ph,.overlap .ph img,.split2 .ph img,.find .ph img{max-height:calc(100vh - 96px);max-height:calc(100svh - 96px)}
  /* A definite width keeps the cap from travelling through aspect-ratio into the width: with width auto,
     Chrome narrowed a capped photo to 362px in its 760px card and left a cream panel beside it. Now the box
     keeps the card's width, is cut to the cap, and the photo (object-fit:cover) is cropped instead. */
  .tile .ph,.plate .ph,.board-photo .ph{width:100%}
}

/* Footer */
/* The footer (2026-09-30, Stanley): the sign again as the page signs off, and the two ways to reach the shop as
   buttons, a call and Facebook. The address and hours sit in Find us just above; the one line kept says where
   the photographs and the film came from, which stays until the rules on generated food images are checked
   (T-043). */
.foot{background:var(--walnut-deep);color:rgba(255,255,255,.78);padding:clamp(36px,5vw,56px) var(--gutter) clamp(28px,4vw,40px);border-top:1px solid rgba(255,255,255,.12);font-size:14px}
.foot .wrap{display:grid;gap:clamp(22px,3vw,32px)}
.foot-top{display:flex;align-items:center;justify-content:space-between;gap:20px 28px;flex-wrap:wrap}
.foot .foot-mark{display:inline-flex;color:var(--neon);padding:4px 0}
.foot-mark svg{height:clamp(44px,5vw,58px);width:auto;overflow:visible;filter:drop-shadow(0 0 6px rgba(255,209,102,.6)) drop-shadow(0 0 22px rgba(255,180,60,.35))}
.foot-actions{display:flex;gap:12px;flex-wrap:wrap}
.foot-actions .btn{display:inline-flex;align-items:center;gap:10px}
.foot .ico{width:18px;height:18px;flex:none;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.foot small{display:block;padding-top:clamp(18px,2.4vw,24px);border-top:1px solid rgba(255,255,255,.1);opacity:.7}
/* phones: the two buttons one under the other, each the full width, a big target for a thumb */
@media (max-width:520.98px){.foot-actions{flex-direction:column;width:100%}.foot-actions .btn{justify-content:center}}

/* Pause everything on hidden tabs */
body.paused *,body.paused *::before,body.paused *::after{animation-play-state:paused!important}

/* Reduced motion: honoured completely, final states shown, positional transforms kept, no smooth
   scrolling (a jump down the page would otherwise glide past the whole film) */
@media (prefers-reduced-motion: reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation:none!important;transition:none!important;transition-delay:0s!important}
  .js .reveal .part{opacity:1;transform:none}
  .flow-step svg *,.neon path,.neon--static path{stroke-dashoffset:0!important}
  .bento .tile .ph img,.bento .tile:hover .ph img,.plate .ph img,.plate:hover .ph img{transform:none} /* at the zooms' own specificity, or they win */
  .band--lane,.band--lane2,.band--mid{transform:translateY(-50%)}
  .band--settle{transform:translate(-50%,-50%)}
}

/* ---------- The buffet enquiry page ---------- */
.page-buffet .nav{position:sticky}
.pagehead{position:relative;padding:clamp(56px,8vw,110px) var(--gutter) clamp(36px,5vw,64px);color:#fff;background:var(--walnut-deep);overflow:hidden}
.pagehead::before{content:"";position:absolute;inset:0;background:url(../img/texture-pastry.jpg) center/cover;opacity:.28;mix-blend-mode:luminosity} /* a real photo, as the footer says (F045) */
.pagehead::after{content:"";position:absolute;inset:0;background:linear-gradient(to right,rgba(61,42,22,.92),rgba(61,42,22,.55))}
.pagehead .wrap{position:relative;z-index:1}
.pagehead .kicker{color:var(--neon);display:block;margin-bottom:14px}
.pagehead h1{font-size:clamp(44px,7vw,92px)}
.pagehead .em{color:var(--neon)}
.pagehead .lede{color:rgba(255,255,255,.85);margin-top:16px}
.formsec .cols{display:grid;grid-template-columns:1.3fr .9fr;gap:clamp(28px,5vw,72px);align-items:start}
.enquiry{display:grid;gap:18px;padding:clamp(20px,3vw,36px);border-radius:24px;background:var(--panel);border:1px solid var(--line);box-shadow:0 30px 60px -40px rgba(29,35,51,.4)}
.grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(230px,100%),1fr));gap:18px} /* side by side only where the longest option, "Collect from the shop", fits beside the select's arrow: from 861px it had been cut to "Collect from th" (code review of 2026-10-02) */
@media (max-width:300px){.enquiry{padding:8px}}
.field{display:grid;gap:8px}
.field label{font-weight:600;font-size:15px}
.field label small{display:block;font-weight:400;color:var(--text-secondary);font-size:13px;margin-top:2px}
.field input,.field select,.field textarea{font:inherit;font-size:17px;color:var(--ink);background:var(--canvas);border:1.5px solid var(--line-strong);border-radius:12px;padding:12px 14px;width:100%;transition:border-color .3s var(--ease-out),box-shadow .3s var(--ease-out)}
.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--accent-text);box-shadow:0 0 0 4px var(--accent-muted)}
.field.bad input,.field.bad select,.field.bad textarea{border-color:#a8321f;box-shadow:0 0 0 4px rgba(168,50,31,.14)}
@media (max-width:300px){.field input,.field select,.field textarea{font-size:16px;padding-left:10px;padding-right:10px}} /* under 300px (a phone zoomed to 150%) the fields' words at 16px, the least that keeps iOS from zooming in on a tap, so "Collect from the shop" still fits its select; after the rules above, which it overrides */
.field textarea{resize:vertical;min-height:120px}
/* what is wrong with a field, in words under it (buffet.js), so the red border is never the only sign (F006) */
.field-msg{margin:0;font-size:14px;font-weight:600;color:#8f2a17}
.notice:focus:not(:focus-visible){outline:none} /* focused after a round trip so it is read out, not to be clicked */
.hp{position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden}
.fine{font-size:14px;color:var(--text-secondary)}
.enquiry .row{display:flex;gap:12px;flex-wrap:wrap;align-items:center}
/* one height with the link buttons beside it: a button keeps line-height normal and lost .btn's 2px border here,
   so "Send to Mandy" stood 47px beside the 57px "Or call" (audit 2026-09-28, F092) */
.enquiry button.btn{cursor:pointer;line-height:inherit}
.enquiry button.btn:disabled{opacity:.7;cursor:progress;transform:none}
.notice{padding:clamp(20px,3vw,32px);border-radius:20px;margin-bottom:22px;animation:noticein .5s var(--ease-out)}
/* the notices' entrance has its own keyframes: they had been the home page's accordion's, and went out with it
   (review of 2026-10-03) */
@keyframes noticein{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
.notice h2{font-size:clamp(28px,3.4vw,44px)}
.notice p{margin-top:10px;max-width:56ch}
.notice a{color:inherit}
.notice--sent{background:var(--walnut);color:#fff}
/* "Sent." leads somewhere: home, or another enquiry (F022) */
.notice-links{display:flex;flex-wrap:wrap;gap:4px 24px;margin-top:16px}
.notice-links a{font-weight:600}
@media (pointer:coarse){.notice-links a{padding:10px 0}}
/* On phones and tablets the nav is the mark and a call button: a plain text link home as well (F022) */
/* The arrow has empty alternative text, so the link is named by its words alone: Chrome read the arrow aloud first
   (regression round 2). The first declaration is for browsers without the syntax. */
.pagehead .homelink{display:none}
@media (max-width:860.98px){.pagehead .homelink{display:inline-block;margin-bottom:12px;padding:11px 0;color:#fff;font-weight:600;font-size:15px}.pagehead .homelink::before{content:"\2039\00a0";content:"\2039\00a0" / ""}}
.notice--error{background:#f7e6e1;color:#5a1c10;border:1px solid rgba(168,50,31,.3)}
/* Without JavaScript the notices show from the address alone: both redirects end in #sent or #error (F011). */
.notice:target{display:block!important}
.notice--sent:target~.enquiry{display:none!important}
.aside{position:sticky;top:96px;display:grid;gap:16px}
@media (max-height:900px){.aside{position:static}} /* taller than a laptop's screen, it stuck with its foot out of view (F067) */
.aside .board-photo{margin:0}
.aside .kicker{display:block;margin-top:16px} /* with the list's own margin gone, the kicker sits nearer its list than the photo (F069) */
.aside .onplatter{margin-top:0}
@media (max-width:860.98px){.formsec .cols{grid-template-columns:1fr}.aside{position:static}.grid2{grid-template-columns:1fr}}

/* Slideshow on the buffet page: crossfade with a slow drift, transform and opacity only */
.slides .ph{position:relative;aspect-ratio:4/3;overflow:hidden;background:var(--walnut-deep);touch-action:pan-y} /* horizontal swipes are the slideshow's (F020) */
.slides .slide{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transform:scale(1.08);transition:opacity 1.2s var(--ease-inout),transform 0s 1.2s}
.slides .slide.on{opacity:1;transform:scale(1);transition:opacity 1.2s var(--ease-inout),transform 7s linear}
/* The sandwich platter's labels run from x 136 to 1428 of its 1920px width, and the caption names them: a
   centred 4:3 window (x 277 to 1642) cut "cheese and pickle" to a sliver. 18% keeps all three in any window
   from 4:3 up (layout mode measures it). */
.ph img.labels-left{object-position:18% 50%}
.slides figcaption b,.slides figcaption span{transition:opacity .35s var(--ease-out)}
.slides.swapping figcaption b,.slides.swapping figcaption span{opacity:0}
/* Each dot is a target of 24x24, or 44x44 on a touch screen (WCAG 2.2 target size), with the visible dot
   drawn small in its middle; padding and a negative margin keep the dots where the 10px ones sat. */
/* the row under the caption: the button that pauses the slideshow (WCAG 2.2.2, shown by buffet.js, which plays it),
   then the dots, both 24px targets, 44px on a touch screen */
.slides .slidebar{display:flex;align-items:center;padding:0 9px 9px;margin-top:-7px}
.slides .dots{display:flex;min-width:0} /* the six 44px dots narrow to fit the card under 345px on a touch screen, where the sixth was cut in half (about 40px each at 320) */
.slides .playpause{flex:none;display:grid;place-items:center;width:24px;height:24px;border:0;padding:0;background:none;cursor:pointer;border-radius:50%;color:var(--ink);-webkit-tap-highlight-color:transparent}
.slides .playpause svg{width:14px;height:14px;fill:currentColor}
.slides .playpause .i-play,.slides .playpause.paused .i-pause{display:none}
.slides .playpause.paused .i-play{display:inline}
.slides .playpause:active svg{transform:scale(.85)}
.slides .dots button{position:relative;width:24px;height:24px;border:0;padding:0;background:none;cursor:pointer;border-radius:50%}
/* an inactive dot is --line-strong, 3.6:1 on the card (F079) */
.slides .dots button::before{content:"";position:absolute;left:50%;top:50%;width:10px;height:10px;margin:-5px 0 0 -5px;border-radius:50%;background:var(--line-strong);transition:transform .3s var(--ease-out),background .3s var(--ease-out)}
.slides .dots button[aria-current="true"]::before{background:var(--accent);transform:scale(1.25)}
@media (hover:hover){.slides .dots button:hover::before{transform:scale(1.25)}} /* a tap would leave it stuck on a touch screen */
.slides .dots button:active::before{transform:scale(.8)}
@media (pointer:coarse){.slides .slidebar{padding:0 1px 1px;margin-top:-15px}.slides .playpause{width:44px;height:44px}.slides .playpause svg{width:18px;height:18px}.slides .dots button{width:44px;height:44px}.slides .dots button::before{width:14px;height:14px;margin:-7px 0 0 -7px}}
@media (prefers-reduced-motion: reduce){.slides .slide{transform:none}.slides .slide.on{transform:none}}

/* ---------- WordPress's own pages and the 404 (index.php, 404.php): the site's type, no film (F003) ---------- */
.page-plain .nav{position:sticky}
.page-plain{display:flex;flex-direction:column;min-height:100vh;min-height:100svh}.page-plain main{flex:1} /* the footer sits at the foot of a short page */
.prose .wrap{max-width:760px;overflow-wrap:break-word} /* a long email address or link in a Page breaks at the column's edge, where html's overflow-x:clip had cut it off */
.prose h1{font-size:clamp(38px,5.4vw,64px);margin-bottom:22px}
.prose h2{font-size:clamp(26px,3vw,36px);margin:1.6em 0 .5em}
.prose h3{margin:1.4em 0 .4em}
.prose p,.prose ul,.prose ol{margin:0 0 1em;max-width:68ch;line-height:1.6}
.prose ul,.prose ol{padding-left:1.3em}
.prose li{margin:.3em 0}
.prose a{color:var(--accent-text)}
.prose img{border-radius:14px;margin:1.2em 0}
/* What an editor adds to a Page stays inside the column at every width (code review of 2026-10-02): an iframe, video
   or embed at a fixed width (a 600px map ran 250px off a phone), a Classic-block caption with an inline pixel width,
   and the editor's figures, which lost core's reset with wp-block-library (functions.php) and kept the browser's 40px
   side margins (F053's fault, on the theme's own cards). A wide table scrolls inside its box. */
.prose :is(iframe,video,embed,object){max-width:100%}
.prose video{height:auto}
.prose .wp-caption{max-width:100%}
.prose :where(figure){margin:0 0 1em}
.prose .wp-block-table{overflow-x:auto}
.prose .kicker{display:block;margin-bottom:14px}
.prose .lede{margin-bottom:26px}
.prose .row{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:22px}
.prose .row a{color:inherit}
