/* ══════════════════════════════════════════════════════════════════════════════
   amireallyfree.no · AIRF-1 V2.3 · site.css
   Tokens verbatim from AIRF_SPLIT-Q_SPEC.md — no other hex on this page.
   Colour grammar is law: gold = self/identity · cyan = FREE / free / FREEDOM and the dot
   of the ? · nothing else is cyan. One orchestrated moment (the calibration), then
   stillness — with two exceptions ruled by JJ on 5 Sep 2026: the dot breathes, and the
   doors acknowledge a touch-screen visitor once. The Architect's Seal (lucid-seal.css) is
   a byte-mirrored estate component and carries its own canon tokens — the one exception.
   ══════════════════════════════════════════════════════════════════════════════ */
:root{
  --base:#09090f; --ink:#eef2ee;
  --gold-hi:#f5e6a3; --gold:#e7b73f; --gold-lo:#d4af37;
  --gold-grad:linear-gradient(178deg,#f5e6a3 0%,#e7b73f 50%,#d4af37 100%);
  --cyan:#22d3ee;
  --mono-dim:rgba(238,242,238,.55);
  --fd:'Orbitron',system-ui,sans-serif;
  --fs:'Cormorant Garamond',Georgia,serif;
  --fm:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
  /* THE BREATH · tune here: period of one breath, how small it gets, how dim it rests (V1.3: 3s, scale-driven) */
  --pulse-period:3s; --pulse-scale:.78; --pulse-low:.82;
  color-scheme:dark;
}

/* ── the film's face · self-hosted, subsetted, swap ── */
@font-face{font-family:'Orbitron';font-style:normal;font-weight:800;font-display:swap;src:url(fonts/orbitron-800.woff2) format('woff2');}
@font-face{font-family:'Cormorant Garamond';font-style:normal;font-weight:400;font-display:swap;src:url(fonts/cormorant-garamond-400.woff2) format('woff2');}
@font-face{font-family:'Cormorant Garamond';font-style:italic;font-weight:400;font-display:swap;src:url(fonts/cormorant-garamond-400i.woff2) format('woff2');}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(fonts/ibm-plex-mono-400.woff2) format('woff2');}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(fonts/ibm-plex-mono-500.woff2) format('woff2');}

/* ── quality floor ── */
*,*::before,*::after{box-sizing:border-box;}
html{background:var(--base);overflow-x:clip;-webkit-text-size-adjust:100%;}
body{margin:0;background:transparent;color:var(--ink);font:400 1rem/1.5 var(--fs);min-height:100svh;}   /* V2.2: html carries the base so the ripples canvas (z -1) can sit under the page */
a{color:inherit;}
:focus-visible{outline:2px solid var(--gold);outline-offset:4px;border-radius:2px;}
::selection{background:rgba(231,183,63,.28);color:var(--ink);}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;}
.beat{position:relative;display:grid;place-items:center;padding:0 5vw;}

/* ═══ BEAT ONE · THE QUESTION + THE LOGLINE ═════════════════════════════════
   min-height in svh; the bottom padding lifts the group above the geometric centre so
   browsers that overlay a bottom toolbar (iOS Safari and friends) still centre it optically. */
.beat-q{
  display:grid;grid-template-rows:minmax(7svh,1fr) auto minmax(14svh,1.5fr) auto;justify-items:center;align-items:start;
  min-height:100vh;min-height:100svh;padding:0 5vw calc(env(safe-area-inset-bottom,0px) + 3svh);
}
.hero{grid-row:2;display:grid;justify-items:center;row-gap:clamp(34px,8svh,88px);}   /* room to breathe between title and logline */
/* THE LEAD · a 1px gold line from the logline down to a small ?, right above the doors.
   Part of the calibration's cascade: it grows down after the logline arrives, then the ? appears. */
.lead{grid-row:3;align-self:stretch;width:1px;margin-top:clamp(28px,6svh,64px);
  background:linear-gradient(180deg,rgba(231,183,63,0) 0%,rgba(231,183,63,.62) 22%,rgba(231,183,63,.62) 100%);
  transform-origin:top;transition:transform 900ms cubic-bezier(.2,.8,.2,1) 350ms;}
.qmark{grid-row:4;margin-top:clamp(2px,.8svh,8px);padding:11px 16px;line-height:0;display:inline-block;transition:opacity 600ms ease 1150ms,transform 160ms ease;}
.qmark:hover,.qmark:focus-visible{transform:translateY(-2px);}
.qmark svg{height:clamp(22px,2.6vw,38px);width:auto;display:block;overflow:visible;}
.qs-bow{fill:none;stroke:url(#qg);stroke-width:142.5;stroke-linecap:butt;}
.qs-dot{fill:var(--cyan);}
.seq .lead{transform:scaleY(0);}
.seq .qmark{opacity:0;}
.lk{
  margin:0;text-align:center;
  font:800 clamp(2.6rem,9vw,8.5rem)/1 var(--fd);letter-spacing:1px;
  font-kerning:none;   /* the calibration splits glyphs into cells; no kerning = zero reflow on settle */
  display:flex;flex-direction:column;align-items:center;row-gap:.25em;   /* 16px @ 64px author */
}
.lk .l1,.lk .l2{display:block;white-space:nowrap;}
/* 320–359px: the 2.6rem floor makes AM I REALLY ~341px wide — wider than the screen. Size to fit. */
@media (max-width:359px){.lk{font-size:min(2.6rem,10.6vw);}}
@media (min-width:900px){
  /* inline: the full sentence is ~11.4em wide, so it takes 7.6vw (9vw wraps at every width) */
  .lk{display:block;white-space:nowrap;font-size:clamp(2.6rem,7.6vw,8.5rem);}
  .lk .l1,.lk .l2{display:inline;}
}
.w-gold{background:var(--gold-grad);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent;}
.w-gold.split{background:none;}
.w-gold.split .c{background:var(--gold-grad);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent;}
.w-cyan{color:var(--cyan);-webkit-text-fill-color:var(--cyan);}

/* THE ? · Orbitron 800's own outline, as geometry.
   The SVG sits on the baseline at cap height (.72em = 720 units), so it lands exactly where
   the font's ? would, on every platform, whatever the font's ascent metrics say.
   Bow = a stroke along the glyph's centreline, width = the stem (142.5 units): it can be
   drawn like a pen. Dot = the glyph's own second contour. Same seam as the SPEC, by construction. */
.q{display:inline;}
.qm{height:.72em;width:auto;display:inline-block;vertical-align:baseline;overflow:visible;}
.q-bow{fill:none;stroke:url(#qg);stroke-width:142.5;stroke-linecap:butt;}
.q-dot{fill:var(--cyan);}
.q-glow{fill:var(--cyan);opacity:0;}

/* ═══ THE CALIBRATION · the one orchestrated moment (§3.1b) ═════════════════
   html.seq is set by the head script only when JS is on and motion is allowed; seq.js
   removes it at the end state. With no JS, nothing below ever applies. */
.seq .lk [data-resolve]{visibility:hidden;}
.seq .q-bow{stroke-dasharray:1000;stroke-dashoffset:1000;}
.seq .q-dot{opacity:0;}
.c{display:inline-block;white-space:pre;text-align:center;clip-path:inset(0);}
.c.cyc{opacity:.55;}
/* BOW · draws itself along the glyph — top bar left→right, down the right side, back along
   the arm, down the stem. One continuous stroke, ~640ms, ease-out. */
.seq .q-bow.play{animation:airf-draw 640ms cubic-bezier(.25,.8,.25,1) forwards;}
/* ── KEYFRAME NAMESPACE (V2.6, 10 Sep) ────────────────────────────────────────
   @keyframes names are GLOBAL to the document, and the last definition wins. site.css loads
   first, so from V2.1 — the moment machine.css and arrival.css joined the page — three of the
   title's own animations were being silently replaced by the decoder's:
     draw   → arrival.css animates --draw (a percentage), so THE BOW NEVER DREW: it sat at
              stroke-dashoffset 1000 for the whole 640ms and snapped to 0 when the calibration
              ended. Measured on the live page: the animation ran, the value never moved.
     pop    → machine.css's tile pop, so the dot's scale pop was the wrong curve.
     bloom  → arrival.css's one-shot expanding fade, so the dot's resting glow faded to nothing
              instead of breathing.
   Every animation this sheet owns is now prefixed. test/machine.test.mjs asserts that no
   keyframe name is defined in more than one shipped sheet, so this cannot return.
   ──────────────────────────────────────────────────────────────────────────── */
@keyframes airf-draw{to{stroke-dashoffset:0;}}
/* DOT · scale 0 → 1.06 → 1 · 180ms */
.seq .q-dot.play{opacity:1;transform-box:fill-box;transform-origin:center;animation:airf-pop 180ms cubic-bezier(.2,.9,.3,1.2) both;}
@keyframes airf-pop{0%{transform:scale(0);}70%{transform:scale(1.06);}100%{transform:scale(1);}}
/* THE BREATH · after the calibration the dot is the one living thing on the page (JJ, 5 Sep) */
html:not(.seq) .q-dot{transform-box:fill-box;transform-origin:center;animation:airf-breathe var(--pulse-period) ease-in-out infinite;}
html:not(.seq) .q-glow{transform-box:fill-box;transform-origin:center;animation:airf-bloom var(--pulse-period) ease-in-out infinite;}
@keyframes airf-breathe{0%,100%{transform:scale(1);opacity:1;}50%{transform:scale(var(--pulse-scale));opacity:var(--pulse-low);}}
@keyframes airf-bloom{0%,100%{transform:scale(1);opacity:.7;}50%{transform:scale(var(--pulse-scale));opacity:0;}}
/* THE EGG · hold the title → the photograph (§6). Never in the DOM at rest; page.js injects it on
   the first hold. The dot is the person, and the person appears: the dot stays at full. */
.lk{-webkit-touch-callout:none;user-select:none;-webkit-user-select:none;touch-action:manipulation;
  transition:transform 300ms ease;}
.lk:focus-visible{outline-offset:12px;}
.egg{position:fixed;inset:0;z-index:0;width:100%;height:100%;object-fit:cover;object-position:53% 36%;
  opacity:0;pointer-events:none;transition:opacity 500ms ease;}
/* V2.4 (JJ, 9 Sep: "the easter egg pic upon first display comes into play quite abrupt").
   The still is fetched on the first hover or hold, so on a first hold the class landed while the
   image had no pixels and it appeared at full the instant the bytes arrived — a pop, not a fade.
   Nothing is shown until the photograph has decoded (page.js adds .ready); the fade then runs. */
.egg:not(.ready){opacity:0 !important;}
.beat-q{position:relative;z-index:1;}
.held .egg.ready{opacity:1;transition-duration:420ms;}
/* V2.5 (JJ, 10 Sep): "too much space between my face and the title … too little space between
   top page margin and title." The rise was reaching for the top edge; it now stops short — the
   title sits under a real margin and closer to the still it is standing on. */
.held .lk{transform:translateY(-9vh);}
@media (min-width:900px){.held .lk{transform:translateY(-11.5vh);}}
.lk .l1,.lk .w-cyan,.q-bow{transition:opacity 300ms ease;}
/* V2.2 (JJ, 9 Sep): held, the title stays at full — it is the still's title — with a dark halo for legibility instead of a fade */
.held .lk .l1,.held .lk .w-cyan,.held .q-bow{opacity:1;}
html.held:not(.seq) .lk{filter:drop-shadow(0 2px 14px rgba(9,9,15,.9)) drop-shadow(0 0 44px rgba(9,9,15,.75));}   /* outranks the computed glow */
.held .q-dot{animation:none;transform:none;opacity:1;}
.held .q-glow{animation:none;opacity:.7;}
.held .logline,.held .lead,.held .qmark{opacity:0;transition-duration:300ms;transition-delay:0ms;}
.held .lead{transform:scaleY(1);}
/* THE LOGLINE · hidden during the calibration, arrives on the first gesture or when the
   question completes — whichever comes first (seq.js removes html.seq; the transition plays) */
.logline{
  margin:0;max-width:62ch;text-align:center;font:400 clamp(1.1rem,2.4vw,1.9rem)/1.45 var(--fs);color:var(--ink);
  transition:opacity 900ms ease,transform 900ms ease;
}
/* three lines, longest first, so the block sits heavy at the top (JJ, 5 Sep); below 360px it wraps naturally */
.logline .ln{display:inline;}
@media (min-width:360px){.logline .ln{display:block;}}
/* one colour in the sentence, by the colour law: freedom is cyan. Nothing else. */
.logline .free{color:var(--cyan);}
.seq .logline{opacity:0;transform:translateY(.5em);}
@media (prefers-reduced-motion:reduce){
  .seq .lk [data-resolve]{visibility:visible;}
  .seq .q-bow{stroke-dasharray:none;stroke-dashoffset:0;}
  .seq .q-dot,.seq .logline,.seq .qmark{opacity:1;transform:none;}
  .seq .lead{transform:none;}
  .q-bow,.q-dot,.q-glow,.logline,.lead,.qmark,.door,.glyph svg,.egg,.lk,.lk .l1,.lk .w-cyan{animation:none!important;transition:none!important;}
  .q-dot{transform:none!important;opacity:1!important;}
  .q-glow{opacity:0!important;}
}

/* ═══ BEAT THREE · THE DOORS · side by side at every width ══════════════════ */
.doors{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);min-height:62svh;}
/* the panels are inert — no cursor, no hover, no click. The anchor wraps the word only (≥44px). */
.door-panel{display:grid;place-items:center;min-height:62svh;padding:8vh 3vw;min-width:0;}
.door-panel+.door-panel{border-left:1px solid rgba(231,183,63,.25);}
.door{
  display:inline-block;padding:.35em .9em;min-height:44px;text-decoration:none;
  font:800 clamp(1.9rem,6vw,5rem)/1 var(--fd);letter-spacing:1px;
  background:var(--gold-grad);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent;
  transition:-webkit-text-fill-color 120ms ease,color 120ms ease;
}
.door:hover,.door:focus-visible{-webkit-text-fill-color:var(--ink);color:var(--ink);}
.door:focus-visible{outline-offset:2px;}
/* narrow phones: the word's own padding tightens so two doors never exceed the screen */
@media (max-width:479px){.door{padding:.35em .5em;font-size:clamp(1.6rem,6vw,5rem);}}
@media (min-width:760px){
  .doors,.door-panel{min-height:100svh;}
  .door-panel{padding:8vh 5vw;}
}
/* on touch screens there is no hover: when the doors arrive in view they do the hover once,
   WATCH then READ — the doors acknowledge you (JJ, 5 Sep). Colour = the hover ink, never cyan. */
@media (hover:none){
  .doors.ack .door{animation:airf-ack 1000ms ease both;}
  .doors.ack .door+.door{animation-delay:320ms;}
}
@keyframes airf-ack{0%,100%{-webkit-text-fill-color:transparent;color:transparent;}45%{-webkit-text-fill-color:var(--ink);color:var(--ink);}}

/* ═══ BEAT 3.5 · THE HANDLE · one string, three addresses · free is cyan ═════ */
.handle{min-height:22svh;display:flex;align-items:center;justify-content:center;gap:clamp(14px,3.5vw,36px);padding:6vh 5vw;}
.handle .h{font:400 clamp(1.05rem,2vw,1.5rem)/1 var(--fm);color:var(--ink);letter-spacing:.01em;white-space:nowrap;}
.handle .free{font-weight:inherit;color:var(--cyan);text-decoration:none;border-bottom:1px solid transparent;padding:12px 0;margin:-12px 0;transition:border-color 120ms ease;}
.handle .free:hover,.handle .free:focus-visible{border-bottom-color:var(--cyan);}
.glyph{display:inline-grid;place-items:center;width:44px;height:44px;color:var(--ink);text-decoration:none;transition:color 120ms ease;}
.glyph svg{width:32px;height:32px;display:block;fill:currentColor;transition:transform 160ms cubic-bezier(.34,1.56,.64,1);}
.glyph:hover,.glyph:focus-visible{color:#fff;}
/* the marks answer the hand: a bump with a small jiggle on hover, a press on tap */
.glyph:hover svg,.glyph:focus-visible svg{transform:scale(1.14) translateY(-1px);}
.glyph:hover svg{animation:airf-bump 420ms cubic-bezier(.34,1.56,.64,1);}
.glyph:active svg{transform:scale(.88);transition-duration:70ms;animation:none;}
@keyframes airf-bump{0%{transform:scale(1);}40%{transform:scale(1.24) rotate(-7deg);}70%{transform:scale(1.08) rotate(5deg);}100%{transform:scale(1.14) translateY(-1px);}}
@media (max-width:359px){.handle{gap:10px;}.handle .h{font-size:.95rem;}}

/* ═══ BEAT FOUR · AIRF DECODER (S3 · V2.1) · lives in assets/machine.css + assets/arrival.css, linked after this file ═══ */

/* ═══ BEAT FIVE · FOOTER · one line, the chip, no date on the line ═══════════ */
.foot{padding:3vh 5vw 7vh;font:400 12px/1.7 var(--fm);color:var(--mono-dim);text-align:center;}
.foot-line{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:6px 8px;}
.foot a{color:inherit;text-decoration:none;transition:color 120ms ease;}
.foot a:hover,.foot a:focus-visible{color:var(--ink);}
.foot a.home:hover,.foot a.home:focus-visible{color:var(--gold);}
.foot .sep{opacity:.6;padding:0 2px;}
.foot .glyph{width:44px;height:44px;color:var(--mono-dim);}
.foot .glyph svg{width:18px;height:18px;}
.foot .glyph:hover,.foot .glyph:focus-visible{color:var(--ink);}
/* THE CHIP · the estate's version marker, in the flagship footer's cut (lucid-footer.css .ff-ver):
   chamfered plate, milled inset, one diamond — gold here, per this page's colour law */
.chip{
  display:inline-flex;align-items:center;gap:7px;min-height:28px;padding:5px 12px;border:0;cursor:pointer;
  clip-path:polygon(7px 0,100% 0,100% calc(100% - 7px),calc(100% - 7px) 100%,0 100%,0 7px);
  background:linear-gradient(180deg,rgba(255,255,255,.05),rgba(0,0,0,.44));
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.09),inset 0 1px 0 rgba(255,255,255,.07),inset 0 -2px 5px rgba(0,0,0,.5);
  font:700 9.5px/1 var(--fm);letter-spacing:1.7px;color:var(--mono-dim);opacity:.86;white-space:nowrap;
  transition:opacity .2s ease,color .2s ease;
}
.chip s{width:4px;height:4px;flex:none;text-decoration:none;transform:rotate(45deg);background:rgba(231,183,63,.85);box-shadow:0 0 5px rgba(231,183,63,.5);}
.chip:hover,.chip:focus-visible,.chip[aria-expanded="true"]{opacity:1;color:var(--ink);}
.chip:focus-visible{outline:0;box-shadow:inset 0 0 0 2px var(--gold);}
.receipt{margin:12px 0 0;font:400 11px/1.7 var(--fm);color:var(--mono-dim);}

/* ═══ 404 · the wrong door is answered by the domain: .no ══════════════════ */
.lost{min-height:100svh;display:grid;place-items:center;padding:0 5vw calc(env(safe-area-inset-bottom,0px) + 6svh);}
.no{font:800 clamp(4rem,18vw,14rem)/1 var(--fd);letter-spacing:1px;text-decoration:none;
  background:var(--gold-grad);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent;
  display:inline-flex;align-items:baseline;}
.no .dot{height:.142em;width:auto;display:inline-block;vertical-align:baseline;overflow:visible;margin-right:.06em;}
.no:focus-visible{outline-offset:10px;}

/* ═══ PRINT · the question alone, on paper ══════════════════════════════════ */
/* V2.5 (JJ, 10 Sep): the front page prints — and saves as a PDF — as its own poster, in colour.
   `print-color-adjust:exact` is what makes Chrome keep the plate when the reader leaves
   "Background graphics" unticked; without it the browser's economy mode drops the ground and the
   title floats on white. `@page{margin:0}` gives a full-bleed sheet and suppresses the browser's
   own header and footer — which is also how the printed page keeps the no-date law. */
@page{margin:0;}
@media print{
  html,body{background:var(--base) !important;}
  html,body,.beat-q,.beat-q *,.doors,.doors *,.handle,.handle *,.foot,.foot *{
    -webkit-print-color-adjust:exact !important;print-color-adjust:exact !important;}
  /* beat one's grid reserves two flexible rows for the lead, which print hides — collapse them
     or the poster runs onto a second sheet with nothing but the doors on it. */
  .beat-q{min-height:auto;padding:7vh 0 0;grid-template-rows:auto auto auto auto;gap:3.5vh;}
  .beat-q *,.doors *{animation:none !important;transition:none !important;}
  /* 62svh of panel becomes 62% of the SHEET in print — the two doors would take a page to
     themselves. They keep their proportion, not their height. */
  .doors,.door-panel{min-height:0;}
  .door-panel{padding:4vh 3vw;}
  .doors{margin-top:3vh;}
  /* the SVG gradient does not survive the print pipeline in every engine — the bow states its gold */
  .q-bow{stroke:var(--gold) !important;} .q-dot{fill:var(--cyan) !important;}
  .foot{padding:2vh 5vw 2vh;}
}

/* ═══ V2.2 · THE PAGE MOVES (JJ, 9 Sep 2026) ═══════════════════════════════════
   the title glows once it has computed · hover the title and the still is teased in behind it (hold = the egg, as before)
   · the small ? loosens and wobbles under the cursor · cyan ripples rise at random on the black and evaporate (the dot's wake)
   · the ? nods when you come back to it · the JJ mark above the handle · every same-tab exit leaves through the question.
   All transform / opacity / canvas; reduced motion → none of it. */
.lk{cursor:pointer;filter:drop-shadow(0 0 0 rgba(231,183,63,0));transition:transform 300ms ease,filter 900ms ease;}
html:not(.seq) .lk{filter:drop-shadow(0 0 30px rgba(231,183,63,.17));}
html:not(.seq).tease:not(.held) .lk{filter:drop-shadow(0 0 34px rgba(231,183,63,.34));}
.tease:not(.held) .egg.ready{opacity:.07;transition-duration:900ms;}
/* the lead's ? · the loosen (bow lifts and tilts, the dot drops and brightens) and a slow wobble while hovered */
.qs-bow{transform-origin:307px 298px;transition:transform .32s cubic-bezier(.2,.8,.2,1);}
.qs-dot{transition:transform .32s cubic-bezier(.2,.8,.2,1),fill .32s ease;}
.qmark:hover .qs-bow,.qmark:focus-visible .qs-bow{transform:translateY(-63px) rotate(-18deg);}
.qmark:hover .qs-dot,.qmark:focus-visible .qs-dot{transform:translateY(63px);fill:#7ee6f4;}
.qmark:hover svg,.qmark:focus-visible svg{animation:airf-q-wobble 1.4s ease-in-out infinite;transform-origin:22% 96%;}
@keyframes airf-q-wobble{0%,100%{transform:rotate(0);}25%{transform:rotate(-4deg);}75%{transform:rotate(3deg);}}
/* the return · the ? nods (the lamp, not the sun): page.js adds .nod to the mark when the title re-enters the viewport */
.lk .qm{transform-origin:22% 96%;}
.lk .qm.nod{animation:airf-q-nod 1.2s cubic-bezier(.2,.8,.2,1) 1;}
@keyframes airf-q-nod{0%{transform:none;}26%{transform:translateY(-.05em) rotate(-9deg);}52%{transform:rotate(4deg);}76%{transform:rotate(-2deg);}100%{transform:none;}}
/* the ripples · a fixed canvas under everything (z -1); the egg (z 0) and the page sit over it */
#ripples{position:fixed;inset:0;z-index:-1;width:100%;height:100%;pointer-events:none;}
/* the JJ mark · a signature above the handle, not a third door: ink at rest, gold under the cursor */
.jj-row{display:flex;justify-content:center;padding:0 5vw;margin:clamp(18px,4svh,44px) 0 -6px;}
.jj{font:800 clamp(1.4rem,2.6vw,1.9rem)/1 var(--fd);letter-spacing:.18em;color:var(--ink);text-decoration:none;padding:12px 16px;min-height:44px;display:inline-flex;align-items:center;transition:color 160ms ease,transform 420ms cubic-bezier(.2,.8,.2,1);}
.jj:hover,.jj:focus-visible{color:var(--gold);transform:translateY(-2px);}
/* the exit mark · every same-tab outbound click leaves through the question (380ms, then the destination) */
.exit{position:fixed;inset:0;z-index:60;display:grid;place-items:center;background:var(--base);opacity:0;pointer-events:none;transition:opacity 220ms ease;}
.exit.on{opacity:1;pointer-events:auto;}
.exit-q{height:min(24vh,170px);width:auto;overflow:visible;display:block;}
.exit-bow{fill:none;stroke:url(#xg);stroke-width:142.5;stroke-linecap:butt;}
.exit-dot{fill:var(--cyan);transform-box:fill-box;transform-origin:center;}
.exit.on .exit-dot{animation:airf-breathe 1.1s ease-in-out infinite;}
@media (prefers-reduced-motion:reduce){
  .lk,.qs-bow,.qs-dot,.qmark svg,.lk .qm,.exit,.exit-dot{animation:none!important;transition:none!important;}
  html:not(.seq) .lk{filter:drop-shadow(0 0 30px rgba(231,183,63,.17));}
  #ripples{display:none;}
}
@media print{#ripples,.exit,.jj-row,.machine,.egg,.lead,.qmark{display:none !important;}
  .foot{display:block !important;}.foot .chip{display:none !important;}}


/* ── V2.6 · THE MOBILE PASS · the footer's own controls (both rooms use this footer) ─────
   Measured on an iPhone emulation: the version chip was a 28px target and the footer's links
   20px. Vertical padding on the inline links expands the hit area without moving a line. */
@media (max-width:719px){
  .chip{min-height:44px;padding:12px 14px;}
  .foot-line{gap:8px 10px;}
  .foot a:not(.glyph){display:inline-block;padding:12px 3px;margin:-12px 0;}
}
