
html,body{margin:0;background:#F2DFDE;color:#3B1526;font-family:Inter,system-ui,sans-serif;-webkit-font-smoothing:antialiased}
*{box-sizing:border-box}
a{color:#3B1526;text-decoration:none}
a:hover{color:var(--acc-ink)}
button{font-family:inherit}
:focus-visible{outline:2px solid var(--acc);outline-offset:2px}
::selection{background:rgba(var(--acc-rgb),.20)}
:root{--acc:#0E8A60;--acc-rgb:14,138,96;--warm:#E8A317;--warm-rgb:232,163,23;--warm-200:#C9871B;--sand:#C08894;--sand-rgb:192,136,148;--sand-200:#72505A;
  --s-grad:linear-gradient(180deg,#FFF4F3,#FBE8E7);--s-0:#F7E7E6;--s-1:#FFF4F3;--s-2:#FFFAFA;
  --bd:#EFD4D2;--bd-2:#DFB6B4;--bd-3:#F6E2E1;--bd-4:#E5C2C0;
  --el-1:0 1px 2px rgba(94,40,44,.06),0 2px 6px rgba(94,40,44,.05);
  --el-2:0 2px 4px rgba(94,40,44,.06),0 8px 20px rgba(94,40,44,.09);
  --el-3:0 4px 10px rgba(94,40,44,.07),0 20px 48px rgba(94,40,44,.13);
  --glass:rgba(253,250,244,.88);--glass-2:rgba(247,241,230,.94);--glass-3:rgba(250,245,236,.94);--glass-4:rgba(253,250,244,.9);
  --t-0:#3B1526;--t-1:#5C2A3D;--t-2:#74495A;--t-3:#7F5A69;--t-4:#6E374C;--warm-ink:#7A4F0B;--acc-ink:#0A6647;--screen-pad:16px;--card-pad:16px;--dur-screen:.42s;--dur-row:.34s;--dur-sheet:.32s;--dur-micro:.15s;--dur-comp:.24s;--ease:cubic-bezier(.22,1,.36,1);--ease-out:cubic-bezier(.33,1,.68,1)}
#shell,#qRoot{
  --s-grad:linear-gradient(180deg,#FFF4F3,#FAE4E3);--s-0:#F2DFDE;--s-1:#FFF4F3;--s-2:#FFFAFA;
  --bd:#EDD0CE;--bd-2:#DDB2B0;--bd-3:#F5E0DF;--bd-4:#E3BFBD;
  --glass:rgba(250,245,235,.92);--glass-2:rgba(244,237,224,.95);--glass-3:rgba(248,242,232,.95);--glass-4:rgba(251,247,239,.92);
  --t-0:#361322;--t-1:#57273A;--t-2:#74495A;--t-3:#795564;--t-4:#6A3448;--warm-ink:#7A4F0B;--acc-ink:#0A6647;
}
#shell{display:grid;grid-template-columns:minmax(0,1fr)}
#mapPane{display:none}
@media (min-width:1000px){
  #shell{grid-template-columns:400px minmax(0,1fr)}
  #mapPane{display:block}
  /* Every section has two map hosts: a small one in the scrolling column for a
     phone, and the full-height side pane for a wide screen. Both being on
     screen at once meant the inline one won — it comes first in the DOM — and
     the pane sat empty and grey beside it. Above this width the pane is the
     map, so the inline hosts and the List/Map toggle that only exists for them
     go away. Same rule #mapInline has always followed. */
  .t-inline-map{display:none!important}
  .t-view-toggle{display:none!important}
  #colBorder{border-right:1px solid var(--bd)}
  #mapScreen{display:flex;flex-direction:column}
  #mapInline{display:none}
  #mapTop{position:static;background:none;padding:14px 14px 0}
  #mapSheet{position:static;top:auto!important;flex:1;min-height:0;border-radius:0;background:none;border-top:0;box-shadow:none;transition:none}
  #mapSheet>div:first-child{cursor:default}
  #mapSheet>div:first-child>span:first-child{display:none}
}
#shell::after{content:"";position:fixed;inset:0;z-index:200;opacity:.5;pointer-events:none;background-image:radial-gradient(rgba(94,40,44,.05) .5px,transparent .5px);background-size:2px 2px;mix-blend-mode:multiply}
#shell::before{content:"";position:fixed;inset:0;z-index:199;pointer-events:none;background:radial-gradient(120% 90% at 50% 40%,transparent 55%,rgba(74,56,32,.05) 100%),radial-gradient(70% 46% at 86% 2%,rgba(var(--warm-rgb),.07) 0%,transparent 60%),radial-gradient(60% 40% at 6% 96%,rgba(var(--acc-rgb),.05) 0%,transparent 62%)}
.leaflet-control-attribution{display:none!important}
.leaflet-container a{color:#6A3448}
/* The credit, behind a small circle. Required by the map licence, so it is
   always reachable — just not painted over the city. */
.t-credit{width:20px;height:20px;border-radius:50%;display:grid;place-items:center;border:0;cursor:pointer;background:rgba(255,250,250,.9);color:#6A3448;font:600 12px/1 Georgia,serif;box-shadow:0 1px 3px rgba(74,56,32,.22)}
.t-credit-text{display:none;white-space:nowrap;padding:3px 7px;border-radius:9px;background:rgba(255,250,250,.94);color:#6A3448;font-size:10px;box-shadow:0 1px 3px rgba(74,56,32,.22)}
.t-credit-text a{color:#6A3448}
.t-credit-open .t-credit-text{display:block}
.t-credit-open .t-credit{display:none}
h1,h2{letter-spacing:-.03em;text-wrap:pretty}
h1{font-weight:500}
p{text-wrap:pretty}
#lpRoot section{scroll-margin-top:72px}
@keyframes t-cat-pop{0%{opacity:0;transform:translateY(14px) scale(.84)}52%{opacity:1;transform:translateY(-3px) scale(1.055)}76%{transform:translateY(0) scale(.986)}100%{opacity:1;transform:none}}
@keyframes t-cat-badge{0%{opacity:0;transform:scale(.4) rotate(-14deg)}60%{opacity:1;transform:scale(1.18) rotate(3deg)}100%{opacity:1;transform:none}}
/* ── Phones ────────────────────────────────────────────────────────────────
   Most people use Trident on a phone, and on Android it ships inside the Play
   Store app (Chrome underneath). */

/* 100vh on a phone is the height WITH the browser's address bar hidden, so the
   bottom tab bar sat under the bar and out of reach. dvh is the real, current
   height. The inline 100vh stays as the fallback for older browsers. */
@supports (height:100dvh){
  #shell,#colBorder,#mapPane{height:100dvh!important}
}
/* Notches, rounded corners and the gesture bar. */
#sectionSwitch{padding-top:max(8px,env(safe-area-inset-top))!important}
nav[aria-label="Main"]{padding-bottom:env(safe-area-inset-bottom)}
/* Taps: no 300ms double-tap-to-zoom wait, no grey flash, and a pull at the top
   of a list scrolls the list rather than reloading the whole app. */
html,body{-webkit-tap-highlight-color:transparent;overscroll-behavior-y:contain}
button,a,input,textarea,[role=tab]{touch-action:manipulation}
/* Chips keep their look but get a finger-sized hit area. Android asks for
   48dp; chips in dense rows at 38px, with gaps, stay easy to hit. */
.t-chip{min-height:38px}
.leaflet-touch .leaflet-bar a{width:40px!important;height:40px!important;line-height:40px!important}
/* 16px inputs: anything smaller makes mobile browsers zoom the page on focus. */
@media (max-width:600px){ input,textarea{font-size:16px!important} }

/* ── Motion ────────────────────────────────────────────────────────────────
   Entrances use fill-mode `backwards`, not `both`: `both` holds the last
   keyframe's transform forever, and a held `transform:none` silently cancels
   every hover lift and press scale written after it. The engine keeps DOM
   between renders, so these play when an element first appears, not on every
   keystroke; a `key` on a wrapper replays them on purpose (the area filter). */

/* Categories: tiles */
.t-cat{position:relative;overflow:hidden;transform-origin:50% 80%;
  animation:t-cat-pop .58s cubic-bezier(.34,1.56,.64,1) backwards;
  transition:transform .32s cubic-bezier(.34,1.56,.64,1),box-shadow .25s ease,border-color .22s ease!important}
.t-cat:hover{transform:translateY(-4px) rotate(-.4deg);box-shadow:0 14px 30px rgba(94,40,44,.16)!important}
.t-cat:active{transform:translateY(0) scale(.95);transition:transform .09s ease!important}
/* A light sweep across the tile on hover. */
.t-cat::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(105deg,transparent 30%,rgba(255,255,255,.55) 48%,transparent 66%);
  transform:translateX(-120%)}
.t-cat:hover::after{transition:transform .75s cubic-bezier(.22,1,.36,1);transform:translateX(120%)}
.t-cat-badge{animation:t-cat-badge .55s cubic-bezier(.34,1.56,.64,1) backwards}
.t-cat:hover .t-cat-badge{animation:t-wiggle .6s cubic-bezier(.34,1.56,.64,1)}
/* The count rolls up into place, so a new area's numbers read as new. */
.t-cat-count{display:inline-block;animation:t-count-in .5s cubic-bezier(.22,1,.36,1) backwards}
/* Counting an area: tiles breathe until the numbers land. */
[data-loading="true"] .t-cat{animation:t-skel 1.1s ease-in-out infinite}

/* Categories: group titles slide in and draw an accent rule */
.t-cat-head{display:flex;align-items:center;gap:10px;animation:t-head-in .5s cubic-bezier(.22,1,.36,1) backwards}
.t-cat-head::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,rgba(var(--warm-rgb),.55),transparent);
  transform-origin:0 50%;animation:t-rule-draw .8s cubic-bezier(.22,1,.36,1) backwards;animation-delay:inherit}

/* Chips everywhere: press, and pop when switched on */
.t-chip{transition:transform .22s cubic-bezier(.34,1.56,.64,1),background .2s ease,border-color .2s ease,color .2s ease!important}
.t-chip:active{transform:scale(.92)}
.t-chip[aria-pressed="true"]{animation:t-chip-on .42s cubic-bezier(.34,1.56,.64,1)}

/* Home cards */
.t-home-card{animation:t-home-in .62s cubic-bezier(.34,1.4,.64,1) backwards;
  transition:transform .3s cubic-bezier(.34,1.56,.64,1),box-shadow .25s ease,border-color .2s ease!important}
.t-home-card:hover{transform:translateY(-5px);box-shadow:0 18px 38px rgba(94,40,44,.16)}
.t-home-card:active{transform:scale(.96);transition:transform .09s ease!important}
.t-home-card:hover .t-home-icon{animation:t-float 1.4s ease-in-out infinite}
.t-home-icon{animation:t-cat-badge .6s cubic-bezier(.34,1.56,.64,1) backwards;animation-delay:inherit}

/* List cards in Cafés, Stays and See */
.t-list-card{animation:t-row .45s cubic-bezier(.22,1,.36,1) backwards;
  transition:transform .25s cubic-bezier(.34,1.56,.64,1),border-color .18s ease,box-shadow .22s ease!important}
.t-list-card:hover{transform:translateY(-2px);box-shadow:0 10px 24px rgba(94,40,44,.12)}
.t-list-card:active{transform:scale(.98);transition:transform .08s ease!important}

/* Tabs: the chosen bottom tab's icon bounces; the section underline draws */
nav[aria-label="Main"] button[aria-current="page"] svg{animation:t-tab-bounce .55s cubic-bezier(.34,1.56,.64,1)}
#sectionSwitch [role=tab][aria-selected="true"]>span{animation:t-rule-draw .4s cubic-bezier(.22,1,.36,1)}

@keyframes t-wiggle{0%,100%{transform:none}25%{transform:rotate(-12deg) scale(1.12)}55%{transform:rotate(9deg) scale(1.08)}80%{transform:rotate(-4deg)}}
@keyframes t-count-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
@keyframes t-head-in{from{opacity:0;transform:translateX(-14px)}to{opacity:1;transform:none}}
@keyframes t-rule-draw{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@keyframes t-chip-on{0%{transform:scale(.9)}55%{transform:scale(1.08)}100%{transform:none}}
@keyframes t-home-in{0%{opacity:0;transform:translateY(22px) scale(.94)}60%{opacity:1;transform:translateY(-3px) scale(1.01)}100%{opacity:1;transform:none}}
@keyframes t-float{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px) rotate(-4deg)}}
@keyframes t-tab-bounce{0%{transform:translateY(0) scale(1)}35%{transform:translateY(-5px) scale(1.14)}65%{transform:translateY(1px) scale(.96)}100%{transform:none}}

/* Home hero: the skyline draws itself, the river drifts, a warm glow breathes.
   Paths use pathLength="1", so a dash of 1 is the whole line whatever its real
   length. The resting state is fully drawn (offset 0); only the animation's
   first frame hides it, so a paused or skipped animation still shows the city. */
.t-draw{stroke-dasharray:1;stroke-dashoffset:0;animation:t-draw 1.6s cubic-bezier(.65,0,.35,1) backwards}
.t-river{animation:t-river 9s linear infinite}
.t-hero-glow{position:absolute;top:-70px;right:-60px;width:220px;height:220px;border-radius:50%;pointer-events:none;
  background:radial-gradient(circle,rgba(232,163,23,.30) 0%,rgba(232,163,23,.10) 45%,transparent 70%);
  animation:t-glow-breathe 7s ease-in-out infinite}
.t-hero{animation:t-home-in .7s cubic-bezier(.34,1.3,.64,1) backwards}
.t-stat{animation:t-home-in .55s cubic-bezier(.34,1.4,.64,1) backwards}
.t-sight-card{animation:t-home-in .55s cubic-bezier(.34,1.4,.64,1) backwards;
  transition:transform .3s cubic-bezier(.34,1.56,.64,1),box-shadow .25s ease,border-color .2s ease}
.t-sight-card:hover{transform:translateY(-4px);box-shadow:0 14px 30px rgba(94,40,44,.14);border-color:var(--bd-2)!important}
.t-sight-card:active{transform:scale(.96);transition:transform .09s ease}
.t-area-pill{animation:t-home-in .45s cubic-bezier(.34,1.4,.64,1) backwards}
.t-area-pill:hover{border-color:rgba(var(--warm-rgb),.5)!important;background:rgba(var(--warm-rgb),.08)!important}

/* Map: tiles tinted toward the app's rose-and-sand palette instead of stock
   OSM, a frosted legend, and a count pill. Only the tile layer is filtered —
   the dots keep their true colours. */
.tall-map .leaflet-tile-pane{filter:saturate(.55) sepia(.18) hue-rotate(-12deg) brightness(1.04) contrast(.96)}
.t-map-frame::after{content:"";position:absolute;inset:0;pointer-events:none;border-radius:inherit;z-index:999;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.5),inset 0 -40px 60px -40px rgba(94,40,44,.18)}
.t-map-legend{display:flex;flex-direction:column;gap:6px;padding:10px 12px;border-radius:12px;min-width:132px;
  background:rgba(255,250,250,.82);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  border:1px solid rgba(255,255,255,.7);box-shadow:0 8px 22px rgba(94,40,44,.14);animation:t-fade .5s ease .3s backwards}
.t-map-count{padding:6px 11px;border-radius:9999px;font-size:11.5px;color:var(--t-1);
  background:rgba(255,250,250,.85);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  border:1px solid rgba(255,255,255,.7);box-shadow:0 4px 14px rgba(94,40,44,.12)}
/* A layer that is on gets a soft ring pulsing round its dot. */
.t-chip[aria-pressed="true"] .t-dot{box-shadow:0 0 0 0 currentColor;animation:t-dot-ping 2.2s ease-out infinite}

/* Reviews */
.t-review-card{animation:t-row .45s cubic-bezier(.22,1,.36,1) backwards}
.t-review-summary{animation:t-home-in .55s cubic-bezier(.34,1.3,.64,1) backwards}
.t-star{transition:transform .2s cubic-bezier(.34,1.56,.64,1),background .15s ease,border-color .15s ease,color .15s ease}
.t-star:hover{transform:translateY(-2px)}
.t-star:active{transform:scale(.9)}
.t-star[aria-checked="true"]{animation:t-chip-on .4s cubic-bezier(.34,1.56,.64,1)}

@keyframes t-draw{from{stroke-dashoffset:1}to{stroke-dashoffset:0}}
@keyframes t-river{from{transform:translateX(0)}to{transform:translateX(-90px)}}
@keyframes t-glow-breathe{0%,100%{transform:scale(1);opacity:.9}50%{transform:scale(1.12) translate(-8px,6px);opacity:1}}
@keyframes t-dot-ping{0%{box-shadow:0 0 0 0 color-mix(in srgb,currentColor 45%,transparent)}70%,100%{box-shadow:0 0 0 7px transparent}}

@media (prefers-reduced-motion:reduce){.t-cat,.t-cat-badge,.t-cat-head,.t-cat-head::after,.t-cat-count,.t-chip,.t-home-card,.t-home-icon,.t-list-card,.t-draw,.t-river,.t-hero-glow,.t-hero,.t-stat,.t-sight-card,.t-area-pill,.t-map-legend,.t-dot,.t-review-card,.t-review-summary,.t-star{animation:none!important}.t-cat::after{display:none}}
@keyframes t-in{from{opacity:0;transform:translateY(10px) scale(.99)}to{opacity:1;transform:none}}
@keyframes t-skel{0%,100%{opacity:.4}50%{opacity:.75}}
@keyframes t-sheet{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:none}}
@keyframes t-fade{from{opacity:0}to{opacity:1}}
@keyframes t-row{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
#shell [data-deck]{perspective:1000px}
#shell [data-tilt]{transform-style:preserve-3d}
@keyframes t-lift{0%{opacity:0;transform:translateY(110%) rotateX(-58deg)}100%{opacity:1;transform:none}}
@keyframes t-deal{0%{opacity:0;transform:translateY(70px) scale(.9) rotate(0deg)}100%{opacity:1}}
@keyframes t-marquee{0%{transform:translateX(0)}100%{transform:translateX(-50%)}}
[data-reveal]{opacity:.2;transform:translateY(38px) scale(.985);filter:saturate(.15) brightness(1.06) opacity(.5);transition:opacity .85s cubic-bezier(.16,1,.3,1),transform .85s cubic-bezier(.16,1,.3,1),filter .9s cubic-bezier(.16,1,.3,1)}
[data-reveal][data-shown]{opacity:1;transform:none;filter:none}
/* Panel rows and their values wait for the section to scroll into view.
   Previously these animated on page load — by the time anyone scrolled down to
   the feature sections the bloom had finished minutes earlier, so the panels
   looked completely static. Holding them at opacity 0 until [data-shown]
   arrives is what makes the animation something you actually see.
   animation-delay stays inline, so the stagger still works per row. */
/* Panel rows and their values animate when their section scrolls into view,
   not on page load — previously they finished long before anyone reached them,
   so the panels looked static.
   
   Deliberately NOT hidden beforehand. An earlier version held them at
   opacity 0 until [data-shown] arrived, which animates beautifully and fails
   terribly: if IntersectionObserver is throttled, unavailable, or the callback
   never fires (a backgrounded tab will do it), every number on the page stays
   invisible forever. A missed animation costs nothing; missing content costs
   the page. So the resting state is visible, and the reveal replays the
   entrance from its own 0% keyframe. */
.reveals-on [data-reveal][data-shown] [data-rowin]{animation:t-row .55s var(--ease) both}
.reveals-on [data-reveal][data-shown] [data-pop]{animation:t-score-pop .7s var(--ease) both}
/* Bars fill when the panel arrives. Resting state is the full width, so a
   suppressed observer leaves a complete bar rather than an empty track — same
   fail-safe reasoning as the values. */
.reveals-on [data-reveal][data-shown] [data-bar]{animation:t-bar .9s cubic-bezier(.16,1,.3,1) both}

/* Each feature panel animates in its OWN colour, taken from --panel set inline
   per block — green for Cafés, amber for Stays, violet for See, indigo for
   Plan. One set of rules, four identities, no duplicated CSS. */

/* The accent rule above the panel draws itself left to right. */
@keyframes t-panel-rule{0%{transform:scaleX(0)}100%{transform:scaleX(1)}}
/* A soft band of the panel's colour sweeps across once, like light moving over
   the card, then leaves. */
@keyframes t-panel-sweep{
  0%{opacity:0;transform:translateX(-60%) skewX(-14deg)}
  22%{opacity:.85}
  70%{opacity:.35}
  100%{opacity:0;transform:translateX(160%) skewX(-14deg)}}
/* The border lifts from neutral to the panel's colour and settles just short
   of full strength, so the card keeps its tint afterwards rather than snapping
   back to grey. */
@keyframes t-panel-glow{
  0%{border-color:var(--bd);box-shadow:var(--el-2)}
  55%{border-color:var(--panel);box-shadow:var(--el-2),0 0 0 4px color-mix(in oklch,var(--panel) 22%,transparent)}
  100%{border-color:color-mix(in oklch,var(--panel) 52%,var(--bd));box-shadow:var(--el-2),0 0 0 0 transparent}}

.t-panel{position:relative;overflow:hidden}
.t-panel .t-panel-rule{transform:scaleX(0);transform-origin:left}
.t-panel .t-panel-sweep{opacity:0}
.reveals-on [data-reveal][data-shown].t-panel{animation:t-panel-glow 1.5s var(--ease) .1s both}
.reveals-on [data-reveal][data-shown] .t-panel-rule{animation:t-panel-rule .85s var(--ease) .15s both}
.reveals-on [data-reveal][data-shown] .t-panel-sweep{animation:t-panel-sweep 1.5s var(--ease) .3s both}
#lpRoot [data-press],#shell [data-press]{transition:transform .16s cubic-bezier(.16,1,.3,1),box-shadow .22s cubic-bezier(.16,1,.3,1),border-color .22s ease}
[data-press]:hover{box-shadow:var(--el-2)}
#lpRoot [data-press]{transition:transform .16s cubic-bezier(.16,1,.3,1),box-shadow .22s cubic-bezier(.16,1,.3,1)}
/* Cards lift a hair on hover — on paper this is the whole feedback vocabulary. */
#lpRoot [data-reveal][data-shown]:hover{transform:translateY(-2px)}
#lpRoot [data-reveal]{transition:opacity .85s cubic-bezier(.16,1,.3,1),transform .5s cubic-bezier(.16,1,.3,1),filter .9s cubic-bezier(.16,1,.3,1)}
#shell button:not([disabled]){transition:background .18s ease,border-color .2s ease,box-shadow .22s cubic-bezier(.16,1,.3,1),transform .16s cubic-bezier(.16,1,.3,1)}
#lpRoot [data-press]:active{transform:scale(.96)}
#lpRoot [data-shimmer]{position:relative;overflow:hidden;isolation:isolate}
#lpRoot [data-shimmer]::after{content:"";position:absolute;top:0;bottom:0;width:40%;background:linear-gradient(100deg,transparent,rgba(255,255,255,.34),transparent);animation:t-shimmer 4.4s cubic-bezier(.16,1,.3,1) infinite;pointer-events:none}
@keyframes t-screen{0%{opacity:0;transform:translateY(12px)}100%{opacity:1;transform:none}}
@keyframes t-card3d{0%{opacity:0;transform:translateY(14px) scale(.99)}100%{opacity:1;transform:none}}
@keyframes t-flipin{0%{opacity:0;transform:translateY(12px) scale(.985)}100%{opacity:1;transform:none}}
@keyframes t-hero3d{0%{opacity:0;transform:translateY(14px) scale(.985)}100%{opacity:1;transform:none}}
@keyframes t-rise{0%{opacity:0;transform:translateY(14px)}100%{opacity:1;transform:none}}
@keyframes t-spring{0%{opacity:0;transform:translateY(16px) scale(.99)}100%{opacity:1;transform:none}}
@keyframes t-fwd{0%{opacity:0;transform:translateX(18px)}100%{opacity:1;transform:none}}
@keyframes t-back{0%{opacity:0;transform:translateX(-18px)}100%{opacity:1;transform:none}}
@keyframes t-up{0%{opacity:0;transform:translateY(20px)}100%{opacity:1;transform:none}}
@keyframes t-marker{0%{opacity:0;transform:translateY(-6px) scale(.9)}100%{opacity:1;transform:none}}
/* Hero wordmark: each letter lifts and settles, so the name arrives rather than
   appearing. Per-letter delay is set inline from the index. */
@keyframes t-letter{0%{opacity:0;transform:translateY(.5em) rotateX(-70deg);filter:blur(4px)}
  60%{opacity:1;filter:blur(0)}
  100%{opacity:1;transform:none;filter:blur(0)}}
/* A slow sheen across the wordmark once it has landed. */
@keyframes t-sheen{0%{background-position:-140% 0}55%,100%{background-position:240% 0}}
/* "Trips" in gold, painted per letter: a gradient clipped through a parent
   over animated letters paints nothing on phones. Five letters, so the
   gradient is five letters wide and each letter shows its own fifth. */
/* Every letter lifts in on its own delay (--d). */
[data-wm-ch]{animation:t-letter .62s var(--ease) both;animation-delay:var(--d)}
/* "Trident": dark, with a gold glint that crosses each letter in turn, so it
   reads as one sweep across the word. Per letter for the same phone reason. */
@keyframes t-wm-shine{0%{background-position:100% 0}22%,100%{background-position:0% 0}}
[data-wm="ink"] [data-wm-ch]{color:transparent;-webkit-text-fill-color:transparent;background:linear-gradient(100deg,var(--t-0) 0%,var(--t-0) 38%,#E8A317 50%,var(--t-0) 62%,var(--t-0) 100%);background-size:300% 100%;background-position:100% 0;-webkit-background-clip:text;background-clip:text;animation:t-letter .62s var(--ease) both,t-wm-shine 6s linear infinite;animation-delay:var(--d),calc(1.8s + var(--i) * 85ms)}
[data-wm="gold"] [data-wm-ch]{color:transparent;-webkit-text-fill-color:transparent;background:linear-gradient(90deg,#C9871B,#E8A317 45%,#F2C14E 75%,#E8A317);background-size:500% 100%;background-position:calc(var(--i) * 25%) 0;-webkit-background-clip:text;background-clip:text}
/* The rotating subject word — out upward, in from below, so the line reads as
   one sentence changing its last word rather than three separate sentences. */
@keyframes t-word-in{0%{opacity:0;transform:translateY(.55em)}100%{opacity:1;transform:none}}
@keyframes t-word-out{0%{opacity:1;transform:none}100%{opacity:0;transform:translateY(-.55em)}}
/* The card's score: rises, overshoots very slightly, and blooms a soft ring of
   its own colour outward as it settles. currentColor, so each section's card
   glows in its own hue without three copies of this rule. */
@keyframes t-score-pop{
  0%{opacity:0;transform:translateY(.28em) scale(.82);text-shadow:0 0 0 transparent}
  55%{opacity:1;transform:translateY(-.04em) scale(1.06);text-shadow:0 0 26px currentColor}
  100%{opacity:1;transform:none;text-shadow:0 0 0 transparent}}
@keyframes t-save{0%{transform:scale(1)}38%{transform:scale(.86)}100%{transform:scale(1)}}
@keyframes t-think{0%{transform:translateX(-100%)}100%{transform:translateX(300%)}}
@keyframes t-clip{0%{clip-path:inset(0 0 100% 0)}100%{clip-path:inset(0 0 0 0)}}
@keyframes t-line{0%{transform:scaleX(0)}100%{transform:scaleX(1)}}
@keyframes t-check{0%{opacity:0;transform:scale(.6)}100%{opacity:1;transform:none}}
@keyframes t-mask{0%{transform:translateY(108%)}100%{transform:none}}
@keyframes t-sweep{0%{opacity:0;transform:scaleX(0)}100%{opacity:1;transform:scaleX(1)}}
@keyframes t-bar{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@keyframes t-pop{0%{opacity:0;transform:translateY(10px) scale(.985)}100%{opacity:1;transform:none}}
#shell [data-press],#lpRoot [data-press]{transition:transform var(--dur-micro) var(--ease-out),box-shadow var(--dur-comp) ease}
#shell [data-press]:active,#lpRoot [data-press]:active{transform:scale(.975)}
#shell button,#shell a{transition:color var(--dur-micro) ease,background var(--dur-comp) ease,border-color var(--dur-comp) ease,transform var(--dur-micro) var(--ease-out)}
#shell button:active{transform:scale(.985)}
[data-mask]{display:block;overflow:hidden;padding-bottom:.09em}
[data-mask]>span{text-wrap:nowrap}
[data-mask]>span{display:block;animation:t-mask .72s var(--ease) both}
[data-reveal]{opacity:.2;transform:translateY(24px) scale(.985);filter:saturate(.15) brightness(1.06) opacity(.5);transition:opacity .7s var(--ease),transform .7s var(--ease),filter .9s var(--ease)}
[data-reveal][data-shown]{opacity:1;transform:none;filter:none}
[data-ink]{transition:color .8s var(--ease),opacity .8s var(--ease)}
[data-ink]:not([data-shown]){color:var(--t-3);opacity:.55}
@keyframes t-glow{0%,100%{box-shadow:0 0 0 rgba(var(--warm-rgb),0)}50%{box-shadow:0 0 22px rgba(var(--warm-rgb),.18)}}
#lpNav{display:none}
@media (min-width:900px){#lpNav{display:flex}}
/* The hero card rotates through four examples of different heights; without a
   floor, everything below it jumped every 3.2s. Floors are the tallest card
   measured at each width (café or see card); the middle block stretches so the
   footer line stays at the bottom. */
#lpHeroCard{display:flex;flex-direction:column;min-height:340px}
#lpHeroCard>div{flex:1;display:flex;flex-direction:column}
#lpHeroCard>div>div:nth-child(2){flex:1}
@media (max-width:599px){#lpHeroCard{min-height:400px}}
@media (max-width:380px){#lpHeroCard{min-height:430px}}
/* Phone header: logo and the two sign-in buttons are what must fit. The live
   count is the first thing to go (the hero chip says the same); below 400px
   the buttons and header padding tighten so 360px Android screens still fit. */
#lpLive + #lpAuth{margin-left:0}
/* 959px, not phone-only: from 760px the section nav appears too, and logo +
   nav + chip + buttons need ~800px, so tablets overflowed whenever the chip's
   label was long ("4660 cafés · live"). */
@media (max-width:1099px){#lpLive{display:none!important} #lpLive + #lpAuth{margin-left:auto}}
@media (max-width:400px){
  [data-lp-header]{gap:10px!important;padding-left:16px!important;padding-right:16px!important}
  #lpAuth button{padding:8px 11px!important;font-size:13px!important}
}
/* !important: the aside carries an inline display:flex, which beat this rule, so
   the panel showed under the form on phones and pushed the page 18px wide. */
@media (max-width:839px){#authAside{display:none!important}}
/* ── intro logo: TRIDENT TRIPS ──────────────────────────────────────────────
   Redesigned 17 Sep 2026 ("premium and smooth", no place named, wordmark reads
   TRIDENT TRIPS). Same safety rule as before: base rules are the FINAL state,
   so the logo shows even if no animation runs; motion is layered on only under
   [data-play=on]. Timings are one timeline — keep the JS removal (3.35s) after
   the exit ends (2.6s + .75s).

   0.00  glow breathes in
   0.10  ring turns into place; strokes draw (stem, prongs, bar)
   0.78  prong tips settle — no overshoot, which read as toy-like
   0.95  TRIDENT: letters rise out of a soft blur, 45ms apart, tracking tightens
   1.45  TRIPS: same, lighter, wider tracking
   1.75  hairline opens from the centre; tagline fades up
   1.90  one sheen passes across the wordmark
   2.60  exit: the whole lockup drifts up, blurs and fades with the ground */
@keyframes t-lg-glow{0%{opacity:0;transform:scale(.7)}100%{opacity:1;transform:none}}
@keyframes t-lg-ring{0%{opacity:0;transform:rotate(-70deg) scale(.86)}100%{opacity:1;transform:none}}
@keyframes t-lg-draw{from{stroke-dashoffset:var(--len)}to{stroke-dashoffset:0}}
@keyframes t-lg-node{0%{opacity:0;transform:scale(.4)}100%{opacity:1;transform:none}}
@keyframes t-lg-char{0%{opacity:0;transform:translateY(38%);filter:blur(9px)}100%{opacity:1;transform:none;filter:blur(0)}}
@keyframes t-lg-track{0%{letter-spacing:var(--track-from)}100%{letter-spacing:var(--track-to)}}
@keyframes t-lg-rule{0%{opacity:0;transform:scaleX(0)}100%{opacity:1;transform:scaleX(1)}}
@keyframes t-lg-tag{0%{opacity:0;transform:translateY(8px)}100%{opacity:1;transform:none}}
@keyframes t-lg-sheen{0%{opacity:0;transform:translateX(-160%) skewX(-18deg)}15%{opacity:1}100%{opacity:0;transform:translateX(260%) skewX(-18deg)}}
@keyframes t-lg-exit{0%{opacity:1;transform:none;filter:blur(0)}100%{opacity:0;transform:translateY(-18px) scale(1.05);filter:blur(8px)}}
@keyframes t-lg-fadeout{0%{opacity:1}100%{opacity:0}}

#tIntro{position:fixed;inset:0;z-index:9999;display:grid;place-items:center;overflow:hidden;
  background:radial-gradient(80% 60% at 50% 38%,#FFF8F6 0%,#F7E6E4 48%,#EDD3D2 100%)}
#tIntro [data-lg=glow]{position:absolute;left:50%;top:40%;width:min(92vw,720px);aspect-ratio:1;
  translate:-50% -50%;border-radius:50%;pointer-events:none;
  background:radial-gradient(circle,rgba(var(--warm-rgb),.20) 0%,rgba(var(--warm-rgb),.07) 38%,transparent 66%)}
#tIntro [data-lg=stack]{position:relative;display:flex;flex-direction:column;align-items:center;gap:clamp(22px,3vw,34px);padding:0 20px}
#tIntro [data-lg=glyph]{width:clamp(108px,15vw,150px);height:clamp(108px,15vw,150px)}
#tIntro [data-lg=glyph] svg{width:100%;height:100%;overflow:visible}
#tIntro [data-lg=ring]{transform-origin:60px 60px}
#tIntro [data-lg=p1]{stroke-dasharray:66px;--len:66px}
#tIntro [data-lg=p2],#tIntro [data-lg=p3]{stroke-dasharray:24px;--len:24px}
#tIntro [data-lg=bar]{stroke-dasharray:48px;--len:48px}
#tIntro [data-lg=n1]{transform-origin:36px 38px}
#tIntro [data-lg=n2]{transform-origin:60px 30px}
#tIntro [data-lg=n3]{transform-origin:84px 38px}
#tIntro [data-lg=type]{display:flex;flex-direction:column;align-items:center}
#tIntro [data-lg=word]{position:relative;display:flex;justify-content:center;overflow:hidden;padding:.08em 0 .06em}
#tIntro [data-lg=word] [data-lg=ch]{display:inline-block}
/* letter-spacing sits on w1/w2 themselves (not the parent word): with it on the
   parent, the words snapped narrower the instant their tracking animation ended.
   The negative right margin cancels the trailing space after the last letter so
   the word stays optically centred. */
#tIntro [data-lg=w1]{--track-from:.44em;--track-to:.28em;letter-spacing:var(--track-to);margin-right:calc(-1 * var(--track-to));font-size:clamp(36px,8.6vw,74px);font-weight:600;line-height:1.02;color:var(--t-0)}
@media (min-width:600px){#tIntro [data-lg=w1]{--track-from:.6em}}
#tIntro [data-lg=w2]{--track-from:1.1em;--track-to:.78em;letter-spacing:var(--track-to);margin-right:calc(-1 * var(--track-to));margin-top:clamp(6px,1vw,10px);font-size:clamp(15px,2.6vw,22px);font-weight:500;line-height:1}
#tIntro [data-lg=w2] [data-lg=ch]{color:transparent;background:linear-gradient(90deg,var(--warm-ink),var(--warm) 55%,var(--warm-200));
  background-size:500% 100%;background-position:calc(var(--i) * 25%) 0;-webkit-background-clip:text;background-clip:text}
#tIntro [data-lg=sheen]{position:absolute;top:0;bottom:0;left:0;width:34%;opacity:0;pointer-events:none;
  background:linear-gradient(100deg,transparent,rgba(255,252,248,.9),transparent)}
#tIntro [data-lg=rule]{display:block;width:clamp(64px,10vw,110px);height:1px;margin-top:clamp(18px,2.4vw,26px);transform-origin:center;
  background:linear-gradient(90deg,transparent,rgba(var(--warm-rgb),.85),transparent)}
#tIntro [data-lg=tag]{margin:clamp(12px,1.6vw,16px) 0 0;white-space:nowrap;font-size:clamp(12px,1.25vw,13.5px);letter-spacing:.14em;color:var(--t-2)}
#tIntro [data-lg=skip]{position:absolute;right:20px;bottom:18px;height:34px;padding:0 15px;
  border-radius:9999px;background:rgba(255,248,246,.6);border:1px solid rgba(94,40,44,.16);color:var(--t-2);
  font:inherit;font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;cursor:pointer;backdrop-filter:blur(8px)}
#tIntro [data-lg=skip]:hover{background:rgba(255,248,246,.9)}

#tIntro[data-play=on]{animation:t-lg-fadeout .75s cubic-bezier(.65,0,.35,1) 2.6s forwards}
#tIntro[data-play=on] [data-lg=glow]{animation:t-lg-glow 1.6s cubic-bezier(.22,1,.36,1) 0s backwards}
#tIntro[data-play=on] [data-lg=stack]{animation:t-lg-exit .75s cubic-bezier(.65,0,.35,1) 2.6s forwards}
#tIntro[data-play=on] [data-lg=ring]{animation:t-lg-ring 1.2s cubic-bezier(.22,1,.36,1) .1s backwards}
#tIntro[data-play=on] [data-lg=p1]{animation:t-lg-draw .8s cubic-bezier(.65,0,.35,1) .14s backwards}
#tIntro[data-play=on] [data-lg=p2]{animation:t-lg-draw .6s cubic-bezier(.65,0,.35,1) .34s backwards}
#tIntro[data-play=on] [data-lg=p3]{animation:t-lg-draw .6s cubic-bezier(.65,0,.35,1) .42s backwards}
#tIntro[data-play=on] [data-lg=bar]{animation:t-lg-draw .5s cubic-bezier(.65,0,.35,1) .58s backwards}
#tIntro[data-play=on] [data-lg=n1]{animation:t-lg-node .6s cubic-bezier(.22,1,.36,1) .78s backwards}
#tIntro[data-play=on] [data-lg=n2]{animation:t-lg-node .6s cubic-bezier(.22,1,.36,1) .84s backwards}
#tIntro[data-play=on] [data-lg=n3]{animation:t-lg-node .6s cubic-bezier(.22,1,.36,1) .9s backwards}
#tIntro[data-play=on] [data-lg=w1]{animation:t-lg-track 1.5s cubic-bezier(.22,1,.36,1) .95s both}
#tIntro[data-play=on] [data-lg=w2]{animation:t-lg-track 1.3s cubic-bezier(.22,1,.36,1) 1.45s both}
#tIntro[data-play=on] [data-lg=w1] [data-lg=ch]{animation:t-lg-char .9s cubic-bezier(.22,1,.36,1) backwards;animation-delay:calc(.95s + var(--i) * 45ms)}
#tIntro[data-play=on] [data-lg=w2] [data-lg=ch]{animation:t-lg-char .8s cubic-bezier(.22,1,.36,1) backwards;animation-delay:calc(1.45s + var(--i) * 45ms)}
#tIntro[data-play=on] [data-lg=sheen]{animation:t-lg-sheen 1.1s cubic-bezier(.45,0,.2,1) 1.9s forwards}
#tIntro[data-play=on] [data-lg=rule]{animation:t-lg-rule .9s cubic-bezier(.22,1,.36,1) 1.75s backwards}
#tIntro[data-play=on] [data-lg=tag]{animation:t-lg-tag .8s cubic-bezier(.22,1,.36,1) 1.85s backwards}
#tIntro[data-play=on] [data-lg=skip]{animation:t-fade .6s var(--ease) .7s backwards}
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
/* Sign-up questions. Two soft colour fields drift behind the card, tinted per
   step; the heading blurs in; a picked tile gives a small spring. */
@keyframes t-q-drift{0%,100%{transform:translate3d(0,0,0) scale(1)}50%{transform:translate3d(5%,-4%,0) scale(1.1)}}
@keyframes t-q-in{from{opacity:0;transform:translateY(16px);filter:blur(8px)}to{opacity:1;transform:none;filter:none}}
@keyframes t-q-pick{0%{transform:scale(1)}35%{transform:scale(1.14) rotate(-5deg)}100%{transform:scale(1)}}
@keyframes t-q-glint{from{transform:translateX(-120%)}to{transform:translateX(120%)}}
#qRoot .q-blob{position:absolute;border-radius:50%;filter:blur(64px);opacity:.6;pointer-events:none;transition:background 1s ease;animation:t-q-drift 16s ease-in-out infinite}
#qRoot .q-opt{position:relative;overflow:hidden}
#qRoot .q-opt[aria-pressed=true] .q-tile{animation:t-q-pick .55s cubic-bezier(.34,1.56,.64,1)}
#qRoot .q-opt[aria-pressed=true]::after{content:"";position:absolute;inset:0;background:linear-gradient(100deg,transparent 30%,rgba(255,255,255,.55) 50%,transparent 70%);animation:t-q-glint .8s cubic-bezier(.16,1,.3,1) both;pointer-events:none}
#qRoot .q-opt:focus-visible{outline:2px solid var(--warm);outline-offset:2px}
#qRoot .q-seg>span{transform-origin:left}

/* ══ Kit additions ══════════════════════════════════════════════════════════
   On the live site these few rules are inline styles written by the React
   template. Here they are real CSS, so the markup stays plain HTML.
   Everything above this line is the stylesheet from tridenttrips.com, byte
   for byte. */

/* The wordmark built by trident-kit.js from data-wordmark="…".
   The size lives on the container, not the words: `gap` is in em, so with a
   16px container the space between two 96px words came out at 4px and the name
   read as one word. */
[data-wordmark]{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 .26em;margin:18px 0 6px;perspective:700px;
  font-size:clamp(38px,7.4vw,96px)}
.t-wm-word{display:inline-flex;font-size:inherit;line-height:1;font-weight:600;letter-spacing:-.045em;color:var(--t-0)}
[data-wm-ch]{display:inline-block;transform-origin:50% 100%}
/* A wordmark used small, in a header. */
[data-wordmark][data-size=sm] .t-wm-word{font-size:15px;font-weight:500;letter-spacing:.2em}

/* Shared page furniture: the same measure, gutters and rhythm every section
   on the live landing page uses. */
.t-wrap{max-width:1180px;margin:0 auto;padding-left:clamp(18px,5vw,64px);padding-right:clamp(18px,5vw,64px)}
.t-page{min-height:100vh;background:
  radial-gradient(80% 52% at 82% -6%,rgba(var(--warm-rgb),.09) 0%,transparent 64%),
  radial-gradient(62% 42% at 4% 104%,rgba(var(--warm-rgb),.1) 0%,transparent 66%),
  linear-gradient(180deg,#FFF6F5 0%,#F7E4E3 46%,#EFD4D4 100%)}
.t-head{position:sticky;top:0;z-index:20;display:flex;align-items:center;gap:16px;padding:16px clamp(18px,5vw,64px);
  background:rgba(255,245,244,.84);backdrop-filter:blur(22px);-webkit-backdrop-filter:blur(22px);
  border-bottom:1px solid rgba(var(--sand-rgb),.14)}
.t-btn{height:50px;padding:0 22px;border-radius:10px;border:0;cursor:pointer;font-family:inherit;font-size:15px;font-weight:500;
  color:#3B1526;background:linear-gradient(180deg,color-mix(in oklch,var(--warm) 90%,white),var(--warm));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.35),0 10px 26px rgba(var(--warm-rgb),.22);
  transition:transform .18s var(--ease)}
.t-btn-quiet{height:50px;padding:0 20px;border-radius:10px;background:transparent;border:1px solid var(--bd);color:var(--t-1);
  font-family:inherit;font-size:15px;cursor:pointer;white-space:nowrap;transition:border-color .2s ease}
.t-btn-quiet:hover{border-color:rgba(var(--sand-rgb),.45)}
.t-btn-sm{height:38px;padding:0 15px;font-size:13.5px;border-radius:8px}
.t-chip-label{display:inline-flex;align-items:center;gap:8px;padding:6px 12px;border-radius:9999px;
  background:rgba(var(--sand-rgb),.1);border:1px solid rgba(var(--sand-rgb),.3);
  font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--sand-200)}
/* EXAMPLE marker. Illustrated numbers on a landing page are fine; unlabelled
   ones are not. Anything invented wears this. */
.t-example{display:inline-flex;align-items:center;gap:6px;padding:3px 8px;border-radius:6px;
  background:rgba(var(--warm-rgb),.12);border:1px solid rgba(var(--warm-rgb),.3);
  font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--warm-ink)}
