/* SWYPE RIGHT — the real client (PWA), Dating Quarter first.
   v8 "CAMERA WORLD" — the visual experience IS the movement (Kris's law,
   2026-08-14). The deck is one continuous world laid out as a diagonal
   staircase of stations (profile → cliff air → the question → more air →
   the next profile). Nothing is a screen transition: a lazy camera with its
   own personality travels the world. Palette: ink night (the brown is gone) —
   moonlit paper text, GOLD only for thresholds/seals/celebration, WATER for
   pressables (house doctrine). */

:root{
  --ink:#e9edf6; --ink-soft:#a9b4c9; --ink-dim:#65718c;
  --ground:#0a0d18; --ground-2:#060810;
  --accent:#e6b45e; --accent-soft:#c9963f;         /* GOLD — thresholds & seals only */
  --water:#6fc9dc; --water-deep:#2a6b7c;           /* WATER — pressables */
  --card:#121929; --card-2:#182238; --card-edge:#28375a;
  --rose:#e08a9b; --good:#8fd0a5;
  /* DEEP WATER — the voyage (Kris, 2026-08-29). The deck's WATER is the
     shallow shore you walk; this is the open sea beyond it: same family, one
     fathom down, so the alphabet grows without a new hue. --voyage is the
     structural colour (edge, ground tint, medallion); --voyage-ink is the
     same hue lifted just far enough to READ as a mark on ink night — a
     colour you cannot see is not a colour, and the deck's #6fc9dc must stay
     clearly the brighter of the two. */
  --voyage:#2e7f96; --voyage-ink:#4fa2bd; --voyage-soft:rgba(46,127,150,.42);
  --serif:"Iowan Old Style","Palatino Linotype",Palatino,Georgia,"Times New Roman",serif;
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --ease-in:cubic-bezier(.18,1.22,.4,1);
  /* narrow layouts carry a bottom dock; wide layouts zero this out (media below) */
  --dock-h:60px;
  /* neutralize the iOS shell's stopgap patch (DQClientPatch.swift) until the
     bench deletes it: its injected CSS carries topbar-era fallbacks
     (top:var(--dq-bar-bottom,114px) on the card pages) that would push every
     page 114px down now the bar is gone. Defining the properties here makes
     the injection resolve to the dock layout's own truth. */
  --dq-bar-bottom:0px; --dq-deck-inset:0px;
}
*{box-sizing:border-box}
html,body{height:100%;margin:0}
body{
  color:var(--ink);font-family:var(--sans);font-size:18px;-webkit-font-smoothing:antialiased;
  background:#040609;   /* the VOID — everything outside the stage window */
  min-height:100dvh;overflow:hidden;
  -webkit-user-select:none;user-select:none;touch-action:manipulation;
}
button{font:inherit;color:inherit;cursor:pointer}

/* THE STAGE — the persistent ambient canvas the whole app lives on */
#ambient{position:fixed;inset:0;z-index:0;pointer-events:none}

/* THE WINDOW FRAME — outside the stage is the void; the curtains cover it and
   give the window a visible luminous edge, so a card flying off stage is cut by
   a REAL frame the eye understands (never an invisible mask). */
.curtain{position:fixed;top:0;bottom:0;z-index:0;pointer-events:none;
  width:calc((100vw - min(520px, 100vw)) / 2);
  /* transparent: THE SUBSTRATE flows on the ambient canvas beneath — the
     curtains keep only the window's luminous edge + a breath of shade */
  background:linear-gradient(180deg, rgba(3,5,8,.35), rgba(5,7,13,.12) 40%, rgba(3,5,8,.35));
}
.curtain.left{left:0;border-right:1px solid rgba(150,180,235,.16);
  box-shadow:inset -18px 0 34px -18px rgba(0,0,0,.9)}
.curtain.right{right:0;border-left:1px solid rgba(150,180,235,.16);
  box-shadow:inset 18px 0 34px -18px rgba(0,0,0,.9)}

/* ══ THE BRAND — DATING QUARTER in our gold. The crumb wears the real gold
   ramp (amber → gold → white-gold): metal is contrast, clipped to the text. ══ */
.crumb{background:linear-gradient(105deg,#8a6414 0%,#d4a72c 38%,#ffeeb0 50%,#d4a72c 62%,#8a6414 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
  -webkit-text-fill-color:transparent;font-weight:600}
.gate-mark{width:min(280px,68vw);margin:0 auto 10px;display:block}   /* transparent art needs no melt */

/* ══ THE CURTAIN — the stage owns the load. Order, always: darkness → the
   world fades in → the card enters. Play ONCE, on the curtain's rise. ══ */
/* .enter is applied BEFORE the boot overlay lifts (backstage hold — fill-mode
   both keeps everything at its from-state); these delays are the entrance
   beats: the world fades in first, then the card rises. */
#deck.enter .preading,#deck.enter .empty-read{animation:bootCard .55s cubic-bezier(.3,.9,.25,1) .42s both}
.gate.enter{animation:bootCard .55s cubic-bezier(.3,.9,.25,1) .42s both}
@keyframes bootFade{from{opacity:0}}
@keyframes bootCard{from{transform:translateY(26px);opacity:0}}

/* ══ THEMES — a curated shelf, styled to perfection, never free reign.
   THE CONTRACT each theme obeys: one dominant surface (--tbg1→--tbg2), one
   edge (--tedge), ONE highlight (--thi), readable ink (--tink), and decor
   (.td) that lives at the card's edges — NEVER over words. A person's theme
   travels with their card everywhere it appears. ══ */
/* NO overflow:hidden here — the flying .dfly must escape its themed qcard
   (the flick clips at the card border otherwise). The decor kit clips itself
   inside .tdw instead. */
.themed{position:relative;
  background:linear-gradient(180deg,var(--tbg1),var(--tbg2)) !important;
  border-color:var(--tedge) !important;color:var(--tink,var(--ink))}
.themed>*:not(.tdw){position:relative;z-index:1}
.themed .plabel,.themed .ledge-cta{color:var(--thi)}
.themed .ledge-line{background:linear-gradient(90deg,transparent,var(--thi),transparent);box-shadow:0 0 16px var(--thi)}
.themed .chip{border-color:var(--tedge)}
.mitem.themed{background:linear-gradient(90deg,var(--tbg1),rgba(18,25,41,.55)) !important}
.th-redhearts{--tbg1:#2c1016;--tbg2:#190a0f;--tedge:#75293c;--thi:#ff6b81;--tink:#f4e7ea}
.th-jetblack{--tbg1:#101114;--tbg2:#060708;--tedge:#3c4049;--thi:#9aa3b5;--tink:#e8eaef}
.th-royal{--tbg1:#2c1b52;--tbg2:#180e30;--tedge:#4b2f7d;--thi:#b58cff;--tink:#efe9fb}
.th-gold{--tbg1:#33250a;--tbg2:#1c1204;--tedge:#8a6d2a;--thi:#ffd24a;--tink:#fdf4dd}
.th-meadow{--tbg1:#1c4229;--tbg2:#0f2617;--tedge:#3d7050;--thi:#9fe8ae;--tink:#eef8ee}
/* CLOUDS — white and pristine, the counterweight to Jet Black (dark ink) */
.th-clouds{--tbg1:#f5f8fd;--tbg2:#dde7f4;--tedge:#b7c7e0;--thi:#4f7fd0;--tink:#28324e}
/* the readability clause of the contract — secondary text derives from the
   theme's ink, so light themes stay legible without special cases */
.themed .psub,.themed .pcount,.themed .pc-line,.themed .dc-fine,
.themed .ad-sub,.themed .ad-fine{color:color-mix(in srgb,var(--tink) 62%,transparent)}
.themed .pname,.themed .pbody,.themed .dc-q,.themed .dc-name,.themed .ad-name,
.themed .pc-name{color:var(--tink)}
.themed .pface,.themed .ad-face,.themed .pc-face.pc-init{background:color-mix(in srgb,var(--tbg2) 82%,#000)}
.th-clouds .dc-btn.no{border-color:#8ba3c9;color:#3d517c}
.mp-th.th-clouds span{color:#28324e}
/* ══ THE DECOR KIT — one kit, six colourways. EVERY theme wears the SAME
   structure: the surface (--tbg1→--tbg2), the edge (--tedge), a corner glow
   + a foot glow (--thi), ONE slow sheen crossing every 12s (soft-edged — it
   fades out INSIDE the card, never a hard cut), and six emblem sprites at
   the card's edges, swaying gently. Only the palette and the emblem glyph
   change per theme, so the six looks read as versions of one another —
   never six random rooms. ══ */
/* .tdw — the kit's OWN clipping window: the oversize sheen and corner glows
   are masked to the card here, so the card itself never needs overflow:hidden */
.tdw{position:absolute;inset:0;overflow:hidden;border-radius:inherit;pointer-events:none;z-index:0}
.td{position:absolute;pointer-events:none;z-index:0;font-style:normal}
.td.glow{top:-26%;right:-16%;width:70%;height:62%;
  background:radial-gradient(closest-side,color-mix(in srgb,var(--thi) 22%,transparent),transparent 72%)}
.td.glow.b{top:auto;right:auto;bottom:-24%;left:-14%;width:58%;height:52%;opacity:.7}
.td.sheen{top:0;bottom:0;left:-60%;width:220%;
  background:linear-gradient(115deg,transparent 34%,color-mix(in srgb,var(--thi) 7%,transparent) 46%,color-mix(in srgb,var(--thi) 14%,transparent) 50%,color-mix(in srgb,var(--thi) 7%,transparent) 54%,transparent 66%);
  animation:thSheen 12s ease-in-out infinite}
@keyframes thSheen{0%,100%{transform:translateX(-13%)}50%{transform:translateX(13%)}}
.td.s{color:var(--thi);text-shadow:0 0 10px color-mix(in srgb,var(--thi) 45%,transparent)}
.td.s1{top:5%;left:5%;font-size:22px;opacity:.38;animation:thSway 8s ease-in-out infinite}
.td.s2{top:12%;right:6%;font-size:15px;opacity:.30;animation:thSway 10s ease-in-out infinite reverse}
.td.s3{top:42%;left:3%;font-size:12px;opacity:.22;animation:thSway 12s ease-in-out infinite}
.td.s4{top:56%;right:3%;font-size:13px;opacity:.24;animation:thSway 9s ease-in-out infinite reverse}
.td.s5{bottom:8%;left:6%;font-size:16px;opacity:.30;animation:thSway 11s ease-in-out infinite}
.td.s6{bottom:4%;right:7%;font-size:20px;opacity:.36;animation:thSway 13s ease-in-out infinite reverse}
@keyframes thSway{0%,100%{transform:translateY(0) rotate(-5deg)}50%{transform:translateY(-9px) rotate(6deg)}}
/* the kit in miniature — shelf buttons and the little prev card keep only the
   corner sprites, small, so the look reads without crowding the words */
.mp-th .td.s,.prevcard .td.s{font-size:10px}
.mp-th .td.s3,.mp-th .td.s4,.prevcard .td.s3,.prevcard .td.s4{display:none}

/* ══ THE PREV CARD — the one behind you, in their place, in their look ══ */
.prevcard{position:absolute;top:-118px;left:50%;transform:translateX(-50%);
  width:min(440px,88%);display:flex;align-items:center;gap:12px;padding:12px 14px;
  background:linear-gradient(180deg,#131a2d,#0b1120);border:1px solid #2b3a60;border-radius:18px;
  box-shadow:0 18px 44px rgba(0,0,0,.55);cursor:pointer}
/* the arrival beat: LAND (the space above waits, empty) → the card sweeps in
   from the right → THEN the count begins. fill-mode both holds it offstage
   right through the landing beat; sparking + the countdown are armed by JS
   only after this entrance settles. */
.prevcard.arrive-in{animation:pcIn .45s cubic-bezier(.2,.9,.3,1) .22s both}
@keyframes pcIn{from{transform:translateX(calc(-50% + 100vw));opacity:.4}
  to{transform:translateX(-50%);opacity:1}}
.prevcard.sparking{animation:pcRing 1.15s ease-in-out infinite}
@keyframes pcRing{0%,100%{box-shadow:0 18px 44px rgba(0,0,0,.55),0 0 0 0 rgba(230,180,94,.0)}
  50%{box-shadow:0 18px 44px rgba(0,0,0,.55),0 0 22px 2px rgba(230,180,94,.28)}}
.prevcard.themed.sparking{animation:none;box-shadow:0 18px 44px rgba(0,0,0,.55),0 0 22px 2px color-mix(in srgb,var(--thi) 30%,transparent)}
.pc-face{flex:none;width:46px;height:46px;border-radius:12px;background-size:cover;background-position:center;border:1px solid var(--card-edge)}
.pc-face.pc-init{display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:20px;background:#182138}
.pc-body{flex:1;min-width:0;text-align:left}
.pc-name{font-family:var(--serif);font-size:17px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pc-line{font-size:11.5px;color:var(--ink-dim);letter-spacing:.03em}
.pc-line .star{color:var(--accent)}
.prevcard .gb-undo{flex:none;border:1px solid var(--water);background:none;color:var(--water);
  border-radius:12px;padding:8px 13px;font:inherit;font-size:13px}
.prevcard .gb-line{position:absolute;left:14px;right:14px;bottom:5px;height:2px;width:calc(100% - 28px);
  background:var(--accent);border-radius:2px;box-shadow:0 0 8px var(--accent)}
.prevcard .pc-hint{flex:none;font-size:11px;color:var(--ink-dim);letter-spacing:.08em;text-transform:uppercase}
.prevcard.settled{opacity:.88}
.prevcard.settled:hover{opacity:1}

/* ══ the look shelf (My Profile) + the mirror ══ */
.mp-themes{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-top:6px}
.mp-th{position:relative;overflow:hidden;height:64px;border-radius:14px;border:1px solid var(--card-edge);
  background:linear-gradient(180deg,#131a2d,#0b1120);color:var(--ink);font:inherit;font-size:12.5px;letter-spacing:.03em}
.mp-th span{position:relative;z-index:1}
.mp-th.sel{outline:2px solid var(--accent);outline-offset:2px}
.mp-preview{display:block;width:100%;margin:16px 0 0;padding:12px;border-radius:14px;
  border:1px solid var(--water);background:none;color:var(--water);font:inherit;font-size:14px}
.admire.preview{align-items:flex-start;overflow-y:auto;padding:30px 0 60px}
.pv-wrap{width:min(478px,93%);margin:0 auto}
.pv-wrap .preading{min-height:0}
.pv-close{position:fixed;top:14px;right:16px;z-index:2;border:1px solid var(--card-edge);
  background:rgba(10,13,24,.8);color:var(--ink);border-radius:12px;padding:8px 14px;font:inherit;font-size:13px}

/* ══ the ADMIRE card — a look, never a re-decision ══ */
.admire{position:fixed;inset:0;z-index:60;display:flex;align-items:center;justify-content:center;
  background:rgba(4,6,12,.55);animation:adDim .3s ease both}
.admire.away{opacity:0;transition:opacity .32s ease}
.admire .acard{width:min(320px,84vw);padding:18px 18px 16px;text-align:center;
  animation:adRise .45s cubic-bezier(.3,.9,.25,1) both}
.admire.away .acard{transform:translateY(18px);transition:transform .32s ease}
@keyframes adDim{from{opacity:0}}
@keyframes adRise{from{transform:translateY(26px);opacity:0}}
.ad-photo{width:150px;height:200px;border-radius:16px;margin:4px auto 12px;
  background-size:cover;background-position:center;border:1px solid var(--card-edge)}
.ad-face{width:110px;height:110px;border-radius:50%;margin:8px auto 12px;display:flex;
  align-items:center;justify-content:center;font-family:var(--serif);font-size:44px;
  background:#182138;border:1px solid var(--card-edge)}
.ad-name{font-family:var(--serif);font-size:26px}
.ad-sub{color:var(--ink-dim);font-size:14px;margin:4px 0 10px}
.ad-seal{color:var(--accent);font-size:13px;letter-spacing:.04em;margin-bottom:6px}
.ad-fine{color:var(--ink-dim);font-size:11.5px}

/* the lantern wash — cool moonlight, a whisper of gold (inside the window) */
.lantern{position:fixed;inset:0;pointer-events:none;z-index:0;
  background:radial-gradient(42% 32% at 50% 6%, rgba(190,210,255,.07), transparent 70%)}

/* the pull meter — the ledge's grip, made visible at the very top */
#meter{position:fixed;left:0;top:0;height:3px;background:var(--accent);width:0;z-index:20;
  box-shadow:0 0 10px var(--accent);transition:width .05s linear}

.app{position:relative;z-index:1;height:100dvh;display:flex;flex-direction:column;
  max-width:520px;margin:0 auto;overflow:hidden;padding-top:env(safe-area-inset-top)}

/* ══ THE DOCK — the LAW: the stage and the controls NEVER share pixels.
   On a phone the controls live in a bottom dock at the thumb, OUTSIDE the
   stage — the content region ends above it, so nothing can ever slide in
   under a bar again (no scrims, no offsets, no stale magic numbers).
   On anything wider the stage takes the FULL height and the dock moves into
   the void beside it: the WAYMARK (the mark + where-you-are) on the left,
   the doors on the right — void furniture, the Substrate flowing behind.
   Every target stays 44×44. WATER for pressables; the matches ✦ keeps GOLD —
   it is a seal, not a control. */
.stageArea{position:relative;flex:1;min-height:0;overflow:hidden}
.dockbar{flex:none;display:flex;align-items:center;gap:8px;
  padding:3px 12px calc(3px + env(safe-area-inset-bottom));
  background:linear-gradient(180deg,rgba(9,12,22,.97),rgba(5,7,13,.99));
  border-top:1px solid rgba(150,180,235,.14);   /* the window's bottom edge — cuts read as frame */
  position:relative;z-index:10}
.waymark{display:flex;align-items:center;gap:8px;flex:1;min-width:0}
.dockbtns{display:flex;align-items:center;gap:4px}
/* the entrance beat rides the CHILDREN so it works in both dock shapes
   (on wide, .dockbar is display:contents and cannot animate itself) */
.dockbar.enter .waymark,.dockbar.enter .dockbtns{animation:bootFade .5s ease .3s both}
/* The mark is WIDE (the D&Q couple, transparent) — the button keeps the 44px
   target height and lets width follow the art. No mask needed any more. */
.logo-home{height:44px;flex:0 0 auto;display:flex;align-items:center;gap:8px;
  background:none;border:none;padding:0 2px}
.logo-home[hidden]{display:none}
.logo-home .markcol{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px}
.logo-home img{height:34px;width:auto;transition:transform .18s}
.logo-home:active img{transform:scale(.9)}

/* ── THE TELLTALE (Kris, 2026-08-29) — the mark wears YOUR standing.
   Kris ruled NO fourth dot: the voyage is not news from a room, it is where
   you are, so it gets its own light instead of a slot in the dot alphabet.
   A little window at the mark showing a live harbour or open water, tinted by
   the actual hour at the port. It is a TELLTALE, NOT A CONTROL — it lives
   inside the mark's button, so the tap it eats is the tap it already had
   (home), and a dead decorative pixel never appears in the dock. Absent
   standing = absent window: no standing must only ever read as silence. ── */
.telltale{width:38px;height:38px;flex:0 0 38px;border-radius:11px;overflow:hidden;
  border:1px solid color-mix(in srgb,var(--voyage) 55%,transparent);
  box-shadow:0 0 14px -4px var(--voyage-soft), inset 0 0 12px -6px #000;
  transition:transform .18s,box-shadow .35s}
.telltale[hidden]{display:none}
.telltale svg{display:block;width:100%;height:100%}
.logo-home:active .telltale{transform:scale(.9)}
/* THE THREE DOTS — the quarter's notification language, worn under the mark.
   One dot per landing card, in the card's own colour: WATER the deck, GOLD
   what you keep, ROSE your stall. Dark = quiet; lit = that room has news, and
   the mark (one tap) takes you to the landing to read it. The colours repeat
   on the landing cards so the language teaches itself. */
.waydots{display:flex;gap:7px;line-height:0}
.wd{width:7px;height:7px;border-radius:50%;background:rgba(120,136,170,.5);
  box-shadow:inset 0 0 0 1px rgba(150,180,235,.28);
  transition:background .35s,box-shadow .35s,transform .35s}
.wd.lit{transform:scale(1.2)}
.wd-deck.lit{background:var(--water);box-shadow:0 0 9px 2px rgba(111,201,220,.8)}
.wd-keep.lit{background:var(--accent);box-shadow:0 0 9px 2px rgba(230,180,94,.85)}
.wd-stall.lit{background:var(--rose);box-shadow:0 0 9px 2px rgba(224,138,155,.8)}
/* the breathe rides the LIT dot only, and each colour keeps its own rhythm so
   two lit dots read as two rooms rather than one pulse */
.wd-deck.lit{animation:wdBreathe 2.6s ease-in-out infinite}
.wd-keep.lit{animation:wdBreathe 2.2s ease-in-out infinite}
.wd-stall.lit{animation:wdBreathe 3s ease-in-out infinite}
@keyframes wdBreathe{0%,100%{filter:brightness(1)}50%{filter:brightness(1.45)}}
.tico{position:relative;width:44px;height:44px;flex:0 0 44px;display:flex;align-items:center;justify-content:center;
  background:none;border:none;border-radius:12px;padding:0;color:var(--ink-soft);
  transition:color .2s,background-color .2s}
.tico[hidden]{display:none}
.tico:hover,.tico:active{color:var(--water)}
/* the lit door — the dock always shows where you are (native tab affordance) */
.tico.here{color:var(--water);background:rgba(111,201,220,.10)}
.matches-door.here{background:rgba(230,180,94,.10)}   /* the seal stays gold; its tile warms */
.tico svg{display:block}
.back{display:none}
.back.show{display:flex}
.crumb{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  font-size:12.5px;letter-spacing:.22em;text-transform:uppercase;color:var(--ink-dim)}
.matches-door .star{font-size:21px;line-height:1;color:var(--accent);transition:none}
.matches-door:hover,.matches-door:active{color:var(--ink-soft)}   /* the seal never turns water */
.matches-door .count{position:absolute;top:2px;right:0;min-width:17px;height:17px;padding:0 4px;
  border-radius:999px;background:var(--card);border:1px solid var(--card-edge);color:var(--ink-soft);
  font-size:11px;line-height:15px;text-align:center;font-variant-numeric:tabular-nums}
.matches-door.sparking .count{background:var(--accent);border-color:var(--accent);
  color:#241903;font-weight:600}
/* SPARKING — a mutual match waits unseen. Not a counter shouting; a kept flame.
   The sparks stay lit until you've looked at who it is. */
.matches-door{position:relative}
.matches-door.sparking{background:rgba(230,180,94,.09);   /* a lit tile — the glow needs a floor */
  animation:doorGlow 1.7s ease-in-out infinite}
@keyframes doorGlow{0%,100%{box-shadow:0 0 6px rgba(230,180,94,.22)}50%{box-shadow:0 0 20px rgba(230,180,94,.55)}}
.matches-door.sparking .star{animation:starTwinkle 1.25s ease-in-out infinite}
@keyframes starTwinkle{0%,100%{transform:scale(1)}50%{transform:scale(1.4) rotate(16deg)}}
.matches-door.sparking::before,.matches-door.sparking::after{content:'✦';position:absolute;
  color:var(--accent);pointer-events:none;font-size:11px;animation:sparkPop 1.9s ease-in-out infinite}
.matches-door.sparking::before{top:-8px;right:9px;animation-delay:.3s}
.matches-door.sparking::after{bottom:-9px;left:11px;font-size:9px;animation-delay:1.05s}
@keyframes sparkPop{0%,100%{opacity:0;transform:scale(.4) rotate(0)}40%{opacity:1;transform:scale(1.2) rotate(42deg)}70%{opacity:.5}}

/* ── views are COLUMNS — they slide, they never cut. They fill the stageArea,
   whose box ends where the dock begins: no view can ever touch the chrome. ── */
.view{position:absolute;inset:0;display:none;flex-direction:column;will-change:transform}
.view.show{display:flex}

/* ══ WIDE STAGE (laptop / tablet landscape) — the stage runs top to bottom;
   the dock leaves the column and becomes furniture in the void. ══ */
@media (min-width:820px){
  :root{--dock-h:0px}
  .dockbar{display:contents}
  .waymark,.dockbtns{position:fixed;top:0;bottom:0;z-index:10;
    width:calc((100vw - 520px)/2);min-width:130px;
    flex-direction:column;justify-content:center;align-items:center;
    padding:24px 14px}
  .waymark{left:0;gap:14px}
  .dockbtns{right:0;gap:24px}
  .waymark .logo-home{flex-direction:column;gap:14px;height:auto}
  .waymark .logo-home img{height:auto;width:min(150px,74%);
    filter:drop-shadow(0 6px 24px rgba(0,0,0,.6))}
  /* "on the web we have the fuller DQ space" (Kris) — the telltale stops being
     a chip and becomes a real window in the void beside the big mark. */
  .waymark .telltale{width:min(150px,74%);height:74px;flex:none;border-radius:14px;
    order:-1;box-shadow:0 8px 26px -10px #000, 0 0 22px -6px var(--voyage-soft)}
  .waymark .waydots{gap:10px}
  .waymark .wd{width:9px;height:9px}
  .crumb{flex:none;max-width:92%;white-space:normal;text-align:center;line-height:1.7}
}

/* ══ THE CARD STANDARD — every destination is a solid body you land on.
   BOUNDARY LAW: only the VOID touches the Substrate. A card occludes the
   field (readable content, always), and is the bounded surface that can
   later host its OWN card-local energy tap. Same material as the deck's
   .preading/.qcard so the whole palace is one substance. ══ */
.vcard{
  width:min(486px,94%);margin:12px auto 14px;
  background:linear-gradient(180deg,#131a2d 0%,#0f1526 55%,#0b1120 100%);
  border:1px solid #2b3a60;border-radius:26px;
  box-shadow:0 34px 80px rgba(0,0,0,.65),0 4px 18px rgba(0,0,0,.5),
    inset 0 1px 0 rgba(190,210,255,.07)}

/* ══ THE DECK — one continuous CAMERA WORLD ══════════════════════════════════
   #wfield  — the parallax field BEHIND the stations (motes, words, ghosts)
   #dworld  — the world plane; the camera moves by transforming this
   #clouds  — in FRONT: celebration sparks + speed vignette                    */
#deck{touch-action:none;overflow:hidden}
#wfield{position:absolute;inset:0;z-index:0;pointer-events:none}
#clouds{position:absolute;inset:0;z-index:5;pointer-events:none}
.dworld{position:absolute;left:0;top:0;z-index:1;will-change:transform}

/* a STATION — one soul's place in the world: their page, the cliff air below
   it, and the question hanging in that air */
.station{position:absolute;width:100%}

/* the reading surface — a REAL CARD: a solid panel floating in the air, edges
   visible against the void, the parallax field drifting past its sides. The
   ledge is its literal bottom edge — you go over the edge of the CARD. */
.preading{min-height:var(--sh,560px);display:flex;flex-direction:column;align-items:center;
  width:min(478px,93%);margin:14px auto 0;padding:16px 22px 0;text-align:center;
  background:linear-gradient(180deg,#131a2d 0%,#0f1526 55%,#0b1120 100%);
  border:1px solid #2b3a60;border-radius:26px;
  box-shadow:0 34px 80px rgba(0,0,0,.65),0 4px 18px rgba(0,0,0,.5),
    inset 0 1px 0 rgba(190,210,255,.07)}

/* STAGE the reveal — elements rise in over time, never dumped all at once */
.stage-in>*{animation:stageRise .5s cubic-bezier(.18,1.05,.4,1) both}
.stage-in>*:nth-child(1){animation-delay:.02s}
.stage-in>*:nth-child(2){animation-delay:.09s}
.stage-in>*:nth-child(3){animation-delay:.16s}
.stage-in>*:nth-child(4){animation-delay:.23s}
.stage-in>*:nth-child(5){animation-delay:.30s}
.stage-in>*:nth-child(6){animation-delay:.37s}
.stage-in>*:nth-child(7){animation-delay:.44s}
.stage-in>*:nth-child(8){animation-delay:.51s}
.stage-in>*:nth-child(9){animation-delay:.58s}
.stage-in>*:nth-child(10){animation-delay:.65s}
.stage-in>*:nth-child(11){animation-delay:.72s}
.stage-in>*:nth-child(n+12){animation-delay:.79s}
@keyframes stageRise{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}
.pcount{font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-dim);margin:2px 0 18px}
.pphoto{width:min(320px,80vw);height:clamp(240px,42vh,380px);border-radius:24px;
  background-size:cover;background-position:center;box-shadow:0 14px 40px rgba(0,0,0,.55);margin-bottom:6px}
.pface{width:104px;height:104px;border-radius:50%;margin:8px 0 4px;
  background:radial-gradient(circle at 35% 30%,#3b6b8c,#16283e);
  display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:48px;color:#dfe9f6}
.pname{font-family:var(--serif);font-size:40px;line-height:1.05;margin:12px 0 2px}
.psub{color:var(--ink-soft);font-size:17px;line-height:1.4;margin-bottom:20px;max-width:32ch}
.pstanza{max-width:34ch;margin:0 auto 24px}
/* "from their world" — the life photos + loves chips that make a page a person */
.pworld{margin:0 auto 24px;width:100%;display:flex;flex-direction:column;align-items:center}
.pworld .plabel{margin-bottom:10px}
.pphoto2{width:min(340px,84vw);height:clamp(170px,28vh,250px);border-radius:20px;
  background-size:cover;background-position:center;box-shadow:0 10px 30px rgba(0,0,0,.5)}
.pchips{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;max-width:38ch}
.chip{border:1px solid var(--card-edge);border-radius:999px;padding:7px 13px;font-size:13.5px;
  color:var(--ink-soft);background:rgba(18,25,41,.55);white-space:nowrap}
.plabel{font-size:11px;letter-spacing:.24em;text-transform:uppercase;color:var(--ink-dim);margin-bottom:8px}
.pbody{font-family:var(--serif);font-size:22px;line-height:1.5;color:var(--ink)}

/* the ledge — the cliff edge at the bottom of the CARD. GOLD: it is a threshold. */
.ledge{margin-top:auto;width:calc(100% + 44px);margin-left:-22px;margin-right:-22px;
  padding:26px 0 30px;display:flex;flex-direction:column;align-items:center;
  gap:12px;background:linear-gradient(180deg,transparent,rgba(4,6,12,.5));
  border:none;border-radius:0 0 26px 26px;cursor:pointer;
  -webkit-tap-highlight-color:transparent;color:inherit;font:inherit}
.ledge-line{width:min(320px,78vw);height:2px;border-radius:2px;
  background:linear-gradient(90deg,transparent,var(--accent),transparent);box-shadow:0 0 16px var(--accent)}
.ledge-cta{color:var(--accent);font-size:12.5px;letter-spacing:.16em;text-transform:uppercase;opacity:.55}
.ledge-cta .arr{display:block;font-size:20px;margin-top:6px;animation:bob 1.8s ease-in-out infinite}
@keyframes bob{0%,100%{transform:translateY(0);opacity:.5}50%{transform:translateY(6px);opacity:1}}

/* THE QUESTION — a solid platform hanging in the cliff air, a real place the
   camera falls TO. It never pops in. */
.wplinth{position:absolute;left:0;width:100%;height:var(--sh,560px);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  padding:24px;text-align:center}
.qcard{position:relative;width:min(402px,90%);padding:26px 22px 26px;
  display:flex;flex-direction:column;align-items:center;
  background:linear-gradient(180deg,#11182a 0%,#0c1222 100%);
  border:1px solid #2b3a60;border-radius:24px;
  box-shadow:0 30px 70px rgba(0,0,0,.65),inset 0 1px 0 rgba(190,210,255,.07)}
/* the CARD you flick — a solid little body that tumbles through the air */
.dfly{display:flex;flex-direction:column;align-items:center;will-change:transform;
  background:linear-gradient(180deg,#1a2340 0%,#121a30 100%);
  border:1px solid #34497c;border-radius:20px;padding:20px 30px 16px;margin-bottom:18px;
  box-shadow:0 14px 34px rgba(0,0,0,.55),inset 0 1px 0 rgba(190,210,255,.09)}
.dfly.flying{z-index:9;position:relative;transition:none;
  box-shadow:0 26px 60px rgba(0,0,0,.6),0 0 24px rgba(230,180,94,.18)}
.dfly.slide-off{transition:transform .48s cubic-bezier(.4,0,.85,.5),opacity .48s ease;
  transform:translateX(-84vw) rotate(-7deg);opacity:0}
.dfly.resting{opacity:.44;filter:saturate(.55)}
.dc-photo{width:150px;height:150px;border-radius:50%;background-size:cover;background-position:center;
  box-shadow:0 12px 34px rgba(0,0,0,.55),0 0 0 3px rgba(230,180,94,.35);margin-bottom:14px}
.dc-face{width:130px;height:130px;border-radius:50%;margin-bottom:14px;
  background:radial-gradient(circle at 35% 30%,#3b6b8c,#16283e);
  display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:56px;color:#dfe9f6;
  box-shadow:0 12px 34px rgba(0,0,0,.55)}
.dc-name{font-family:var(--serif);font-size:34px;margin:2px 0 6px}
.dc-q{font-family:var(--serif);font-size:22px;color:var(--ink-soft);margin-bottom:24px;max-width:26ch;
  transition:opacity .4s}
.dc-choice{display:flex;gap:16px;align-items:center;transition:opacity .4s}
.dc-btn{padding:15px 26px;border-radius:999px;font-size:16px;letter-spacing:.02em;
  border:1px solid var(--card-edge);background:rgba(18,25,41,.72);color:var(--ink-soft);
  transition:transform .12s,border-color .2s,color .2s,box-shadow .2s}
.dc-btn:active{transform:scale(.95)}
.dc-btn.no:hover{border-color:var(--water);color:var(--ink)}
.dc-btn.yes{background:linear-gradient(180deg,#23283b,#171c2c);border-color:var(--accent);color:var(--accent);
  font-size:17px;padding:15px 30px}
.dc-btn.yes:hover{box-shadow:0 6px 24px rgba(230,180,94,.28)}
.dc-fine{margin-top:20px;color:var(--ink-dim);font-size:12px;letter-spacing:.02em;max-width:30ch;transition:opacity .4s}
/* a spent question: the asking parts rest; the seal remains for anyone who climbs back */
.wplinth.spent .dc-q,.wplinth.spent .dc-choice,.wplinth.spent .dc-fine{opacity:0;pointer-events:none}
.dseal{min-height:22px;margin-top:14px;color:var(--ink-soft);font-size:15px;
  opacity:0;transition:opacity .6s .3s}
.dseal .star{color:var(--accent)}
.wplinth.spent .dseal{opacity:1}

/* THE GRACE BAR — drops in as the landing settles (the last beat of the
   movement). Five seconds between the gesture and the truth; UNDO = it never
   happened. The gold line drains with the count. */
.gracebar{position:absolute;top:6px;left:12px;right:12px;z-index:7;overflow:hidden;
  display:flex;align-items:center;gap:12px;padding:13px 10px 15px 16px;
  background:rgba(13,18,32,.97);border:1px solid var(--card-edge);border-radius:16px;
  box-shadow:0 10px 30px rgba(0,0,0,.45);
  animation:gbDown .55s cubic-bezier(.18,1.22,.4,1) both}
@keyframes gbDown{from{transform:translateY(-135%);opacity:.4}to{transform:none;opacity:1}}
.gracebar.gb-out{transition:transform .35s cubic-bezier(.55,0,.9,.5),opacity .35s;
  transform:translateY(-135%);opacity:0}
.gracebar .gb-txt{flex:1;font-size:14.5px;color:var(--ink);line-height:1.35;min-width:0}
.gracebar .gb-txt .star{color:var(--accent)}
.gracebar .gb-undo{flex:none;border:1px solid var(--water);border-radius:999px;background:rgba(111,201,220,.08);
  color:var(--water);font-size:14px;letter-spacing:.05em;padding:9px 16px;font-weight:600}
.gracebar .gb-undo:active{transform:scale(.95)}
.gracebar .gb-count{display:inline-block;min-width:12px;text-align:center;font-variant-numeric:tabular-nums;
  color:var(--ink);opacity:.85}
.gracebar .gb-line{position:absolute;left:0;bottom:0;height:3px;width:100%;
  background:linear-gradient(90deg,var(--accent),var(--accent-soft));border-radius:2px}

/* the deliberate look-back door at the top of a profile (landings are arrivals —
   you cannot scroll back up the fall; you can open this door) */
.pback{border:1px dashed var(--card-edge);border-radius:999px;background:rgba(18,25,41,.5);
  color:var(--ink-dim);font-size:12.5px;letter-spacing:.06em;padding:7px 14px;margin-bottom:14px;
  transition:color .2s,border-color .2s}
.pback:hover{color:var(--water);border-color:var(--water)}

/* empty / room-dark state (a terminal station) */
.empty-read{justify-content:center;text-align:center;color:var(--ink-soft)}
.empty-read .seal{font-size:52px;color:var(--accent);filter:drop-shadow(0 0 24px rgba(230,180,94,.7));margin-bottom:10px}
.empty-read h2{font-family:var(--serif);font-weight:600;font-size:28px;color:var(--ink);margin:0 0 10px}
.empty-read p{max-width:30ch;margin:0;line-height:1.5}
.empty{text-align:center;max-width:30ch;color:var(--ink-soft)}
.empty h2{font-family:var(--serif);font-weight:600;font-size:26px;color:var(--ink);margin:0 0 10px}
/* THE EMPTY DECK (v64): a direction, not a shrug — the next happening on an
   ink plate and one door to the board */
.empty-read .ed-next{margin-top:16px;width:min(320px,80vw)}
.empty-read .ed-next span:last-child{font-size:14px;color:var(--ink)}
.empty-read .ed-go{margin-top:14px;padding:12px 22px;border-radius:14px;border:1px solid var(--voyage-ink,#7fc3d6);
  background:linear-gradient(180deg,#1c2740,#141d31);color:var(--voyage-ink,#7fc3d6);font-size:15px;letter-spacing:.02em;cursor:pointer}
.empty-read .ed-go:active{transform:scale(.98)}

/* ── scroll surface (My Profile) ── */
.scroll{flex:1;overflow-y:auto;width:100%;padding:6px 22px 40px;-webkit-overflow-scrolling:touch}
.scroll::-webkit-scrollbar{display:none}

/* ── matches list ── */
.list{flex:1;overflow-y:auto;width:100%;padding:8px 18px 40px}
.list::-webkit-scrollbar{display:none}
.mitem{display:flex;align-items:center;gap:14px;padding:16px 16px;margin-bottom:12px;
  background:rgba(18,25,41,.6);border:1px solid var(--card-edge);border-radius:18px;
  transition:border-color .2s}
.mitem.arrive{animation:arrive .5s var(--ease-in) both;animation-delay:calc(var(--i,0)*70ms)}
@keyframes arrive{from{transform:translateX(-26px);opacity:0}to{transform:none;opacity:1}}
.mitem:hover{border-color:var(--water)}
.mitem .mface{width:52px;height:52px;border-radius:50%;flex:none;
  background:radial-gradient(circle at 35% 30%,#3b6b8c,#16283e);
  display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:24px;color:#dfe9f6}
.mitem .mbody{flex:1;min-width:0}
.mitem .mname{font-family:var(--serif);font-size:22px}
.mitem .mnote{color:var(--ink-soft);font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mitem .seal{color:var(--accent);font-size:18px}
.list .note{text-align:center;color:var(--ink-dim);font-size:13px;margin:6px 0 20px;letter-spacing:.02em}

/* ── THE LANDING CARDS — three rooms, three colours (Kris, 2026-08-27) ──
   Each card wears ONE colour and ONE mark, the same pair its dot wears under
   the DQ logo — WATER ☖ the deck · GOLD ✦ what you keep · ROSE ☺ your stall.
   A lit card (news inside) glows in its own colour; the faces strip shows a
   taste of what the tap opens. --lc is the card's colour, --lcs its glow. */
/* with FOUR cards the head gives back the room the window takes — the scene is
   what you land on now, so the title steps down from banner to line */
#landingScroll.four .lhead{margin:6px 0 2px}
#landingScroll.four .lhead h2{font-size:24px}
#landingScroll.four .lhead .lsub{font-size:12px}
#landingScroll.four .lcard{padding:15px 14px;margin-bottom:11px}
#landingScroll.four .lcard .lmark{width:48px;height:48px;font-size:22px}
#landingScroll.four .lcard .lname{font-size:21px}
#landingScroll.four .lcard .ldetail{font-size:12.5px}
.lhead{text-align:center;margin:14px 0 6px}
.lhead h2{font-family:var(--serif);font-size:30px;font-weight:400;margin:0 0 4px}
.lhead .lsub{color:var(--ink-dim);font-size:13px;letter-spacing:.04em}
.lcard{display:flex;align-items:center;gap:15px;padding:18px 16px;margin-bottom:14px;text-align:left;width:100%;
  background:linear-gradient(115deg,color-mix(in srgb,var(--lc) 9%,rgba(18,25,41,.72)),rgba(18,25,41,.62) 55%);
  border:1px solid var(--card-edge);border-left:3px solid color-mix(in srgb,var(--lc) 55%,transparent);
  border-radius:18px;transition:border-color .25s,box-shadow .25s}
.lcard.arrive{animation:arrive .5s var(--ease-in) both;animation-delay:calc(var(--i,0)*80ms)}
/* backstage hold: while the curtain is down the cards wait unplayed, so their
   staggered entrance is what the audience actually sees when it lifts */
#landing.enter .lcard.arrive{animation:none;opacity:0}
#landing.enter .lhead{opacity:0}
.lhead{transition:opacity .6s ease}
.lcard:hover{border-color:var(--lc)}
.lcard:active{transform:scale(.985)}
.lcard.lit{border-color:color-mix(in srgb,var(--lc) 70%,var(--card-edge));
  box-shadow:0 0 22px -4px var(--lcs)}
.lcard .lmark{width:54px;height:54px;border-radius:50%;flex:none;
  display:flex;align-items:center;justify-content:center;font-size:24px;color:var(--lc);
  background:radial-gradient(circle at 35% 30%,color-mix(in srgb,var(--lc) 26%,#101828),#0b1220);
  border:1px solid color-mix(in srgb,var(--lc) 40%,transparent)}
.lcard .lbody{flex:1;min-width:0}
.lcard .lname{font-family:var(--serif);font-size:23px}
.lcard .lnote{color:var(--ink-soft);font-size:14.5px;margin-top:2px}
.lcard .ldetail{color:var(--ink-dim);font-size:13px;margin-top:5px;line-height:1.35}
.lcard .lfaces{display:flex;margin-top:9px}
.lcard .lfc{width:30px;height:30px;border-radius:50%;flex:none;margin-right:-8px;
  background-size:cover;background-position:center;
  background-color:#16283e;border:1.5px solid color-mix(in srgb,var(--lc) 45%,#0b1220);
  display:flex;align-items:center;justify-content:center;
  font-family:var(--serif);font-size:14px;color:#dfe9f6}
.lcard .lgo{flex:none;color:var(--lc);font-size:19px}
/* THE LADDER (v64): the smiles row tells each card's story — a face and the
   wire's own line ("Ada smiled at you twice at the braai, Cape Town" / "you
   smiled at Bruno at …"); an empty queue names the next happening instead */
.lcard .lstories{display:flex;flex-direction:column;gap:6px;margin-top:9px}
.lcard .lstory{display:flex;align-items:center;gap:9px;font-size:13px;color:var(--ink-soft);line-height:1.3;min-width:0}
.lcard .lstory .lfc{margin-right:0}
.lcard .lstory>span:last-child{flex:1;min-width:0;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.lcard .lnext{margin-top:9px;font-size:13px;color:var(--ink-soft);line-height:1.35}
.lcard .lnext b{font-size:10.5px;letter-spacing:.17em;text-transform:uppercase;color:var(--voyage-ink);font-weight:400;margin-right:8px}
.lcard .lmark svg{width:26px;height:26px;display:block}
.lcard.lit .lgo{animation:wdBreathe 2.6s ease-in-out infinite}

/* ══ THE VOYAGE CARD — the landing's FIRST card (Kris, 2026-08-29) ══════════
   "a fun and playful language of our travelling … sprites and backgrounds and
   animations … as well as any extra things the server puts on from the world."

   It is the SAME card as the other three — left colour edge, medallion, name,
   status, detail, chevron — so the page reads as one system. What it adds is a
   WINDOW: a live scene along its top, inside the same rounded border, showing
   the harbour you are standing in at the hour it actually is there. That is
   the "styled the same as the DQ logo is with the live data" ask: the scene is
   not decoration, every colour in it comes off the server's flavour.

   NO OVERLAY: the scene is its own band, above the text — it never sits on top
   of anything you have to read.                                              */
.lcard.voyage{flex-direction:column;align-items:stretch;gap:0;padding:0;overflow:hidden}
.lcard.voyage .vscene{position:relative;width:100%;height:104px;overflow:hidden;
  border-bottom:1px solid color-mix(in srgb,var(--lc) 30%,transparent)}
.lcard.voyage .vscene svg{display:block;width:100%;height:100%}
.lcard.voyage .lrow{display:flex;align-items:center;gap:15px;padding:15px 16px}
.lcard.voyage .lmark{width:46px;height:46px}
/* the standing, said over the scene at the horizon — not over the water the
   eye is reading, and never over the sprite */
.lcard.voyage .vlabel{position:absolute;left:14px;bottom:9px;
  font-family:var(--serif);font-size:19px;color:#f2f7ff;letter-spacing:.01em;
  text-shadow:0 2px 10px rgba(0,0,0,.85),0 0 3px rgba(0,0,0,.7)}
.lcard.voyage .vclock{position:absolute;right:14px;bottom:11px;
  font-size:12.5px;letter-spacing:.1em;color:#dfe9f6;opacity:.92;
  font-variant-numeric:tabular-nums;text-shadow:0 2px 10px rgba(0,0,0,.85)}

/* THE SPRITE MOTION — the 12 principles, at a harbour's pace. Everything here
   is slow in / slow out and gently out of phase: nothing in a real harbour
   moves on the same beat, and two things moving together read as one machine.
   `prefers-reduced-motion` stops the lot; a still harbour is still a harbour. */
@keyframes vSwell{0%,100%{transform:translateX(0)}50%{transform:translateX(-22px)}}
@keyframes vBob{0%,100%{transform:translateY(0) rotate(-1.6deg)}50%{transform:translateY(-3.5px) rotate(1.6deg)}}
@keyframes vGull{0%{transform:translate(-14px,3px)}100%{transform:translate(230px,-9px)}}
@keyframes vTwinkle{0%,100%{opacity:.25}50%{opacity:.9}}
@keyframes vLamp{0%,100%{opacity:.55}50%{opacity:1}}
.vswell-a{animation:vSwell 9s ease-in-out infinite}
.vswell-b{animation:vSwell 13s ease-in-out infinite reverse}
.vswell-c{animation:vSwell 17s ease-in-out infinite}
.vboat,.vboat-slow{transform-box:fill-box;transform-origin:center bottom}
.vboat{animation:vBob 5.5s ease-in-out infinite}
.vboat-slow{animation:vBob 7.2s ease-in-out infinite}
.vgull{animation:vGull 17s linear infinite;opacity:.75}
.vgull-b{animation:vGull 23s linear infinite;animation-delay:-8s;opacity:.5}
.vstar{animation:vTwinkle 4s ease-in-out infinite}
.vlamp{animation:vLamp 5s ease-in-out infinite}
@media (prefers-reduced-motion:reduce){
  .vswell-a,.vswell-b,.vswell-c,.vboat,.vboat-slow,.vgull,.vgull-b,.vstar,.vlamp{animation:none}
}

/* ══ THE VOYAGE SHEET — THE DOOR. The one place that ACTS ═══════════════════
   Kris: "everything else was a visual teaser." Travel controls live HERE and
   nowhere else — the card and the telltale only ever tease. Same law the bench
   proved on native: a SHEET (not a menu), the story effect said BEFORE it can
   happen, and the register CHOSEN, never typed. The filter narrows a list the
   server already sent; it is not free text to the server and it never leaves
   this device.                                                               */
.vsheet{position:fixed;inset:0;z-index:60;display:none;
  background:rgba(4,6,9,.72);backdrop-filter:blur(7px)}
.vsheet.show{display:flex;align-items:flex-end;justify-content:center}
.vsheet-body{width:100%;max-width:560px;max-height:88dvh;display:flex;flex-direction:column;
  background:linear-gradient(180deg,#131b2c,#0b1220);
  border:1px solid var(--card-edge);border-bottom:none;
  border-radius:20px 20px 0 0;box-shadow:0 -18px 60px -18px #000;
  animation:vsheetUp .38s var(--ease-in) both}
@keyframes vsheetUp{from{transform:translateY(30px);opacity:0}to{transform:translateY(0);opacity:1}}
.vsheet-scene{height:96px;flex:none;overflow:hidden;border-radius:19px 19px 0 0;position:relative}
.vsheet-scene svg{display:block;width:100%;height:100%}
.vsheet-head{padding:13px 16px 8px;flex:none}
.vsheet-head h3{font-family:var(--serif);font-weight:400;font-size:22px;margin:0}
.vsheet-head .vnote{color:var(--ink-soft);font-size:14px;margin-top:3px;line-height:1.4}
/* THE STORY EFFECT, said before it happens — contract §5. Changing standing
   retires every outstanding deal about your stall. This warning is not a
   nicety; it is the only place a person can learn it. */
.vsheet-warn{margin:8px 16px 4px;padding:9px 12px;border-radius:12px;
  border:1px solid rgba(230,180,94,.3);background:rgba(230,180,94,.07);
  color:var(--accent);font-size:12.5px;line-height:1.45}
.vsheet-filter{margin:10px 16px;flex:none;display:flex;align-items:center;gap:9px;
  border:1px solid var(--card-edge);border-radius:12px;padding:0 12px;background:rgba(8,12,22,.7)}
.vsheet-filter svg{flex:none;color:var(--ink-dim)}
.vsheet-filter input{flex:1;min-width:0;background:none;border:none;outline:none;
  color:var(--ink);font:inherit;font-size:15.5px;padding:11px 0}
.vsheet-filter input::placeholder{color:var(--ink-dim)}
.vsheet-list{flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;padding:0 10px 18px}
.vgroup{padding:14px 8px 5px;font-size:11.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--ink-dim);position:sticky;top:0;
  background:linear-gradient(180deg,#0e1626 70%,rgba(14,22,38,0))}
.vrow{display:flex;align-items:center;gap:12px;width:100%;text-align:left;
  padding:12px 12px;border:none;border-radius:13px;background:none;color:var(--ink);
  font:inherit;font-size:16.5px;transition:background-color .18s}
.vrow:hover{background:rgba(46,127,150,.12)}
.vrow:active{background:rgba(46,127,150,.2)}
.vrow .vr-when{margin-left:auto;flex:none;font-size:12.5px;color:var(--ink-dim);
  font-variant-numeric:tabular-nums;letter-spacing:.06em}
.vrow.on{background:rgba(46,127,150,.18);box-shadow:inset 0 0 0 1px var(--voyage)}
.vrow.on .vr-when{color:var(--voyage-ink)}
.vrow .vr-tick{flex:none;width:18px;color:var(--voyage-ink);opacity:0}
.vrow.on .vr-tick{opacity:1}
.vsheet-acts{flex:none;display:flex;gap:9px;padding:11px 16px 16px;border-top:1px solid var(--card-edge)}
.vsheet-acts button{flex:1;padding:12px 8px;border-radius:13px;font:inherit;font-size:14.5px;
  background:rgba(46,127,150,.1);border:1px solid color-mix(in srgb,var(--voyage) 60%,transparent);
  color:var(--voyage-ink)}
.vsheet-acts button.quiet{background:none;border-color:var(--card-edge);color:var(--ink-dim)}

/* ── WHAT'S ON — the room's front half (Kris's ruling, 2026-09-01) ──────────
   Travel stopped being a place you choose and became a thing you join. Two
   happenings a day, worldwide; each is one card with exactly one button. The
   world (map, zones, harbours) lives BELOW this, as the half you scroll to. */
.whatson{margin:16px 0 4px}
.wo-head h2{font-family:var(--serif);font-size:27px;line-height:1.1;margin:0}
.wo-note{color:var(--ink-dim);font-size:12.5px;font-style:italic;line-height:1.4;margin:5px 0 13px}
.wo-empty{color:var(--ink-dim);font-size:13px;font-style:italic;line-height:1.45;
  padding:16px 2px 4px}

/* THE DOOR — the progression. Shut, it is the most useful thing on the page:
   it names what is left to finish, where finishing it has an obvious reward. */
.wo-door{display:flex;flex-direction:column;gap:7px;padding:15px 16px;margin:0 0 14px;
  border-radius:16px;border:1px solid color-mix(in srgb,var(--accent) 45%,var(--card-edge));
  background:linear-gradient(160deg,rgba(230,180,94,.09),rgba(255,255,255,.02))}
.wo-door strong{font-family:var(--serif);font-weight:400;font-size:19px;color:var(--accent)}
.wo-door span{color:var(--ink-soft);font-size:13px;line-height:1.45}
.wo-door ul{margin:2px 0 4px;padding-left:17px;color:var(--ink-soft);font-size:12.5px;line-height:1.6}

/* THE HAPPENING CARD. The commissioned postcard is the ground; ink night is
   laid over it so the words read (never a box on top of the art — the art IS
   the ground and the scrim is part of it). One action, and it is unmissable. */
/* ⚠ `.ev` is now the PERSPECTIVE box, not the card skin — the two `.fc-face`
   children carry the border, radius, background and clipping. Leaving
   `overflow:hidden` here would clip the rotating faces mid-flip. */
.ev{position:relative;display:block;margin:0 0 13px}
.ev-on_now .fc-face{border-color:color-mix(in srgb,var(--accent) 60%,var(--card-edge));
  box-shadow:0 0 0 1px rgba(230,180,94,.14),0 14px 34px -22px rgba(0,0,0,.9)}
/* ══ THE FLIP CARD — a GENERIC pattern, used across the product ══════════════
   Kris: *"we make it in all the app and website that we have these flippable
   cards"*. So `.fc` knows nothing about happenings — give it two `.fc-face`
   children and toggle `.is-flipped`. Anything with a pretty front and a wordy
   back can use it.
   ⚠ The card's height is the TALLER face's height, because both faces are
   stacked in the same grid cell. That is deliberate: a card that resized on
   flip would shove the whole board around under the member's thumb. */
.fc{position:relative;perspective:1400px;background:none;border:0;padding:0;
  margin:0 0 13px;display:block}
.fc-inner{position:relative;display:grid;transform-style:preserve-3d;
  transition:transform .52s cubic-bezier(.22,.61,.36,1)}
.fc.is-flipped .fc-inner{transform:rotateY(180deg)}
.fc-face{grid-area:1/1;position:relative;overflow:hidden;border-radius:18px;
  backface-visibility:hidden;-webkit-backface-visibility:hidden;
  background:var(--card);border:1px solid var(--card-edge);min-height:0}
.fc-back{transform:rotateY(180deg)}
/* ⛔ backface-visibility alone still lets the hidden face take pointer events in
   some engines — a member taps the picture and hits a button on the back. */
.fc:not(.is-flipped) .fc-back,.fc.is-flipped .fc-front{pointer-events:none}
.fc-flip{position:absolute;right:10px;bottom:10px;z-index:4;width:30px;height:30px;
  display:grid;place-items:center;border-radius:50%;cursor:pointer;
  background:rgba(6,8,16,.82);border:1px solid rgba(233,237,246,.2);
  backdrop-filter:blur(6px);padding:0}
.fc-flip svg{width:13px;height:13px;fill:var(--ink-soft)}
.fc-flip:hover svg,.fc-flip:focus-visible svg{fill:var(--accent)}
.fc-flip:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
@media (prefers-reduced-motion:reduce){
  .fc-inner{transition:none}
  .fc.is-flipped .fc-inner{transform:none}
  .fc.is-flipped .fc-front{visibility:hidden}
  .fc-back{transform:none;visibility:hidden}
  .fc.is-flipped .fc-back{visibility:visible}
}

/* ══ THE HAPPENING CARD ═════════════════════════════════════════════════════
   🚨 NO TYPE SITS ON A PICTURE. Kris: *"I dont like when we have text over an
   image without a solid background."* A gradient scrim is NOT a solid
   background — how readable it is depends on what the plate happens to be doing
   underneath, so it works on some pictures and fails on others and you cannot
   test your way out of that. The picture is a picture; the words sit on an
   OPAQUE plate below it. */
/* ⭐ ONE VARIABLE OWNS THE PICTURE'S HEIGHT. The art, the plate that sits under
   it and the mark that sits in its corner all read `--art-h`, so they cannot
   drift apart when a variant changes — which is exactly how a mark ends up
   floating in the middle of a picture on one card and off the edge on another. */
.ev{display:block;--art-h:196px}
.ev-small{--art-h:112px}
.ev-p-location,.ev-p-closed{--art-h:150px}
.ev-small.ev-p-location,.ev-small.ev-p-closed{--art-h:96px}

.ev-art{position:absolute;inset:0 0 auto 0;height:var(--art-h);
  background-size:cover;background-position:center;opacity:1}

/* the plate: opaque, hard top edge, the words live here and nowhere else */
.ev-plate{position:relative;z-index:2;display:flex;flex-direction:column;gap:5px;
  margin-top:var(--art-h);padding:14px 16px 16px;background:var(--card);
  border-top:1px solid var(--card-edge)}
.ev-small .ev-plate{padding:11px 14px 13px}
.ev-plate[role=button]{cursor:pointer}
.ev-plate:focus-visible{outline:2px solid var(--accent);outline-offset:-3px}

/* the mark — what the picture is OF. Kris asked for it bottom-right of the
   image, so it hangs off the picture's own bottom edge and never crosses the
   words. It clears the flip button, which owns the card's bottom-right. */
.ev-mark{position:absolute;z-index:3;right:12px;top:calc(var(--art-h) - 40px);
  width:30px;height:30px;display:grid;place-items:center;border-radius:50%;
  background:rgba(6,8,16,.82);border:1px solid rgba(233,237,246,.2);
  backdrop-filter:blur(6px)}
.ev-mark svg{width:13px;height:13px}
.ev-mark-venue{border-color:rgba(230,180,94,.55)}
.ev-mark-venue svg{fill:var(--accent)}
.ev-mark-location svg{fill:#7fd0e4}
.ev-mark-closed svg{fill:var(--ink-dim)}

/* ⛔ CLOSED MUST READ AS CLOSED, NOT AS A BROKEN IMAGE. The first attempt sat at
   24% and Kris called it: *"too hard to see, it looks like a missing image."*
   A dead picture and a shut harbour look identical, and only one of them is
   something we meant. So the grey is legible now and the word does the work. */
.ev-p-closed .ev-art{filter:grayscale(1) contrast(.92) brightness(.9);opacity:.62}
.ev-shut{position:absolute;z-index:3;left:50%;top:calc(var(--art-h)/2);
  transform:translate(-50%,-50%);
  font-size:13px;font-weight:600;letter-spacing:.3em;color:var(--ink);
  background:rgba(6,8,16,.86);border:1px solid rgba(233,237,246,.28);
  padding:7px 15px 7px 18px;border-radius:4px;backdrop-filter:blur(5px)}
.ev-small .ev-shut{font-size:11px;padding:5px 11px 5px 14px}

.ev-when{font-size:10.5px;letter-spacing:.17em;text-transform:uppercase;
  color:var(--accent)}
.ev-p-closed .ev-when{color:var(--ink-dim)}
.ev-title{font-family:var(--serif);font-weight:400;font-size:25px;line-height:1.08;
  margin:0;color:var(--ink)}
.ev-small .ev-title{font-size:19px}
.ev-where{display:flex;flex-wrap:wrap;align-items:center;gap:4px 9px;font-size:13px;
  color:var(--ink-soft)}
.ev-venue{display:inline-flex;align-items:center;gap:5px;color:var(--accent)}
.ev-venue svg{width:11px;height:11px;fill:var(--accent);flex:none}
.ev-port{color:var(--ink-dim)}

/* the back: the picture is present but demoted — Kris asked for "a lesser view
   of the image" — and every word here is on the card's own opaque ground */
.ev-back-art{position:absolute;inset:0 0 auto 0;height:96px;background-size:cover;
  background-position:center;opacity:.4;filter:saturate(.85)}
.ev-back-art::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(19,26,44,0) 0%,var(--card) 100%)}
.ev-back-body{position:relative;z-index:2;display:flex;flex-direction:column;gap:8px;
  padding:70px 16px 52px}
/* .ev-body retired 2026-09-04 — the flip card uses .ev-plate / .ev-back-body */
.ev-when{font-size:10.5px;letter-spacing:.16em;color:var(--accent);text-transform:uppercase}
.ev-opens_soon .ev-when{color:var(--voyage-ink)}
.ev-title{font-family:var(--serif);font-weight:400;font-size:29px;line-height:1.05;margin:0;
  letter-spacing:.01em}
.ev-where{font-size:12.5px;color:var(--ink-soft)}
.ev-blurb{margin:4px 0 10px;font-size:13.5px;line-height:1.45;color:var(--ink);max-width:34em}
/* THE WHOLE CARD IS THE TAP — the CTA is a label on it, never a target
   inside it. A 40px button inside a 300px card the finger was already aiming
   at is a smaller target for no reason. */
.ev[data-go]{cursor:pointer;transition:transform .16s,box-shadow .25s}
.ev[data-go]:active{transform:scale(.985)}
.ev-cta{align-self:flex-start;margin-top:4px;padding:11px 19px;border-radius:14px;
  font-size:12px;letter-spacing:.15em;font-weight:600;color:#08131a;
  background:linear-gradient(180deg,var(--water),var(--water-deep));
  box-shadow:0 8px 20px -12px rgba(111,201,220,.85)}
.ev.going{opacity:.6;pointer-events:none}
.ev.going .ev-cta::after{content:" casting off…"}

/* ⚠ WHAT YOU CANNOT BOARD IS HALF THE SIZE. Giving it the same weight as what
   you can is what turns a board back into a list. */
.ev-small{margin-bottom:10px}
/* (was `.ev-small .ev-art{opacity:.22}` — the picture is a picture now) */
.ev-small .ev-body{padding:16px 15px 15px;gap:3px}
.ev-small .ev-title{font-size:20px}
.ev-small .ev-when{font-size:10px;color:var(--ink-dim)}
/* LAST ORDERS — the final quarter-hour. The line itself changes register (the
   words say it), and the lamp pulses so a glance catches it across the room. */
.ev-closing .ev-when{color:var(--accent);animation:lastorders 1.5s ease-in-out infinite}
@keyframes lastorders{0%,100%{opacity:1}50%{opacity:.55}}
@media (prefers-reduced-motion:reduce){.ev-closing .ev-when{animation:none}}
/* THE BEAT — where the night is up to, on the front plate under the title */
.ev-beat{display:flex;flex-direction:column;gap:1px;margin:-2px 0 4px;font-size:12.5px;
  color:var(--ink-soft);line-height:1.35}
.ev-beat b{font-size:10px;letter-spacing:.17em;text-transform:uppercase;color:var(--accent);
  font-weight:400}
.ev-beat i{font-style:normal;color:var(--ink-dim);font-size:11.5px}
.ev-small .ev-beat{display:none}
.ev-small .ev-where{font-size:12px}

/* THE EVIDENCE — the run of the night, and who keeps the room. */
.ev-agenda{display:flex;flex-direction:column;gap:3px;margin:2px 0 6px;
  padding-left:11px;border-left:2px solid color-mix(in srgb,var(--voyage) 55%,transparent)}
.ev-agenda span{font-size:12.5px;color:var(--ink-soft);line-height:1.4}
.ev-agenda b{display:inline-block;min-width:46px;color:var(--accent);font-weight:400;
  font-variant-numeric:tabular-nums}
.ev-keeper{font-size:12px;color:var(--ink-dim);font-style:italic;margin-bottom:6px}

/* ── THE SCHEDULE ROW — a row in a timetable, not a line in a database ────── */
.sched{display:flex;flex-direction:column;gap:8px;margin-top:9px}
.sr{display:flex;align-items:center;gap:12px;width:100%;padding:12px 13px;text-align:left;
  border-radius:14px;border:1px solid var(--card-edge);background:rgba(255,255,255,.02);
  color:var(--ink);font:inherit;cursor:pointer;transition:transform .15s,border-color .2s}
.sr:active{transform:scale(.99)}
.sr[data-go]{border-color:color-mix(in srgb,var(--water) 40%,var(--card-edge))}
.sr.big{border-color:color-mix(in srgb,var(--accent) 55%,var(--card-edge));
  background:linear-gradient(160deg,rgba(230,180,94,.10),rgba(255,255,255,.02))}
.sr.lounge{border-color:color-mix(in srgb,var(--voyage) 45%,var(--card-edge))}
.sr-mark{flex:none;width:40px;height:40px;border-radius:12px;display:grid;place-items:center;
  font-size:19px;background:rgba(255,255,255,.05);border:1px solid var(--card-edge)}
.sr.big .sr-mark{background:rgba(230,180,94,.14);border-color:transparent}
.sr-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.sr-top{display:flex;align-items:baseline;gap:8px}
.sr-day{font-size:10.5px;letter-spacing:.16em;color:var(--ink-dim)}
.sr-time{font-size:12px;color:var(--ink-soft);font-variant-numeric:tabular-nums}
.sr-big{font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--accent)}
.sr-title{font-family:var(--serif);font-size:17.5px;line-height:1.15;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sr.big .sr-title{font-size:20px}
.sr-where{font-size:12px;color:var(--ink-soft);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sr-reach{font-size:11.5px;color:var(--voyage-ink)}
.sr-chev{flex:none;color:var(--ink-dim);font-size:20px;line-height:1}

/* ── THE SLOW BOAT — off-peak travel, and a temptation rather than a fallback */
.slowboat{display:flex;align-items:center;gap:13px;width:100%;margin-top:14px;padding:15px 14px;
  text-align:left;font:inherit;color:var(--ink);border-radius:17px;cursor:pointer;
  border:1px solid color-mix(in srgb,var(--voyage) 55%,var(--card-edge));
  background:linear-gradient(150deg,rgba(46,127,150,.20),rgba(255,255,255,.02));
  transition:transform .15s}
.slowboat:active{transform:scale(.99)}
.sb-mark{flex:none;width:44px;height:44px;border-radius:14px;display:grid;place-items:center;
  font-size:22px;background:rgba(46,127,150,.22)}
.sb-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}
.sb-body strong{font-family:var(--serif);font-weight:400;font-size:20px}
.sb-body span{font-size:12.5px;line-height:1.4;color:var(--ink-soft)}

/* ── THE NOTICE — why a harbour is shut, with the evidence ───────────────── */
.vsheet-body.notice{gap:0}
.nt-head{padding:2px 0 14px}
.nt-kind{font-size:10.5px;letter-spacing:.17em;text-transform:uppercase;color:var(--accent)}
.nt-head h3{margin:6px 0 5px;font-family:var(--serif);font-weight:400;font-size:24px;line-height:1.15}
.nt-by{font-size:13px;color:var(--ink-soft)}
.nt-dates{font-size:12px;color:var(--ink-dim);margin-top:3px}
.nt-sub{display:block;font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-dim);margin-bottom:6px}
.nt-venue{padding:13px 14px;margin-bottom:14px;border-radius:14px;
  border:1px solid var(--card-edge);background:rgba(255,255,255,.02)}
.nt-venue strong{display:block;font-family:var(--serif);font-weight:400;font-size:19px}
.nt-cap{display:block;font-size:12px;color:var(--ink-soft);margin:3px 0 8px}
.nt-rooms{list-style:none;margin:0;padding:0}
.nt-rooms li{font-size:12.5px;color:var(--ink-soft);padding:3px 0;line-height:1.4}
.nt-rooms b{display:block;color:var(--ink);font-weight:400}
.nt-lines ol{list-style:none;margin:0;padding:0}
.nt-lines li{display:flex;gap:12px;padding:8px 0;font-size:13px;line-height:1.45;
  border-top:1px solid color-mix(in srgb,var(--card-edge) 60%,transparent)}
.nt-lines b{flex:none;width:82px;color:var(--accent);font-weight:400;font-size:11.5px;
  letter-spacing:.04em;padding-top:2px;font-variant-numeric:tabular-nums}
.nt-lines span{color:var(--ink-soft)}


/* LATER IS A LIST, NOT A DECK OF CARDS — an announcement, not an invitation. */
.wo-later{margin:2px 0 6px;border-top:1px solid var(--card-edge);padding-top:10px}
.wo-later summary{cursor:pointer;font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-dim);list-style:none}
.wo-later summary::-webkit-details-marker{display:none}
.wo-later summary span{color:var(--voyage-ink);margin-left:6px}
.wo-later ul{list-style:none;margin:9px 0 0;padding:0}
.evr{display:flex;align-items:baseline;gap:10px;padding:7px 0;font-size:13px;
  border-bottom:1px solid color-mix(in srgb,var(--card-edge) 55%,transparent)}
.evr-when{flex:none;width:76px;font-size:11px;letter-spacing:.1em;color:var(--ink-dim)}
.evr-title{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.evr-where{flex:none;color:var(--ink-soft);font-size:12px}

/* THE WORLD — demoted below the board, and given a rule so the eye knows the
   room has two halves rather than one long list. */
.hub-world{margin-top:22px;padding-top:4px;border-top:1px solid var(--card-edge)}
.hub-top{margin-bottom:2px}

/* THE CROSSING — the ceremony. Four beats, and every one of them skippable. */
.crossing{position:fixed;inset:0;z-index:90;display:grid;place-items:center;text-align:center;
  background:var(--ground);opacity:0;transition:opacity .3s}
.crossing.run{opacity:1}
.crossing.out{opacity:0}
.cx-sky{position:absolute;inset:0;
  background:radial-gradient(120% 80% at 50% 105%,rgba(46,127,150,.55),transparent 62%),
             linear-gradient(180deg,#070d1a,#0e1a2e)}
.cx-word{position:absolute;font-family:var(--serif);font-size:34px;line-height:1.15;
  padding:0 26px;opacity:0}
.crossing.run .cx-1{animation:cxBeat 1s ease both}
.crossing.run .cx-2{animation:cxBeat 1.1s ease .95s both;color:var(--voyage-ink);font-size:23px;letter-spacing:.3em}
.crossing.run .cx-3{animation:cxLand 1.15s var(--ease-in) 1.95s both;color:var(--accent)}
.cx-sub{position:absolute;bottom:24%;font-size:12px;letter-spacing:.18em;color:var(--ink-dim);
  text-transform:uppercase;opacity:0}
.crossing.run .cx-sub{animation:cxBeat 1s ease 2.3s both}
@keyframes cxBeat{0%{opacity:0;transform:translateY(14px)}22%,72%{opacity:1;transform:none}100%{opacity:0;transform:translateY(-12px)}}
@keyframes cxLand{0%{opacity:0;transform:translateY(26px) scale(.94)}45%,100%{opacity:1;transform:none}}
.cx-skip{position:absolute;bottom:34px;right:26px;background:none;border:1px solid var(--card-edge);
  color:var(--ink-dim);border-radius:12px;padding:8px 15px;font:inherit;font-size:11px;letter-spacing:.14em}
@media (prefers-reduced-motion: reduce){.crossing,.crossing *{animation:none !important;transition:none !important}}

/* A LINE THE ROOM SAYS BACK — transient, at the foot, never over content. */
.toast{position:fixed;left:50%;bottom:calc(var(--dock-h) + 16px);transform:translate(-50%,14px);
  z-index:80;max-width:min(92vw,460px);padding:12px 17px;border-radius:14px;
  background:var(--card-2);border:1px solid var(--card-edge);color:var(--ink);
  font-size:13px;line-height:1.4;text-align:center;opacity:0;pointer-events:none;
  box-shadow:0 18px 40px -22px rgba(0,0,0,.95);transition:opacity .25s,transform .25s}
.toast.show{opacity:1;transform:translate(-50%,0)}

/* THE REACH — which two parts of the world this hour suits. A fact about
   clocks, and the reason an event is scheduled where it is. */
.ev-reach{font-size:11.5px;letter-spacing:.04em;color:var(--voyage-ink);margin-bottom:11px}

/* SUNDAY'S OPEN DOORS — rows, never cards. Giving a lounge a poster would make
   the one quiet day of the week look like the six loud ones. */
.wo-lounges{margin:2px 0 14px;padding:12px 14px;border-radius:16px;
  border:1px solid color-mix(in srgb,var(--voyage) 45%,var(--card-edge));
  background:linear-gradient(160deg,rgba(46,127,150,.11),rgba(255,255,255,.02))}
.wo-sub{font-size:10.5px;letter-spacing:.17em;text-transform:uppercase;color:var(--voyage-ink);
  margin-bottom:7px}
.wo-lounges ul{list-style:none;margin:0;padding:0}
.evr-go{margin-left:auto;flex:none;padding:6px 13px;border-radius:11px;font:inherit;font-size:11px;
  letter-spacing:.12em;border:0;color:#08131a;background:linear-gradient(180deg,var(--water),var(--water-deep))}
.evr-go:active{transform:scale(.96)}
.evr.lounge .evr-title{color:var(--voyage-ink)}

/* THE DISPATCH — next week, posted on a Sunday. A moment, so it gets a block. */
.wo-dispatch{margin:14px 0 4px;padding:13px 15px;border-radius:16px;
  border:1px solid color-mix(in srgb,var(--accent) 42%,var(--card-edge));
  background:linear-gradient(160deg,rgba(230,180,94,.10),rgba(255,255,255,.02))}
.wo-dispatch summary{cursor:pointer;list-style:none;display:flex;flex-direction:column;gap:4px}
.wo-dispatch summary::-webkit-details-marker{display:none}
.wo-stamp{font-size:10.5px;letter-spacing:.18em;text-transform:uppercase;color:var(--accent)}
.wo-dispatch strong{font-family:var(--serif);font-weight:400;font-size:21px;line-height:1.1}
.wo-chapter{margin:6px 0 10px;font-size:13px;font-style:italic;line-height:1.45;color:var(--ink-soft)}
.wo-dispatch ul{list-style:none;margin:0;padding:0}

/* THE SEASON — the world admits it has a story running. */
.wo-season{margin:18px 0 2px;padding-top:13px;border-top:1px solid var(--card-edge)}
.wo-season-name{font-size:10.5px;letter-spacing:.19em;text-transform:uppercase;color:var(--ink-dim)}
.wo-season strong{display:block;margin-top:5px;font-family:var(--serif);font-weight:400;font-size:19px}
.wo-season p{margin:5px 0 0;font-size:13px;font-style:italic;line-height:1.5;color:var(--ink-soft)}

/* YOUR TRAVEL LOG — the passport page and the recaps. */
.tlog{margin-top:24px;padding-top:6px;border-top:1px solid var(--card-edge)}
.tl-stamps{display:flex;gap:18px;margin:10px 0 14px;font-size:12px;color:var(--ink-dim)}
.tl-stamps b{display:block;font-family:var(--serif);font-size:24px;color:var(--accent);line-height:1.1}
.tl-night{padding:12px 14px;margin-bottom:10px;border-radius:15px;
  border:1px solid var(--card-edge);background:rgba(255,255,255,.02)}
.tl-when{font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-dim)}
.tl-night h3{margin:4px 0 5px;font-family:var(--serif);font-weight:400;font-size:20px}
.tl-night p{margin:0;font-size:13px;line-height:1.5;color:var(--ink-soft)}

/* ── THE TRAVEL HUB ROOM — the world's room, in the voyage's ink ──────────── */
#hubScroll{padding-top:0}
/* THE MAP — four zone panels of the commissioned world, scroll-snap
   horizontal. The lamps are the ports, reacting: heat is drawn as pulse. */
.hub-map{display:flex;height:192px;margin:0 -22px;overflow-x:auto;overflow-y:hidden;
  scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:none;
  border-bottom:1px solid color-mix(in srgb,var(--voyage) 45%,transparent);background:#0b1526}
.hub-map::-webkit-scrollbar{display:none}
.hm-panel{position:relative;flex:none;width:100%;height:100%;overflow:hidden;scroll-snap-align:start}
.hm-panel img{position:absolute;max-width:none;user-select:none;pointer-events:none}
.hm-lamp{position:absolute;width:7px;height:7px;margin:-3.5px 0 0 -3.5px;border-radius:50%;
  background:#f6e7c6;box-shadow:0 0 6px 1px rgba(246,231,198,.7)}
.hm-lamp.busy{background:var(--accent);animation:lampBusy 1.6s ease-in-out infinite}
.hm-lamp.steady{animation:lampSteady 2.6s ease-in-out infinite}
.hm-lamp.quiet{opacity:.6;width:5.5px;height:5.5px}
.hm-lamp.closed{background:#3d4d63;box-shadow:none;opacity:.7}
@keyframes lampBusy{0%,100%{box-shadow:0 0 6px 2px rgba(230,180,94,.75)}50%{box-shadow:0 0 16px 7px rgba(230,180,94,.35)}}
@keyframes lampSteady{0%,100%{box-shadow:0 0 5px 1px rgba(246,231,198,.55)}50%{box-shadow:0 0 10px 4px rgba(246,231,198,.3)}}
@media (prefers-reduced-motion: reduce){.hm-lamp{animation:none !important}}
.hub-tabs{display:flex;gap:6px;margin:10px 0 2px;overflow-x:auto;scrollbar-width:none}
.hub-tabs::-webkit-scrollbar{display:none}
.hub-tabs button{flex:none;padding:7px 12px;border-radius:12px;font:inherit;font-size:11px;
  letter-spacing:.14em;background:none;border:1px solid var(--card-edge);color:var(--ink-dim)}
.hub-tabs button.on{border-color:color-mix(in srgb,var(--voyage) 65%,transparent);
  color:var(--voyage-ink);background:rgba(46,127,150,.12)}
/* THE PORT ROWS — full width, name first, data underneath, postcard right */
.hub-cards{display:flex;flex-direction:column;gap:11px;margin-top:12px}
.prow{display:flex;align-items:stretch;gap:0;width:100%;padding:0;text-align:left;font:inherit;
  color:var(--ink);border-radius:16px;overflow:hidden;background:rgba(255,255,255,.02);
  border:1px solid var(--card-edge);transition:transform .16s,border-color .2s,box-shadow .25s}
.prow:hover{border-color:var(--voyage)}
.prow:active{transform:scale(.985)}
.prow[data-heat="busy"]{border-color:color-mix(in srgb,var(--accent) 55%,var(--card-edge));
  box-shadow:0 0 18px -6px rgba(230,180,94,.4)}
.prow[data-heat="steady"]{border-color:color-mix(in srgb,var(--voyage) 60%,var(--card-edge))}
.prow.closed{opacity:.55;filter:saturate(.5)}
.prow .pr-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px;padding:12px 12px 12px 14px}
.prow .pr-top{display:flex;align-items:baseline;gap:7px}
.prow .pr-name{font-family:var(--serif);font-size:20px;line-height:1.15}
.prow .pr-hot{color:var(--accent);font-size:13px}
.prow .pr-clock{margin-left:auto;font-size:13px;color:var(--ink-soft);
  font-variant-numeric:tabular-nums;letter-spacing:.07em}
.prow .pr-line{color:var(--ink-soft);font-size:12.5px;line-height:1.35}
.prow .pr-note{color:var(--ink-dim);font-size:12px;font-style:italic;line-height:1.35;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* A CLOSED HARBOUR'S STORY IS THE ROW'S WHOLE POINT — it is the only thing on
   that row worth reading, so it wraps where an open port's note may clip. */
.prow.closed .pr-note{white-space:normal;text-overflow:clip}
.prow .pr-thumb{flex:none;width:96px;background-size:cover;background-position:center;
  border-left:1px solid rgba(0,0,0,.35)}
.hub-head{text-align:center;margin:16px 0 4px}
.hub-head h2{font-family:var(--serif);font-size:27px;font-weight:400;margin:0 0 3px}
.hub-you{color:var(--ink-soft);font-size:14px}
.hub-note{color:var(--ink-dim);font-size:13px;font-style:italic;margin-top:7px;line-height:1.4}
.hub-door{display:block;width:100%;margin:14px 0 6px;padding:12px 8px;border-radius:13px;
  font:inherit;font-size:14.5px;background:rgba(46,127,150,.1);
  border:1px solid color-mix(in srgb,var(--voyage) 60%,transparent);color:var(--voyage-ink)}
.hub-door:active{transform:scale(.985)}
.hub-fault{text-align:center;color:var(--ink-dim);font-size:14px;padding:34px 8px 8px;line-height:1.5}
.hub-btitle{padding:8px 4px 8px;font-size:11.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--ink-dim)}
.vsheet-empty{padding:26px 16px;text-align:center;color:var(--ink-dim);font-size:14px}

/* ── thread (the one text channel) ── */
.thread{flex:1;display:flex;flex-direction:column;min-height:0}
.thread-head{display:flex;align-items:center;gap:6px;padding-right:10px}
.thread-head .thread-cap{flex:1}
.tmenu-btn{flex:none;border:none;background:none;color:var(--ink-dim);font-size:18px;
  letter-spacing:.1em;padding:4px 10px;border-radius:10px;transition:color .2s}
.tmenu-btn:hover{color:var(--water)}
.tsheet{margin:4px 14px 8px;padding:12px;display:flex;flex-direction:column;gap:9px;
  background:rgba(13,18,32,.97);border:1px solid var(--card-edge);border-radius:16px;
  box-shadow:0 12px 30px rgba(0,0,0,.5)}
.ts-act{border:1px solid var(--card-edge);border-radius:12px;background:rgba(18,25,41,.6);
  color:var(--ink-soft);font-size:14.5px;padding:12px 14px;text-align:left;transition:border-color .2s,color .2s}
.ts-act:hover{border-color:var(--water);color:var(--ink)}
.ts-act.danger{color:var(--rose)}
.ts-act.armed{border-color:var(--rose);color:var(--rose);background:rgba(224,138,155,.08)}
.ts-fine{color:var(--ink-dim);font-size:12px;padding:0 2px}
.msgs{flex:1;overflow-y:auto;padding:12px 18px;display:flex;flex-direction:column;gap:10px}
.msgs::-webkit-scrollbar{display:none}
.bubble{max-width:78%;padding:11px 15px;border-radius:18px;font-size:16px;line-height:1.4}
.bubble.them{align-self:flex-start;background:var(--card);border:1px solid var(--card-edge);border-bottom-left-radius:6px}
.bubble.me{align-self:flex-end;background:linear-gradient(180deg,#1c2740,#141d31);
  border:1px solid var(--water-deep);border-bottom-right-radius:6px;color:var(--ink)}
/* the dock below the stage owns the safe area now — the composer keeps only
   its own breathing room */
.composer{display:flex;gap:10px;padding:12px 16px 16px;border-top:1px solid var(--card-edge)}
.composer input{flex:1;background:rgba(18,25,41,.8);border:1px solid var(--card-edge);border-radius:14px;
  color:var(--ink);font:inherit;font-size:16px;padding:12px 15px;outline:none}
.composer input:focus{border-color:var(--water)}
.composer button{background:none;border:1px solid var(--water);border-radius:14px;color:var(--water);
  padding:0 18px;font-size:14px;letter-spacing:.06em}
.thread-cap{text-align:center;font-size:12px;color:var(--ink-dim);padding:8px 0 2px;letter-spacing:.04em}

/* ── the match celebration overlay (a SEAL moment — gold) ── */
.celebrate{position:fixed;inset:0;z-index:40;display:none;flex-direction:column;
  align-items:center;justify-content:center;text-align:center;padding:30px;
  background:radial-gradient(60% 50% at 50% 40%, rgba(230,180,94,.16), rgba(8,11,20,.94) 70%);
  backdrop-filter:blur(3px)}
.celebrate.show{display:flex;animation:fade .5s ease}
@keyframes fade{from{opacity:0}to{opacity:1}}
/* the full dance — the couple steps out of the mark when a mutual lands */
.celebrate .dance{width:min(320px,74vw);margin-bottom:8px;
  filter:drop-shadow(0 0 34px rgba(230,180,94,.45));
  animation:danceIn .7s var(--ease-in) both .15s}
@keyframes danceIn{from{opacity:0;transform:scale(.82) translateY(14px)}
  to{opacity:1;transform:scale(1) translateY(0)}}
.celebrate h2{font-family:var(--serif);font-size:34px;font-weight:600;margin:0 0 8px}
.celebrate p{color:var(--ink-soft);max-width:28ch;margin:0 0 26px}
.celebrate .cbtns{display:flex;gap:14px}
.celebrate .cbtn{padding:13px 22px;border-radius:999px;border:1px solid var(--accent);
  background:linear-gradient(180deg,#23283b,#171c2c);color:var(--accent);font-size:15px}
.celebrate .cbtn.ghost{background:none;border-color:var(--card-edge);color:var(--ink-soft)}

/* ── photos on cards ── */
.pf-photo{width:100%;max-width:320px;height:clamp(200px,34vh,320px);border-radius:22px;margin:6px auto 4px;
  background-size:cover;background-position:center;box-shadow:0 10px 30px rgba(0,0,0,.5)}

/* ── My Profile editor ── */
.mp-head{text-align:center;padding:6px 0 14px}
.mp-head h2{font-family:var(--serif);font-size:30px;font-weight:600;margin:0}
.mp-head .mp-sub{color:var(--ink-dim);font-size:13px;letter-spacing:.02em;margin-top:4px}
.mp-photos{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin:8px 0 22px}
.mp-photo{position:relative;aspect-ratio:3/4;border-radius:14px;background-size:cover;background-position:center;
  border:1px solid var(--card-edge);box-shadow:0 4px 14px rgba(0,0,0,.4)}
.mp-photo .rm{position:absolute;top:5px;right:5px;width:24px;height:24px;border-radius:50%;border:none;
  background:rgba(4,7,14,.85);color:var(--rose);font-size:15px;line-height:22px;text-align:center;cursor:pointer}
.mp-add{aspect-ratio:3/4;border:1px dashed var(--card-edge);border-radius:14px;background:rgba(255,255,255,.02);
  color:var(--ink-soft);font-size:13px;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:6px;cursor:pointer;transition:border-color .2s,color .2s}
.mp-add:hover{border-color:var(--water);color:var(--water)}
.mp-add .plus{font-size:26px;color:var(--water)}
.mp-add.busy{opacity:.6;pointer-events:none}
/* the stall on v2: a photo that is not ready yet wears its state, the hero its place */
.mp-photo.mp-pending{background:repeating-linear-gradient(135deg,rgba(255,255,255,.03) 0 8px,transparent 8px 16px),rgba(18,25,41,.7);
  display:flex;align-items:center;justify-content:center}
.mp-photo .mp-state{font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-dim)}
.mp-photo .mp-hero{position:absolute;left:6px;bottom:6px;font-size:10px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink);background:rgba(4,7,14,.72);padding:2px 7px;border-radius:8px}
.mp-head .mp-standing{margin-top:8px;font-size:12px;letter-spacing:.04em;color:var(--ink-soft)}
.mitem .mname .mage{font-style:normal;font-size:15px;color:var(--ink-dim);margin-left:6px}
.mp-field{margin-bottom:16px}
.mp-field label{display:block;font-size:11px;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-dim);margin-bottom:6px}
.mp-field input,.mp-field textarea{width:100%;background:rgba(18,25,41,.7);border:1px solid var(--card-edge);
  border-radius:12px;color:var(--ink);font:inherit;font-size:16px;padding:11px 14px;outline:none;resize:none}
.mp-field input:focus,.mp-field textarea:focus{border-color:var(--water)}
.mp-field .two{display:flex;gap:10px}
.mp-save{width:100%;padding:14px;border-radius:14px;border:1px solid var(--water);margin-top:6px;
  background:linear-gradient(180deg,#1c2740,#141d31);color:var(--water);font-size:16px;letter-spacing:.02em}
.mp-save:active{transform:scale(.99)}
.mp-saved{color:var(--good);font-size:13px;text-align:center;height:16px;margin-top:8px}
.mp-signout{display:block;margin:22px auto 8px;background:none;border:none;color:var(--ink-dim);
  font-size:13px;border-bottom:1px dashed currentColor;padding:2px 0}
.mp-signout:hover{color:var(--rose)}

/* ── the KronosID gate ── */
.gate{background:radial-gradient(70% 55% at 50% 38%, rgba(230,180,94,.13), rgba(8,11,20,.985) 72%)}
.gate .gate-fine{font-size:12px;color:var(--ink-dim);margin-top:18px;max-width:30ch}
/* ── settings — the quarter's quiet back room ── */
.set-row{margin:14px 0;padding:0 4px}
.set-row label{display:block;font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-dim);margin-bottom:4px}
.set-row .set-val{font-size:15px;color:var(--ink-soft)}
.set-row .set-quiet{color:var(--ink-dim)}
/* the doors you closed — view-only by law; nothing here is a control */
.bl-list{margin-top:6px;border-top:1px solid var(--card-edge)}
.bl-row{display:flex;align-items:center;gap:10px;padding:9px 2px;
  border-bottom:1px solid var(--card-edge)}
.bl-face{flex:none;width:34px;height:34px;border-radius:50%;background-size:cover;
  background-position:center;filter:grayscale(1) brightness(.72);
  border:1px solid var(--card-edge)}
.bl-face.bl-none{background:rgba(255,255,255,.045)}
.bl-who{flex:1;min-width:0}
.bl-name{font-size:14.5px;color:var(--ink-soft);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bl-sub{font-size:11.5px;color:var(--ink-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bl-when{flex:none;font-size:11px;color:var(--ink-dim);letter-spacing:.04em}
.bl-fine{margin-top:8px;font-size:11.5px;color:var(--ink-dim);line-height:1.5;max-width:42ch}
/* leaving — plain, deliberate, and never an overlay */
.set-leave{margin:26px 4px 8px;padding-top:18px;border-top:1px solid var(--card-edge)}
.leave-open{background:none;border:1px solid var(--card-edge);border-radius:12px;
  padding:11px 16px;color:var(--ink-dim);font-size:13.5px;letter-spacing:.04em}
.leave-open:hover{color:var(--rose);border-color:color-mix(in srgb,var(--rose) 45%,transparent)}
.leave-head{font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--rose);margin-bottom:8px}
.leave-body{font-size:14px;color:var(--ink-soft);line-height:1.6;max-width:44ch}
.leave-confirm{margin-top:16px;font-size:13px;color:var(--ink-dim)}
.leave-confirm b{color:var(--ink-soft)}
.leave-input{width:100%;max-width:220px;margin-top:8px;padding:10px 12px;font:inherit;font-size:15px;
  background:rgba(255,255,255,.04);border:1px solid var(--card-edge);border-radius:10px;color:var(--ink)}
.leave-input:focus{outline:none;border-color:var(--water)}
.leave-row{display:flex;gap:10px;flex-wrap:wrap;margin-top:16px}
.leave-cancel{background:none;border:1px solid var(--card-edge);border-radius:12px;
  padding:11px 16px;color:var(--ink-soft);font-size:14px;min-height:44px}
.leave-go{background:none;border:1px solid var(--rose);border-radius:12px;padding:11px 16px;
  color:var(--rose);font-size:14px;min-height:44px}
.leave-go:disabled{opacity:.38;border-color:var(--card-edge);color:var(--ink-dim)}
.leave-said{margin-top:10px;font-size:12.5px;color:var(--rose)}

/* ── a warm one-line banner — rides above the dock where one exists ── */
.banner{position:fixed;left:50%;transform:translateX(-50%);
  bottom:calc(20px + var(--dock-h) + env(safe-area-inset-bottom));z-index:30;
  background:rgba(14,20,34,.94);border:1px solid var(--card-edge);border-radius:14px;
  padding:12px 18px;font-size:14.5px;color:var(--ink);max-width:90vw;text-align:center;
  opacity:0;pointer-events:none;transition:opacity .3s,transform .3s}
.banner.show{opacity:1;transform:translateX(-50%) translateY(-4px)}
.banner .star{color:var(--accent)}

/* ── the feel tuner (?tune=1) — dials for the camera's personality ── */
.tuner{position:fixed;left:10px;bottom:10px;z-index:60;display:none;flex-direction:column;gap:5px;
  background:rgba(6,9,16,.92);border:1px solid var(--card-edge);border-radius:12px;
  padding:10px 12px;font-size:11px;color:var(--ink-dim);max-width:230px}
.tuner.show{display:flex}
.tuner .trow{display:flex;align-items:center;gap:7px}
.tuner .trow label{width:74px;letter-spacing:.04em}
.tuner .trow input{flex:1;accent-color:var(--water)}
.tuner .trow .tv{width:34px;text-align:right;color:var(--ink-soft);font-variant-numeric:tabular-nums}
.tuner .tpresets{display:flex;gap:6px;margin-top:4px}
.tuner .tpresets button{flex:1;background:#121929;border:1px solid var(--card-edge);border-radius:8px;
  color:var(--ink-soft);padding:4px 6px;font-size:11px}
.tuner .tpresets button:hover{border-color:var(--water);color:var(--water)}

/* ── dev bar (demo-only) ── */
.devbar{position:fixed;left:0;right:0;bottom:calc(var(--dock-h) + env(safe-area-inset-bottom));z-index:50;display:none;gap:8px;
  align-items:center;justify-content:center;padding:7px;background:rgba(4,7,14,.9);
  border-top:1px solid var(--card-edge);font-size:12px;color:var(--ink-dim)}
.devbar.show{display:flex}
.devbar input{width:80px;background:#121929;border:1px solid var(--card-edge);border-radius:8px;
  color:var(--ink);padding:4px 7px;font-size:12px}
.devbar button{background:#121929;border:1px solid var(--card-edge);border-radius:8px;
  color:var(--ink-soft);padding:4px 9px;font-size:12px}
.devbar button:hover{border-color:var(--water);color:var(--water)}
.devbar .tag{letter-spacing:.14em;text-transform:uppercase;color:var(--accent-soft)}

.loading{color:var(--ink-dim);font-size:14px;letter-spacing:.06em}

/* ══ THE THRESHOLD — the door a new person meets (readiness.go) ═════════════
   It reuses .celebrate's ground so it feels like the same world as the gate
   and the mutual, but it is a LIST rather than a moment: someone reads it,
   works through it, and comes back. So the copy is left-aligned and the type
   is smaller than a celebration's — this is a checklist, not an announcement. */
.celebrate.threshold{justify-content:flex-start;padding-top:max(34px,7vh);overflow-y:auto;
  /* room under the last button. Without it the final action sits flush
     against the bottom edge — the same class of bug as the unreachable
     ledge (v42): reachable in the layout, not reachable by a thumb. */
  padding-bottom:max(46px,14vh)}
.celebrate.threshold .gate-mark{width:min(190px,44vw);margin-bottom:14px}
.celebrate.threshold h2{font-size:28px}
.celebrate.threshold > p{max-width:34ch;margin-bottom:22px}

.steps{display:flex;flex-direction:column;gap:12px;width:min(430px,92vw);text-align:left}
.step{display:flex;gap:13px;align-items:flex-start;padding:15px 16px;border-radius:16px;
  border:1px solid var(--card-edge);background:linear-gradient(180deg,rgba(30,36,54,.86),rgba(18,22,34,.86))}
/* A finished step stays on screen rather than vanishing: the list must not
   reshuffle under a thumb, and seeing what you have already done is the part
   that makes a checklist feel survivable. */
.step.done{opacity:.5;padding:11px 16px}
.step-mark{flex:none;width:20px;height:20px;margin-top:2px;border-radius:6px;
  border:1.5px solid var(--card-edge);display:flex;align-items:center;justify-content:center;
  font-size:12px;color:#0d1018}
.step.done .step-mark{background:var(--accent);border-color:var(--accent)}
.step-body{flex:1;min-width:0}
.step-title{font-weight:600;font-size:15.5px;color:var(--ink)}
.step.done .step-title{font-weight:500}
.step-note{color:var(--ink-soft);font-size:13.5px;line-height:1.45;margin-top:3px}
.step-act{display:flex;flex-wrap:wrap;gap:9px;margin-top:12px;align-items:center}
.step-act.col{flex-direction:column;align-items:stretch}
.step-act .cbtn{padding:11px 18px;font-size:14px;border-radius:999px;border:1px solid var(--accent);
  background:linear-gradient(180deg,#23283b,#171c2c);color:var(--accent);cursor:pointer}
.step-act .cbtn.ghost{background:none;border-color:var(--card-edge);color:var(--ink-soft)}
.step-act .cbtn:disabled{opacity:.55;cursor:default}
.step-input{width:100%;padding:12px 14px;border-radius:12px;border:1px solid var(--card-edge);
  background:#0f1320;color:var(--ink);font-size:15px;font-family:inherit}
.step-input:focus{outline:none;border-color:var(--accent)}
.step-err{color:#f6a6a6;font-size:13px;min-height:0}
.step-err:empty{display:none}
.hidden-file{display:none}

/* ══ THE REPORT SHEET ══════════════════════════════════════════════════════ */
/* Above the threshold. In real flows you cannot reach a report from behind
   the threshold — deck and threads are both gated — but two overlays that
   can both be .show must have a defined order, or they blend. */
.celebrate.report{z-index:41;justify-content:flex-start;padding-top:max(34px,8vh);overflow-y:auto;padding-bottom:max(46px,14vh)}
.celebrate.report h2{font-size:26px;margin-bottom:6px}
.celebrate.report > p{max-width:34ch;margin-bottom:18px}
.reasons{display:flex;flex-direction:column;gap:8px;width:min(430px,92vw);margin-bottom:14px}
.reason{text-align:left;padding:13px 15px;border-radius:13px;font-size:14.5px;cursor:pointer;
  border:1px solid var(--card-edge);background:linear-gradient(180deg,rgba(30,36,54,.86),rgba(18,22,34,.86));
  color:var(--ink-soft);font-family:inherit}
.reason.on{border-color:var(--accent);color:var(--ink);box-shadow:0 0 0 1px var(--accent) inset}
#rpDetail{width:min(430px,92vw);padding:12px 14px;border-radius:13px;border:1px solid var(--card-edge);
  background:#0f1320;color:var(--ink);font-size:14.5px;font-family:inherit;resize:vertical;margin-bottom:18px}
#rpDetail:focus{outline:none;border-color:var(--accent)}
.celebrate .cbtn.danger{border-color:#8d4a52;color:#f0b3b3}
.celebrate .cbtn.danger:disabled{opacity:.45}
.celebrate.report .gate-fine{max-width:34ch;margin-top:16px}

/* report, reachable from the card itself — the deck is where you meet a
   stranger, so it is where a report most often needs to start. Quiet by
   default: it must be findable without being the loudest thing on a face. */
.ad-report{margin-top:14px;padding:9px 16px;border-radius:999px;font-size:12.5px;cursor:pointer;
  border:1px solid var(--card-edge);background:none;color:var(--ink-dim);font-family:inherit}
.ad-report:hover,.ad-report:focus-visible{color:#f0b3b3;border-color:#8d4a52}

/* The thread menu's report sits with unmatch and block but is not two-tap —
   putting friction on the way to help is the wrong side to put it on. */
#tsReport{color:#f0b3b3}

/* ══ THE V2 DECK — deal plates, look up, go in (2026-09-04) ═════════════════
   Every word about a DEAL sits on its own OPAQUE plate on the reading card —
   above the photograph, never on it, never a scrim. States differ in KIND: a
   gold plate says somebody smiled, an ink plate with a clock says a happening
   dealt this card, a dashed grey label says this is a bench figure. Nobody
   reads opacity. */
.dl-plate{width:min(340px,84vw);margin:0 auto 14px;padding:12px 16px;border-radius:14px;
  background:var(--card);border:1px solid var(--card-edge);color:var(--ink-soft);font-size:14px;line-height:1.4;
  display:flex;flex-direction:column;gap:3px;align-items:center;text-align:center}
.dl-plate .star{color:var(--accent)}
.dl-smile{background:linear-gradient(180deg,#2a2314,#1a1710);border-color:var(--accent);color:var(--ink);
  font-family:var(--serif);font-size:18px;line-height:1.3}
.dl-occasion{border-color:color-mix(in srgb,var(--voyage) 70%,var(--card-edge))}
.dl-met{font-size:10.5px;letter-spacing:.17em;text-transform:uppercase;color:var(--voyage-ink)}
.dl-when{font-size:13px;color:var(--ink-soft);font-variant-numeric:tabular-nums}
/* LAST ORDERS on the card itself — the same bell as the board's, same lamp */
.dl-closing{border-color:var(--accent)}
.dl-closing .dl-when{color:var(--accent);letter-spacing:.06em;animation:lastorders 1.5s ease-in-out infinite}
@media (prefers-reduced-motion:reduce){.dl-closing .dl-when{animation:none}}
.dl-sim{background:#1c1c22;border-style:dashed;border-color:#3a3a46;color:var(--ink-dim);
  font-size:11.5px;letter-spacing:.08em;text-transform:uppercase}
.dl-standing{font-size:12.5px;color:var(--ink-dim);flex-direction:row;gap:5px;justify-content:center}
.dl-room{color:var(--accent)}
.qcard .dl-plate{width:100%;margin:-4px 0 18px}

/* LOOK UP and THE ROOM — their own solid plate UNDER the go-plate on the
   on_now card, so a tap on either can never board a happening. */
.ev-acts{position:relative;z-index:2;display:flex;flex-direction:column;gap:9px;
  padding:0 16px 14px;background:var(--card)}
.ev-lookup{display:flex;flex-direction:column;align-items:flex-start;gap:2px;text-align:left;width:100%;
  padding:11px 14px;border-radius:12px;border:1px solid color-mix(in srgb,var(--voyage) 70%,var(--card-edge));
  background:color-mix(in srgb,var(--voyage) 16%,var(--card));color:var(--ink);font:inherit;cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.ev-lookup b{font-size:10px;letter-spacing:.17em;text-transform:uppercase;color:var(--accent);font-weight:400}
.ev-lookup span{font-size:13.5px;line-height:1.3}
.ev-lookup i{font-style:normal;color:var(--ink-dim);font-size:11.5px}
.ev-lookup:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.ev-lookup.going b::after{content:" · asking"}
/* GO IN — the one door on the on_now card while you are there: THE ROOM */
.ev-goin{display:flex;flex-direction:column;align-items:flex-start;gap:2px;text-align:left;width:100%;
  padding:12px 16px;border-radius:12px;border:1px solid var(--accent);
  background:linear-gradient(180deg,#2a2314,#1a1710);color:var(--accent);font:inherit;font-size:14px;
  letter-spacing:.14em;text-transform:uppercase;cursor:pointer;-webkit-tap-highlight-color:transparent}
.ev-goin span{font-size:11.5px;letter-spacing:.02em;text-transform:none;color:var(--ink-soft)}
.ev-goin:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* THE DOOR, wherever it is offered off the board itself (the promise sheet, the
   harbour). ⚠ `.ev-go` carried no base rule until v69 — it rendered as a raw
   browser button on the event sheet. A door is a THRESHOLD: gold on dark, the
   same instrument as `.ev-goin`, never a default control. */
.ev-go{display:inline-block;padding:12px 18px;border-radius:12px;border:1px solid var(--accent);
  background:linear-gradient(180deg,#2a2314,#1a1710);color:var(--accent);font:inherit;font-size:14px;
  letter-spacing:.14em;text-transform:uppercase;cursor:pointer;-webkit-tap-highlight-color:transparent}
.ev-go:active{transform:scale(.985)}
.ev-go:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* ══ THE ROOM — what happens when you go somewhere (dq-room/1, 2026-09-04 late) ═
   A full-screen solid ground. The plate is a letterboxed strip at the top with
   NO type on it; every word below sits on the room's own ground or on a plate.
   ⛔ No text input anywhere in here. */
.room{position:fixed;inset:0;z-index:50;background:#0b1220;color:var(--ink);overflow-y:auto;
  -webkit-overflow-scrolling:touch;animation:roomIn .32s ease both}
@keyframes roomIn{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.room{animation:none}}
.rm-body{max-width:560px;margin:0 auto;padding:0 0 60px}
.rm-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:16px 16px 10px}
.rm-head h2{font-family:var(--serif);font-weight:400;font-size:26px;line-height:1.08;margin:2px 0}
.rm-kicker{display:block;font-size:10.5px;letter-spacing:.17em;text-transform:uppercase;color:var(--accent)}
.rm-where{font-size:13px;color:var(--ink-dim)}
.rm-ground{height:150px;background-size:cover;background-position:center;border-top:1px solid var(--card-edge);
  border-bottom:1px solid var(--card-edge)}
.rm-say{margin:12px 16px 6px;font-size:13.5px;color:var(--ink-soft);line-height:1.45}
.rm-note{font-size:11.5px;color:var(--ink-dim)}
.rm-btn{padding:11px 18px;border-radius:999px;border:1px solid var(--accent);font:inherit;font-size:14px;
  background:linear-gradient(180deg,#2a2314,#1a1710);color:var(--accent);cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.rm-btn.ghost{background:none;border-color:var(--card-edge);color:var(--ink-soft)}
.rm-btn:disabled{border-style:dashed;color:var(--ink-dim);cursor:default}
.rm-leave{flex:none;margin-top:4px}
/* AREAS — spots on the floor. The whole head is the tap; the one you stand in differs in kind (a gold edge, a YOU token). */
.rm-status{margin-top:8px;border:1px dashed var(--card-edge);border-radius:999px;background:none;color:var(--ink-soft);font:inherit;
  font-size:12px;padding:6px 12px;cursor:pointer;font-style:italic}
.rm-pl{font-size:11.5px;color:var(--accent);font-style:italic;line-height:1.3}
.rm-lines{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;padding:6px 0 10px}
.rm-line{border:1px solid var(--card-edge);border-radius:999px;background:none;color:var(--ink);font:inherit;font-size:14px;padding:10px 14px;cursor:pointer}
.rm-line.is-on{border-color:var(--accent);color:var(--accent)}
.rm-line.is-none{color:var(--ink-dim)}
/* THE PLACE — one card, full width, as tall as it needs. Moving is a
   deliberate GO below it, and the camera goes with you. */
.rm-place{margin:8px 12px 0;border:1px solid var(--accent);border-radius:18px;background:var(--card);overflow:hidden}
.rm-place.is-leaving{opacity:0;transform:translateX(-24px);transition:opacity .24s ease,transform .24s ease}
.rm-place.is-arriving{animation:rmArrive .36s ease}
@keyframes rmArrive{from{opacity:0;transform:translateX(28px)}to{opacity:1;transform:none}}
.rm-pic{aspect-ratio:3/2;background-size:cover;background-position:center;border-bottom:1px solid var(--card-edge)}
.rm-pic.is-none{display:flex;align-items:center;justify-content:center;background:var(--card-2)}
.rm-pic.is-none span{font-family:var(--serif);font-size:30px;color:var(--ink-dim);text-align:center;padding:0 20px}
.rm-card-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;padding:12px 14px 2px}
.rm-act.is-doing{border-color:var(--accent);color:var(--accent)}
.rm-guests{display:flex;flex-direction:column;gap:8px;padding:10px 12px 12px}
.rm-guest{display:flex;align-items:center;gap:12px;width:100%;padding:8px 10px;border:1px solid var(--card-edge);border-radius:14px;background:var(--card-2);color:var(--ink);font:inherit;text-align:left;cursor:pointer}
.rm-guest.is-you{border-color:var(--accent);cursor:default}
.rm-guest.is-new{animation:rmWalkIn .5s ease}
@keyframes rmWalkIn{from{opacity:0;transform:translateX(18px)}to{opacity:1;transform:none}}
.rm-face{flex:none;width:44px;height:44px;border-radius:50%;background-size:cover;background-position:center;border:1px solid var(--card-edge)}
.rm-face.is-none{display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:22px;color:var(--ink-dim);background:var(--card)}
.rm-guest-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.rm-guest-body b{font-family:var(--serif);font-weight:400;font-size:17px}
.rm-guest-body b i{font-style:normal;font-size:13px;color:var(--ink-dim);margin-left:6px}
.rm-sub{font-size:12.5px;color:var(--ink-soft)}
/* ── THE GAIT (2026-09-08) ──────────────────────────────────────────────────
   Replaces `rmIdle`, which was ONE keyframe at ONE period and therefore nine
   figures swaying in harmony — Kris saw it immediately.

   ⭐ THREE INDEPENDENT PROPERTIES, NOT THREE TRANSFORMS. `rotate`, `translate`
   and `scale` are their own animatable properties now, so three animations
   COMPOSE on one element. Written as three `transform` animations the last
   would simply have won and the other two would have done nothing — which is
   the trap this whole idea rests on avoiding.

   Every number arrives from JS as a custom property, per person, per redraw
   (gaitStyle): three periods that are not simple fractions of one another, so
   the sum takes minutes to repeat, and three delays anchored to the WALL CLOCK
   so the room's 8-second DOM rebuild does not jump. The amplitude carries the
   sign, so half the room leans the other way.

   Cost per frame: nothing. These are compositor properties and no JS runs
   between redraws. */
.rm-guest .av-gait{flex:none;transform-origin:50% 100%;will-change:rotate,translate,scale;
  animation:gaitRock var(--g1,3s) ease-in-out var(--d1,0s) infinite,
            gaitDrift var(--g2,4.1s) ease-in-out var(--d2,0s) infinite,
            gaitBreath var(--g3,5.7s) ease-in-out var(--d3,0s) infinite}
@keyframes gaitRock{0%,100%{rotate:calc(var(--amp,2deg) * -1)}50%{rotate:var(--amp,2deg)}}
@keyframes gaitDrift{0%,100%{translate:calc(var(--shift,1px) * -1) 0}50%{translate:var(--shift,1px) calc(var(--bob,1px) * -1)}}
@keyframes gaitBreath{0%,100%{scale:1}50%{scale:var(--breath,1.008)}}

/* THE BEAT — a gesture fires because a FACT CHANGED, never on a timer. One
   shot each, over the gait, on `transform` so it never fights the three
   properties above. Each is a different MOVEMENT, not a louder one — the same
   law as the comic-book alarm. */
.rm-guest .av-moment{animation-name:gaitRock,gaitDrift,gaitBreath,gestMoment;
  animation-duration:var(--g1),var(--g2),var(--g3),1.1s;
  animation-delay:var(--d1),var(--d2),var(--d3),0s;
  animation-iteration-count:infinite,infinite,infinite,1;
  animation-timing-function:ease-in-out,ease-in-out,ease-in-out,cubic-bezier(.18,1.22,.4,1)}
.rm-guest .av-smile{animation-name:gaitRock,gaitDrift,gaitBreath,gestSmile;
  animation-duration:var(--g1),var(--g2),var(--g3),1.1s;
  animation-delay:var(--d1),var(--d2),var(--d3),0s;
  animation-iteration-count:infinite,infinite,infinite,1;
  animation-timing-function:ease-in-out,ease-in-out,ease-in-out,ease-out}
.rm-guest .av-move,.rm-guest .av-act{animation-name:gaitRock,gaitDrift,gaitBreath,gestShift;
  animation-duration:var(--g1),var(--g2),var(--g3),.9s;
  animation-delay:var(--d1),var(--d2),var(--d3),0s;
  animation-iteration-count:infinite,infinite,infinite,1;
  animation-timing-function:ease-in-out,ease-in-out,ease-in-out,ease-in-out}
/* they pulled something off — a hop, and they come down settling */
@keyframes gestMoment{0%{transform:none}22%{transform:translateY(-7px) scaleY(1.04)}
  48%{transform:translateY(0) scaleY(.97)}72%{transform:translateY(-2px)}100%{transform:none}}
/* they smiled at YOU — a turn toward the reader, and a small bow */
@keyframes gestSmile{0%{transform:none}30%{transform:rotate(6deg) translateY(-2px)}
  60%{transform:rotate(-1deg)}100%{transform:none}}
/* they started doing something, or crossed the room — a shift of weight */
@keyframes gestShift{0%{transform:none}35%{transform:translateX(3px) rotate(-3deg)}
  70%{transform:translateX(-1px) rotate(1deg)}100%{transform:none}}
.rm-go{margin:14px 12px 0;display:flex;flex-direction:column;gap:8px}
.rm-go-row{display:flex;align-items:center;gap:12px;padding:8px 10px 8px 8px;border:1px solid var(--card-edge);border-radius:14px;background:var(--card);color:var(--ink);font:inherit;text-align:left;cursor:pointer}
.rm-go-pic{flex:none;width:72px;height:48px;border-radius:9px;background-size:cover;background-position:center;background-color:var(--card-2)}
.rm-go-body{flex:1;min-width:0;display:flex;flex-direction:column}
.rm-go-body b{font-family:var(--serif);font-weight:400;font-size:17px}
.rm-go-body span{font-size:12px;color:var(--ink-dim)}
.rm-go-arrow{font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--accent)}
.rm-hero{width:100%;max-width:300px;aspect-ratio:4/5;border-radius:16px;background-size:cover;background-position:center;border:1px solid var(--card-edge)}
.rm-hero.is-none{display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:64px;color:var(--ink-dim);background:var(--card-2)}
.rm-real h3 i{font-style:normal;font-size:16px;color:var(--ink-dim);margin-left:8px}
.mp-figure-row{display:flex;align-items:center;gap:12px}
.mp-figure-row .rm-note{flex:1}
/* ⚠ THE GUARD MUST NAME THE NEW CLASSES. `.av-idle` no longer exists, and a
   guard that names a dead class is not a guard. */
@media (prefers-reduced-motion:reduce){.rm-guest .av-gait,.rm-guest .av-moment,.rm-guest .av-smile,
  .rm-guest .av-move,.rm-guest .av-act,.rm-place.is-arriving,.rm-guest.is-new{animation:none}}
.rm-area-name{font-family:var(--serif);font-size:19px}
.rm-area-do{font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-dim);white-space:nowrap}
.rm-actions{display:flex;flex-wrap:wrap;gap:6px;padding:10px 12px;border-bottom:1px solid var(--card-edge)}
.rm-act{border:1px solid var(--card-edge);border-radius:999px;padding:9px 13px;font:inherit;font-size:13.5px;
  color:var(--ink);background:var(--card);cursor:pointer;-webkit-tap-highlight-color:transparent}
.rm-act.is-game{border-color:var(--voyage-ink);color:var(--voyage-ink)}
.rm-people{display:flex;flex-wrap:wrap;gap:8px;padding:10px 12px 12px;min-height:44px}
.rm-people:empty::after{content:"nobody here just now";font-size:12px;color:var(--ink-dim);padding:6px 4px}
/* PEOPLE — avatar tokens. The whole token is the tap. YOU differ in kind: gold edge, no tap. */
.rm-person{display:flex;flex-direction:column;align-items:center;gap:2px;width:108px;padding:8px 6px 9px;
  border:1px solid var(--card-edge);border-radius:14px;background:var(--card-2);color:var(--ink);font:inherit;
  cursor:pointer;-webkit-tap-highlight-color:transparent;text-align:center}
.rm-person.is-you{border-color:var(--accent)}
.rm-person .av{display:block}
.av-kit{position:relative;display:block}
.av-kit img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;pointer-events:none;user-select:none}
.rm-pn{font-family:var(--serif);font-size:15px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rm-pa{font-size:11px;color:var(--ink-soft);line-height:1.3}
.rm-pm{font-size:11px;color:var(--voyage-ink);line-height:1.3}
.rm-smiled{font-size:11px;color:var(--accent)}
.rm-sim{font-size:9.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-dim);border:1px dashed #3a3a46;
  border-radius:6px;padding:2px 5px;margin-top:2px}
/* THE GAME — the dealt combination, then a d-pad. The server judges. */
.rm-game{margin:8px 12px 0;padding:14px 14px 12px;border:1px solid var(--voyage-ink);border-radius:16px;background:var(--card);
  display:flex;flex-direction:column;align-items:center;gap:8px;text-align:center}
.rm-combo{display:flex;gap:8px}
.rm-combo b{width:38px;height:38px;border-radius:10px;border:1px solid var(--card-edge);display:flex;align-items:center;
  justify-content:center;font-size:20px;font-weight:400;color:var(--ink);background:var(--card-2)}
.rm-combo b.pressed{border-color:var(--voyage-ink);color:var(--voyage-ink)}
.rm-combo b.hit{border-color:var(--accent);background:var(--accent);color:#1a1408}
.rm-combo b.miss{border-style:dashed;color:var(--ink-dim)}
.rm-score{font-family:var(--serif);font-size:20px;font-weight:400}
.rm-dpad{display:grid;grid-template-columns:repeat(3,64px);grid-template-rows:repeat(2,56px);gap:6px;justify-content:center}
.rm-key{border:1px solid var(--card-edge);border-radius:12px;background:var(--card-2);color:var(--ink);font:inherit;font-size:24px;
  cursor:pointer;-webkit-tap-highlight-color:transparent}
.rm-key[data-press=up]{grid-column:2;grid-row:1}
.rm-key[data-press=left]{grid-column:1;grid-row:2}
.rm-key[data-press=down]{grid-column:2;grid-row:2}
.rm-key[data-press=right]{grid-column:3;grid-row:2}
.rm-key:active{background:var(--voyage-ink);color:#0b1220}
.rm-game-btns{display:flex;gap:10px}
/* THE TRAVEL PROFILE — a sheet inside the room: avatar, name, what they are doing, SMILE. Never the real card. */
.rm-sheet{position:fixed;inset:0;z-index:2;background:rgba(4,6,9,.72);display:flex;align-items:flex-end;justify-content:center}
.rm-sheet[hidden]{display:none}   /* author display beats the hidden attribute — say it twice or the scrim eats every tap */
.rm-card{width:100%;max-width:560px;display:flex;flex-direction:column;align-items:center;gap:6px;padding:22px 18px 26px;
  background:linear-gradient(180deg,#131b2c,#0b1220);border:1px solid var(--card-edge);border-bottom:0;border-radius:20px 20px 0 0;
  text-align:center;
  /* ⚠ A SHEET RISES FROM THE BOTTOM, so content taller than the screen loses
     its TOP — the heading and the picture, in silence, with no way to reach
     them. The builder is the tallest sheet we have (a 210px figure, the slot
     tabs, a part for every choice, the swatches, two buttons) and it grew
     again when facial hair made a seventh tab wrap to a second row. Capped
     and scrollable, so a short phone can still reach every control. */
  max-height:88vh;overflow-y:auto;overscroll-behavior:contain}
.rm-card h3{font-family:var(--serif);font-weight:400;font-size:26px;margin:4px 0 0}
.rm-card-where{font-size:13px;color:var(--ink-soft)}
.rm-smile{margin-top:12px;font-size:16px;padding:13px 30px}
/* THE EXIT — the bridge. Each row is a person who smiled at you; VIEW is an ordinary deal in the deck. */
.rm-exit{padding:10px 12px 0;display:flex;flex-direction:column;gap:10px}
.rm-row{display:flex;align-items:center;gap:12px;padding:10px 12px;border:1px solid var(--card-edge);border-radius:14px;background:var(--card)}
.rm-row-body{flex:1;min-width:0;font-size:14px;line-height:1.4}
.rm-row-body b{font-family:var(--serif);font-weight:400;font-size:17px}
.rm-exit-close{align-self:center;margin-top:8px}

/* THE BUILDER — your character from the drawn kit */
.rm-build{gap:10px}
.bd-stage{display:flex;justify-content:center;padding:4px 0 2px}
.bd-slots{display:flex;gap:6px;flex-wrap:wrap;justify-content:center}
/* 🚨 `.rm-dot` HAD NO RULE AT ALL, and the builder's ONLY navigation was
   therefore seven blank white boxes — `button{color:inherit}` put near-white
   ink (--ink) on the browser's own near-white button ground, so the slot names
   were rendered and invisible. Present since the builder shipped (4 Sep) and
   found by reading the stylesheet for the class, not by any test — the second
   time a used-but-unstyled class has cost us a control (see `.ev-go`, 5 Sep).
   Treated as the SAME instrument as `.hub-tabs button`, because it is the same
   thing: a row of tabs choosing which slot you are editing. Water for the one
   you are on — a tab is a pressable, and gold is spent on thresholds. */
.bd-slots .rm-dot{flex:none;padding:7px 12px;border-radius:12px;font:inherit;font-size:11px;
  letter-spacing:.14em;text-transform:uppercase;background:none;border:1px solid var(--card-edge);color:var(--ink-dim)}
.bd-slots .rm-dot.is-on{border-color:color-mix(in srgb,var(--voyage) 65%,transparent);
  color:var(--voyage-ink);background:rgba(46,127,150,.12)}
.bd-slots .rm-dot:focus-visible{outline:2px solid var(--water);outline-offset:2px}
.bd-parts{display:flex;gap:8px;overflow-x:auto;width:100%;padding:6px 2px;scrollbar-width:none}
.bd-parts::-webkit-scrollbar{display:none}
.bd-part{flex:none;display:flex;flex-direction:column;align-items:center;gap:2px;width:78px;padding:6px 4px;border:1px solid var(--card-edge);border-radius:12px;background:var(--card-2);color:var(--ink-soft);font:inherit;font-size:10.5px;cursor:pointer}
.bd-part.is-on{border-color:var(--accent);color:var(--ink)}
.bd-part .av-thumb{overflow:hidden}
.bd-swatches{display:flex;gap:8px;flex-wrap:wrap;justify-content:center}
.bd-swatch{width:30px;height:30px;border-radius:50%;border:2px solid var(--card-edge);cursor:pointer}
.bd-swatch.is-on{border-color:var(--accent);box-shadow:0 0 0 2px var(--card),0 0 0 3px var(--accent)}

/* ══ THE DOOR — the landing as two sides of one door (Kris, 5 Sep 2026) ═════
   OUT THERE: the window on your harbour at the hour it is there (sky by the
   band, the painted plate below it, a slow drift so it is alive), then the two
   doors that side owns. THE LINE. YOURS: warmer, interior, no world picture —
   your people and your stall. Lamps carry the state; a door with something
   waiting is lit in its own colour and its faces wear the state on the ring.
   No type sits on a picture: the words live on the plates below. */
#landingScroll{padding-top:4px}
.ld-sect{position:relative;padding:8px 0 4px}
.ld-eyebrow{display:flex;align-items:baseline;gap:10px;margin:2px 2px 8px;min-width:0}
.ld-eyebrow b{font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;font-weight:400;flex:none}
.ld-eyebrow span{color:var(--ink-dim);font-size:12.5px;line-height:1.3;min-width:0;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.ld-out .ld-eyebrow b{color:var(--voyage-ink)}
.ld-yours .ld-eyebrow b{color:var(--rose)}

/* the window: a sky band, then the plate as a letterboxed panorama strip */
.ld-window{position:relative;height:184px;border-radius:18px;overflow:hidden;
  border:1px solid var(--card-edge);background:var(--card);margin-bottom:10px;
  box-shadow:0 18px 40px -26px rgba(0,0,0,.9)}
.ld-sky{position:absolute;inset:0 0 auto 0;height:58px;
  background:linear-gradient(180deg,var(--sky1),var(--sky2) 60%,var(--sky3))}
.ld-disc{position:absolute;left:18%;top:var(--discY,40%);width:26px;height:26px;margin:-13px 0 0 -13px;border-radius:50%;
  background:radial-gradient(circle,var(--disc) 0 34%,color-mix(in srgb,var(--disc) 55%,transparent) 36% 52%,transparent 70%);
  animation:ldDrift 140s linear infinite alternate}
.ld-star{position:absolute;left:var(--x);top:var(--y);width:var(--s,1.5px);height:var(--s,1.5px);border-radius:50%;background:#e9f2ff;
  animation:ldTwinkle 3.6s ease-in-out infinite;animation-delay:var(--d,0s)}
.ld-pic{position:absolute;left:0;right:0;top:58px;bottom:0;background-size:cover;background-position:50% 50%;
  animation:ldPan 90s ease-in-out infinite alternate}
.ld-pic-sea{background:linear-gradient(180deg,#1f4b63,#0f2438)}
.ld-window::after{content:"";position:absolute;left:0;right:0;top:58px;height:1px;background:rgba(0,0,0,.35)}
.ld-mark{position:absolute;z-index:3;right:12px;bottom:12px;width:28px;height:28px;display:grid;place-items:center;border-radius:50%;
  background:rgba(6,8,16,.82);border:1px solid rgba(233,237,246,.2);backdrop-filter:blur(6px)}
.ld-mark svg{width:12px;height:12px;fill:#7fd0e4}
/* at night the lamps in the picture are the point — a warm breath over it */
.ld-band-night .ld-pic,.ld-band-evening .ld-pic{filter:saturate(1.05)}
.ld-band-night .ld-window::before{content:"";position:absolute;z-index:2;left:0;right:0;top:58px;bottom:0;pointer-events:none;
  background:radial-gradient(60% 50% at 70% 80%,rgba(230,180,94,.14),transparent 70%);animation:ldBreathe 5s ease-in-out infinite}
@keyframes ldPan{from{background-position:50% 38%}to{background-position:50% 62%}}
@keyframes ldDrift{from{transform:translateX(0)}to{transform:translateX(64px)}}
@keyframes ldTwinkle{0%,100%{opacity:.45;transform:scale(1)}50%{opacity:1;transform:scale(1.5)}}
@keyframes ldBreathe{0%,100%{opacity:.55}50%{opacity:1}}

/* the doors: two up, one solid plate each, the name first, one fact, the faces */
.ld-doors{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.ld-door{position:relative;display:flex;flex-direction:column;align-items:stretch;text-align:left;padding:0;min-height:128px;
  background:var(--card);border:1px solid var(--card-edge);border-radius:16px;overflow:hidden;
  transition:border-color .25s,box-shadow .25s,transform .15s}
.ld-door:hover{border-color:var(--lc)}
.ld-door:active{transform:scale(.985)}
.ld-door:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.ld-water{--lc:var(--water);--lcs:rgba(111,201,220,.45)}
.ld-voyage{--lc:var(--voyage-ink);--lcs:rgba(79,162,189,.45)}
.ld-gold{--lc:var(--accent);--lcs:rgba(230,180,94,.45)}
.ld-rose{--lc:var(--rose);--lcs:rgba(224,138,155,.45)}
.ld-door.lit{border-color:color-mix(in srgb,var(--lc) 70%,var(--card-edge));box-shadow:0 0 24px -6px var(--lcs)}
.ld-dart{display:block;height:64px;background-size:cover;background-position:center;border-bottom:1px solid var(--card-edge)}
.ld-plate{display:flex;flex-direction:column;gap:4px;padding:12px 12px 12px;flex:1}
.ld-name{font-family:var(--serif);font-size:19px;color:var(--ink);display:flex;align-items:center;gap:7px}
.ld-lamp{width:7px;height:7px;border-radius:50%;background:color-mix(in srgb,var(--lc) 30%,transparent);flex:none;transition:background .3s,box-shadow .3s}
.ld-door.lit .ld-lamp{background:var(--lc);box-shadow:0 0 10px 2px var(--lcs);animation:ldLamp 2.4s ease-in-out infinite}
@keyframes ldLamp{0%,100%{box-shadow:0 0 8px 1px var(--lcs)}50%{box-shadow:0 0 16px 4px var(--lcs)}}
.ld-fact{color:var(--ink-soft);font-size:13.5px;line-height:1.3}
.ld-sub{color:var(--ink-dim);font-size:12px;line-height:1.3;margin-top:auto;padding-top:4px}
.ld-go{position:absolute;right:10px;top:10px;color:var(--lc);font-size:17px;opacity:.7}
.ld-door.lit .ld-go{opacity:1;animation:wdBreathe 2.6s ease-in-out infinite}
.ld-faces{display:flex;margin-top:4px;padding-left:2px}
.ld-fw{width:34px;height:34px;border-radius:50%;flex:none;margin-right:-8px;padding:2px;background:var(--card);
  border:1.5px solid color-mix(in srgb,var(--lc) 35%,#0b1220);position:relative}
.ld-fc{display:flex;width:100%;height:100%;border-radius:50%;background-size:cover;background-position:center;background-color:#16283e;
  align-items:center;justify-content:center;font-family:var(--serif);font-size:13px;color:#dfe9f6}
.ld-fw-new{border-color:var(--lc);box-shadow:0 0 10px -1px var(--lcs)}
.ld-fw-yes::after{content:"✦";position:absolute;right:-3px;bottom:-4px;font-size:10px;color:var(--accent);
  background:var(--card);border-radius:50%;width:14px;height:14px;display:grid;place-items:center}
.ld-fw-seen .ld-fc{opacity:.72}

/* THE LINE — between the two sides. A match makes it glow once. */
.ld-line{display:flex;align-items:center;gap:10px;margin:14px 2px 10px;color:var(--ink-dim);font-size:11px;letter-spacing:.14em;text-transform:uppercase}
.ld-line i{flex:1;height:1px;background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--accent) 55%,var(--card-edge)),transparent)}
.ld-line span{flex:none;white-space:nowrap}
.ld-line b{color:var(--accent);font-weight:400}
.ld-line.crossed i{background:linear-gradient(90deg,transparent,var(--accent),transparent);animation:ldLine 2.2s ease-in-out infinite}
.ld-line.crossed span{color:var(--ink-soft)}
@keyframes ldLine{0%,100%{opacity:.6}50%{opacity:1}}
.ld-yours .ld-doors{position:relative}
.ld-yours .ld-door{background:linear-gradient(180deg,#171b2c,#121728)}
.ld-yours{padding-bottom:10px}

/* the door's entrance: one beat, top to bottom */
.ld-sect,.ld-line{animation:arrive .5s var(--ease-in) both}
.ld-line{animation-delay:90ms}.ld-yours{animation-delay:160ms}
#landingScroll.still .ld-sect,#landingScroll.still .ld-line{animation:none}
@media (prefers-reduced-motion:reduce){
  .ld-pic,.ld-disc,.ld-star,.ld-door.lit .ld-lamp,.ld-line.crossed i,.ld-band-night .ld-window::before,.ld-sect,.ld-line{animation:none}
}

/* ══ THE LINE, AT THE LEDGE — on the swiping card (Kris, 5 Sep 2026) ══════════ */
.dc-line{display:flex;align-items:center;gap:8px;width:min(300px,80vw);margin:18px auto 0;
  font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-dim)}
.dc-side{flex:none}.dc-side-yours{color:var(--rose)}
.dc-rail{flex:1;height:1px;position:relative;background:linear-gradient(90deg,color-mix(in srgb,var(--water) 60%,transparent),color-mix(in srgb,var(--accent) 70%,transparent) 50%,color-mix(in srgb,var(--rose) 70%,transparent))}
.dc-you{position:absolute;top:50%;left:10%;width:10px;height:10px;margin:-5px 0 0 -5px;border-radius:50%;background:var(--water);
  box-shadow:0 0 10px 2px rgba(111,201,220,.5);transition:left .6s var(--ease-in),background .6s}
.dc-line-seen .dc-you{background:var(--ink-soft);box-shadow:none}
.dc-line-yes .dc-you{left:50%;background:var(--accent);box-shadow:0 0 12px 3px rgba(230,180,94,.55);animation:ldLamp 2.4s ease-in-out infinite}
.wplinth.spent .dc-line{opacity:.6}
.dc-wait{display:inline-flex;align-items:center;gap:8px;padding:13px 20px;border-radius:999px;border:1px solid color-mix(in srgb,var(--accent) 55%,var(--card-edge));color:var(--ink-soft);font-size:14.5px}
.dc-wait .star{color:var(--accent)}

/* the world's own line at the foot: the season the engine is in, server-written */
.ld-season{margin:18px 6px 6px;text-align:center;color:var(--ink-dim);font-size:12px;line-height:1.45}
.ld-season b{display:block;font-weight:400;font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--voyage-ink);margin-bottom:3px}
.ld-season span{font-family:var(--serif);font-style:italic;font-size:13.5px;color:var(--ink-soft);display:block;max-width:34ch;margin:0 auto}

/* ══ THE BOARD IS DOORS (Kris, 5 Sep 2026 — CLIENT_REQUEST_WHATS_ON.md) ══════ */
/* ⭐ A FLIP CARD IS THE HEIGHT OF ITS FRONT. The back scrolls inside it. The
   grid trick (both faces in one cell) made every front as tall as its wordy
   back — that was the "huge grey empty space" under GO. */
.fc-inner{display:block}
.fc-front{position:relative}
.fc-back{position:absolute;inset:0;overflow-y:auto;-webkit-overflow-scrolling:touch}
.ev-p-none{--art-h:0px}
.ev-p-none .ev-plate{border-top:0}
.wo-why{color:var(--ink-soft);font-size:13.5px;line-height:1.45;margin:6px 0 4px;max-width:36ch}
.hub-top .hub-you{margin-top:4px}
.wo-tier{margin:16px 0 2px}
.wo-tier .wo-sub{margin-bottom:8px}
.wo-now .ev{--art-h:196px}
.wo-next .ev{--art-h:120px}
.wo-next .ev.ev-small{--art-h:96px}
.ev-cta-sub{display:block;margin-top:-2px;font-size:11.5px;color:var(--ink-dim)}
.wo-harbours{margin:16px 0 4px;border-top:1px solid var(--card-edge);padding-top:12px}
.wo-harbours summary{cursor:pointer;list-style:none;display:flex;flex-direction:column;gap:3px;
  font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-dim)}
.wo-harbours summary::-webkit-details-marker{display:none}
.wo-harbours summary span{color:var(--voyage-ink);margin-left:6px}
.wo-harbours summary i{font-style:normal;text-transform:none;letter-spacing:0;font-size:12.5px;color:var(--ink-dim);line-height:1.4}
.wo-harbours[open] summary{margin-bottom:6px}
.wo-harbours .hub-world{margin-top:6px;border-top:0;padding-top:0}
.wo-harbours .hub-note{margin:8px 2px 6px;color:var(--ink-dim);font-size:12px;font-style:italic}
.flash{animation:evFlash 2.4s ease-out}
@keyframes evFlash{0%{box-shadow:0 0 0 0 rgba(230,180,94,.9)}100%{box-shadow:0 0 0 16px rgba(230,180,94,0)}}
/* the event sheet — a promise with a time */
.evsheet .es-art{height:150px;background-size:cover;background-position:center;border-radius:16px 16px 0 0}
.evsheet .es-body{padding:14px 16px 18px;display:flex;flex-direction:column;gap:8px}
.evsheet h3{font-family:var(--serif);font-weight:400;font-size:26px;margin:2px 0 0;line-height:1.05}
.es-where{color:var(--ink-soft);font-size:13px}
.es-blurb{margin:2px 0 4px;font-size:14px;line-height:1.5;color:var(--ink)}
.es-doors{font-size:12.5px;color:var(--accent);letter-spacing:.02em}
.evsheet .ev-go,.evsheet .hub-door{align-self:flex-start}

/* ══ THE HARBOUR SHEET (v69) ═══════════════════════════════════════════════
   Kris, 5 Sep: a port is a place you can travel to, not a label on a list.
   The picture is the establishing shot at the hour it is there; the LAMP
   carries open/shut (⛔ never a badge, never opacity); every block below the
   picture is an opaque plate, so no type ever sits on the art. */
.hbsheet .hb-art{position:relative;height:158px;background-size:cover;background-position:center;
  border-radius:16px 16px 0 0}
.hb-lamp{position:absolute;right:12px;bottom:10px;width:11px;height:11px;border-radius:50%;
  background:#ffd479;box-shadow:0 0 0 3px rgba(255,212,121,.22),0 0 16px 4px rgba(255,196,88,.55)}
.hb-lamp.out{background:#5b7392;box-shadow:0 0 0 3px rgba(91,115,146,.22)}
.hbsheet .hb-body{padding:14px 16px 18px;display:flex;flex-direction:column;gap:9px}
.hbsheet h3{font-family:var(--serif);font-weight:400;font-size:29px;margin:2px 0 0;line-height:1.02}
.hb-mood{color:var(--ink-soft);font-size:13px;letter-spacing:.01em;font-variant-numeric:tabular-nums}
.hb-note{margin:0;font-size:14px;line-height:1.5;color:var(--ink)}
/* what is on here — a door, a promise, or the honest absence. All three are
   the same shape, so the difference a member reads is the WORDS, not a guess. */
.hb-on{display:flex;flex-direction:column;gap:3px;text-align:left;width:100%;
  padding:11px 13px;border-radius:14px;border:1px solid var(--card-edge);
  background:var(--card);color:var(--ink);font:inherit}
.hb-on.open{border-color:var(--accent)}
.hb-on.soon{cursor:pointer}
.hb-on.soon:active{transform:scale(.99)}
.hb-on.none,.hb-on.shut{opacity:1;border-style:dashed;color:var(--ink-soft)}
.hb-sub{font-size:10.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-soft)}
.hb-on strong{font-family:var(--serif);font-weight:400;font-size:18px;line-height:1.15}
.hb-when{font-size:12.5px;color:var(--ink-soft)}
.hb-on.open .ev-go{margin-top:7px;align-self:flex-start}
.hb-notice{display:flex;flex-direction:column;gap:3px;text-align:left;width:100%;
  padding:11px 13px;border-radius:14px;border:1px solid var(--card-edge);background:transparent;
  color:var(--ink);font:inherit;cursor:pointer}
.hb-notice strong{font-family:var(--serif);font-weight:400;font-size:16px;line-height:1.2}
/* the crossing */
.hb-cross{margin-top:3px;padding-top:11px;border-top:1px solid var(--card-edge);
  display:flex;flex-direction:column;gap:6px}
.hb-go{align-self:flex-start;padding:11px 17px;border-radius:13px;cursor:pointer;
  border:1px solid var(--voyage-ink);background:rgba(46,127,150,.16);color:var(--water);
  font:inherit;font-size:13.5px;letter-spacing:.08em;text-transform:uppercase}
.hb-go:active{transform:scale(.985)}
.hb-go[disabled]{opacity:.6}
.hb-here{align-self:flex-start;padding:9px 15px;border-radius:13px;
  border:1px dashed var(--voyage-ink);color:var(--water);font-size:13.5px;letter-spacing:.04em}
.hb-fine{font-size:11.5px;color:var(--ink-soft);line-height:1.45}
@media (prefers-reduced-motion:reduce){.hb-on.soon:active,.hb-go:active{transform:none}}


/* ── THE FIGURE LEADS, AND THE CARD IS A HINT (2026-09-08) ──────────────────
   Two of Kris's asks land in the same row: the little figures got PROMINENT
   (62px at the head of the row, still idling), and the person sheet got enough
   of the real card to decide on. The face did not shrink out of the way — it
   moved to the tail at 44px, because judging a person off a drawn figure is
   the thing we promised never to make anybody do. */
.rm-guest .av-gait{margin:-6px 0 -8px}          /* the taller figure keeps the row's rhythm */
.rm-guest-body b{font-size:17.5px}
/* one shape, three times: a micro-label above the person's own words. It is
   the QUIET instrument — no border, no fill; the sheet's gold is spent on the
   smile, which is the only door on it. */
.rm-hint{align-self:stretch;display:flex;flex-direction:column;gap:1px;padding:7px 0 0;
  border-top:1px solid var(--card-edge);text-align:left}
.rm-hint:first-of-type{border-top:0}
.rm-hint-k{font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-dim)}
.rm-hint p{margin:0;font-family:var(--serif);font-size:16px;line-height:1.34;color:var(--ink)}
/* the figure again, small, so the sheet says out loud WHICH person in the room
   this card belongs to — the tap has no other way to point back at the world */
.rm-figure-note{display:flex;align-items:center;gap:9px;align-self:stretch;padding-top:4px}
.rm-figure-note>span{font-size:11.5px;color:var(--ink-dim);line-height:1.3}

/* ═══ MIST SMILES (dq-mist/1) ══════════════════════════════════════════════
   The smile you did not give, left at the harbour. Its whole visual argument
   is that it is NOT a smile: the smile is gold and warm and in the moment,
   mist is cold and pale and patient. ⛔ It is never a faded smile plate —
   FREEZE §D.16, a state differs in KIND and nobody reads opacity. */

/* the card's plate — water, not gold, and the commissioned vapour behind the
   words rather than a star in front of them */
.dl-mist{background:linear-gradient(180deg,#141d24,#0e1419);
  border-color:color-mix(in srgb,var(--voyage) 70%,var(--card-edge));color:var(--ink);
  font-family:var(--serif);font-size:18px;line-height:1.3;overflow:hidden}
/* ⚠ A BAND ABOVE THE WORDS, NOT A LAYER BEHIND THEM. The plate is a column
   flex and its sentence is a bare text node, so an absolutely-positioned mark
   would paint OVER type that has no element to lift it back — art must never
   be able to break what it decorates (FREEZE §D.16). As a flex item it can
   only ever take its own row. */
/* 🚨 NO BLEND MODE. The marks were cut WITH AN ALPHA CHANNEL on 8 Sep — the
   luminance-to-coverage conversion already happened in `kit.py`, it is not
   something the stylesheet has to redo. Screening them over the plate composited
   their dark pixels as well, and the vapour came out as two grey smudges sitting
   above the words like eyebrows. Looked at, not assumed: the art is 512x295
   RGBA with alpha running the full 0–255. Drawn flat with its own alpha, it is
   vapour. */
/* 🚨 CONTAIN, NOT A CROP, AND GIVE IT THE HEIGHT. The mark is a FACE — a round
   head of haze, two eyes, a nose, and the crescent mouth. Cropping it cut the
   mouth's tips off; starving it of height closed the eyes up into the mouth,
   which is the wide-mouth-small-eyes proportion Kris called a horror vibe.
   Judged at this size rather than at full size. */
.dl-mist .mistmark{display:block;position:relative;width:100%;height:92px;flex:none;
  opacity:.9;pointer-events:none}
/* ⭐ THE BLINK. Two layers, crossfaded: the face, and the same face with its
   eyes shut into a little smile. They have to swap rather than stack, or the
   open eyes show through the closed ones.
   ⛔ AND NO TWO BLINK TOGETHER. The period and the starting offset both come
   from the deal's own id (mistStyle), because a deck of mist cards blinking in
   unison is the exact fault Kris caught in the room's little people on 8 Sep —
   "all swaying the same way in harmony". The offset is NEGATIVE so every mark
   starts mid-cycle and none of them waits to come alive. */
.dl-mist .mistmark::before,.dl-mist .mistmark::after{
  content:"";position:absolute;inset:0;
  background-repeat:no-repeat;background-position:center bottom;background-size:contain;
  animation:var(--mist-period,7s) mistBlink infinite var(--mist-offset,0s)}
.dl-mist .mistmark::before{background-image:var(--mist-open)}
.dl-mist .mistmark::after{background-image:var(--mist-blink);animation-name:mistBlinkShut}
/* a blink is ~110ms of a 5–10s cycle, twice, because people blink in pairs */
@keyframes mistBlink{0%,90.4%{opacity:1}90.8%,92.0%{opacity:0}92.4%,94.0%{opacity:1}
  94.4%,95.6%{opacity:0}96%,100%{opacity:1}}
@keyframes mistBlinkShut{0%,90.4%{opacity:0}90.8%,92.0%{opacity:1}92.4%,94.0%{opacity:0}
  94.4%,95.6%{opacity:1}96%,100%{opacity:0}}
@media (prefers-reduced-motion:reduce){
  .dl-mist .mistmark::before,.dl-mist .mistmark::after{animation:none}
  .dl-mist .mistmark::after{opacity:0}
}

/* the harbour that is holding something for you */
.prow .pr-mist{color:var(--voyage-ink);font-size:13px;letter-spacing:.08em}
.hb-mist{margin-top:10px;padding:11px 12px;border-radius:12px;background:var(--card);
  border:1px solid color-mix(in srgb,var(--voyage) 70%,var(--card-edge));
  display:flex;flex-direction:column;gap:3px}
.hb-mist strong{font-family:var(--serif);font-size:17px;line-height:1.2}

/* WHO HAS GONE — the strip that makes mist reachable. Quieter than the floor
   above it: these people are not here, and the section must never compete
   with the room they left. */
.rm-gone{margin:10px 12px 0;padding:12px 12px 10px;border-radius:16px;background:var(--card);
  border:1px solid var(--card-edge);display:flex;flex-direction:column;gap:8px}
.rm-gone .rm-row{opacity:.92;align-items:flex-start}
/* ⚠ A COLUMN, NOT AN INLINE RUN. `.rm-row-body` is the exit row's shape and
   the exit row carries a SHORT status line; a real subtitle ("has opinions
   about tea temperature") wrapped around the name, pushed the sentence into
   the button and made the row unreadable. Seen on the bench, not predicted. */
.rm-gone-body{display:flex;flex-direction:column;gap:1px}
.rm-gone-body .rm-sub{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rm-gone-say{font-size:12.5px;color:var(--ink-dim);line-height:1.35}
.rm-gone .rm-btn,.rm-gone .rm-note{flex:none;align-self:center}
/* their little figure stands in for the face the media door will not serve */
.rm-gone-fig{flex:none}
.rm-gone-hero{display:flex;justify-content:center;padding:6px 0 2px}
.rm-gone .rm-say{font-size:11.5px;color:var(--ink-dim);font-style:italic;line-height:1.4;margin:2px 0 0}
.rm-mist-btn{border-color:color-mix(in srgb,var(--voyage) 70%,var(--card-edge));color:var(--voyage-ink)}
.rm-misted{color:var(--voyage-ink);font-size:11px;letter-spacing:.06em}
