  :root{
    /* --- vintage SF bus palette (sampled from a photo of an old Muni bus) --- */
    --bus-white:#cacfd5;     /* cool off-white  */
    --bus-orange:#ba6e3a;    /* burnt orange    */
    --bus-red:#942f25;       /* weathered brick red */

    --bg:#cacfd5; --ink:#2c2620; --muted:#736a5e;
    --worm:#cc3847;          /* the Muni worm — original Landor logo red (from worm_logo.svg) */
    --worm-i:#cf2645;        /* the "i" bar — the original logo's second, slightly more crimson tone */
    --land:#c1beb6;          /* SF silhouette, warm landmass under the off-white */
    --accent:var(--bus-orange);   /* UI accent (play button, scrubber) */
    --grid:rgba(70,52,36,.12);
    --track:rgba(48,34,22,.16);
    --panel:rgba(44,32,20,.05);
    --panel-bd:rgba(44,32,20,.18);
    --thumb:#fff;
    --bgA:#dde0e5; --bgB:#c4c1ba;   /* body vignette stops */
  }
  *{box-sizing:border-box;margin:0;padding:0}
  html,body{height:100%; overflow:hidden}
  body{
    background:#0b0d11;
    color:var(--ink); font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;
    min-height:100vh; display:flex; flex-direction:column; justify-content:center; overflow-x:hidden; position:relative;
  }
  /* the Powell platform — its own layer so it can dim + blur (rack-focus) when you tap in */
  .bg{ position:fixed; inset:0; z-index:0; pointer-events:none;
    background:
      radial-gradient(112% 98% at 50% 37%, rgba(14,16,20,.32) 24%, rgba(14,16,20,.62) 56%, rgba(14,16,20,.93) 100%),
      linear-gradient(rgba(14,16,20,.5), rgba(14,16,20,.62)),
      url("powell.webp") center/cover no-repeat;
    transition:filter 1.4s ease, transform 1.4s ease; }
  body.playing .bg{ filter:blur(8px) brightness(.4) saturate(.85); transform:scale(1.07); }
  body::before{ content:"";position:fixed;inset:0;pointer-events:none;z-index:0;
    background-image:radial-gradient(var(--grid) 1px, transparent 1.4px);
    background-size:34px 34px;
    -webkit-mask-image:radial-gradient(circle at 52% 42%, #000 0%, rgba(0,0,0,.22) 72%, transparent 100%);
            mask-image:radial-gradient(circle at 52% 42%, #000 0%, rgba(0,0,0,.22) 72%, transparent 100%); }
  body::after{ content:"";position:fixed;inset:0;pointer-events:none;z-index:50;opacity:.04;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }

  main{position:relative;z-index:1;display:flex;align-items:center;justify-content:center;
       min-height:100vh;padding:clamp(14px,3.5vh,46px) clamp(10px,3vw,40px)}

  /* map screen wrapper — fills the whole viewport (full-bleed at any aspect ratio); revealed on tap-in.
     The dive-in is a centred zoom from .82 → 1; no JS sizing, so resizing/rotating just works. */
  .case{ position:fixed; inset:0; z-index:1; isolation:isolate;
    opacity:0; pointer-events:none; transform:scale(.82); transform-origin:center;
    transition:opacity .6s ease, transform 1.5s cubic-bezier(.45,.05,.25,1); }
  .case.shown{ opacity:1; pointer-events:auto; transform:scale(1); }

  /* backlit screen — fills the case (= the viewport); the gradient runs edge-to-edge */
  .screen{ position:absolute; inset:0; overflow:hidden;
    background:radial-gradient(125% 115% at 50% 36%, #dadfe5 0%, #c6cbd1 58%, #b6bbc2 100%); }
  .screen.power{ animation:power 1.1s ease both; }
  @keyframes power{ 0%{filter:brightness(.25)} 7%{filter:brightness(1.35)} 11%{filter:brightness(.45)} 19%{filter:brightness(1.2)} 27%{filter:brightness(.7)} 42%{filter:brightness(1.06)} 60%{filter:brightness(.96)} 100%{filter:brightness(1)} }
  svg{width:100%;height:100%;display:block;overflow:visible}
  #landPath{fill:var(--land)}
  #land{ opacity:0; transition:opacity .8s ease; }   /* SF silhouette appears only after the morph completes */
  #land.show{ opacity:1; }
  #caps{ opacity:0; transition:opacity .8s ease; }   /* line end caps appear with the finished map */
  #caps.show{ opacity:1; }
  #worm path{fill:var(--worm)}
  #worm path:nth-child(2){fill:var(--worm-i)}   /* the "i" bar is a hair more crimson in the original logo */
  #lines, #linesTop, #stations{filter:drop-shadow(0 1.5px 1.5px rgba(70,40,22,.32))}
  #stations .hub{fill:var(--bg);stroke:var(--ink)}

  /* line legend — real-transit-map circle markers, overlaid on the map (left) */
  .legend{ position:absolute; left:clamp(8px,1.8%,22px); top:clamp(8px,2.4%,26px); z-index:4;
    display:flex; flex-direction:column; gap:clamp(1px,.3vw,4px); align-items:flex-start; pointer-events:none;
    opacity:0; transition:opacity .8s ease; }   /* hidden until the morph completes, then fades in with the land + end caps */
  .legend.show{ opacity:1; }
  .chip{ --c:#888; display:flex; align-items:center; gap:clamp(6px,.8vw,10px);
    padding:5px 16px 5px 0;                       /* transparent pad -> bigger, more forgiving hit target (rows nearly touch; badge unmoved) */
    opacity:.22; transition:opacity .45s ease; }
  .chip .badge{ width:clamp(20px,2.4vw,30px); aspect-ratio:1; border-radius:50%;
    display:grid; place-items:center; background:var(--c); color:#fff;
    font-family:"Helvetica Neue",Helvetica,Arial,sans-serif; font-weight:800; line-height:1;
    font-size:clamp(11px,1.4vw,16px); }
  .chip .nm{ font-weight:700; font-size:clamp(9.5px,1.1vw,13px); color:var(--ink);
    letter-spacing:.01em; white-space:nowrap; text-shadow:0 1px 2px rgba(255,255,255,.5); }
  .chip.on{ opacity:1 }
  /* the worm chip badge is the SFMTA app icon, cropped to the circle (no letter) */
  .chip-worm .badge{ background:#0C6CB5 url("muni-worm-icon.png") center/cover no-repeat; }
  /* the worm story re-reveals the actual morph-source #worm logo (exact pre-morph position/size).
     transition is scoped to .reveal so the morph's instant worm<->lines hand-off is never cross-faded. */
  #worm.reveal{ transition:opacity .5s ease; }
  .chip.press .badge{ animation:winderpress .26s ease; }   /* same depress flash as the arrow keys, on click / tap / J K L M N T */

  /* ---- wind / unwind: arrow-key indicator (bottom-left), styled to match the route-list badges ---- */
  .winder{ position:absolute; left:clamp(8px,1.8%,22px); bottom:clamp(10px,3vh,28px); z-index:6;
    display:flex; align-items:center; gap:clamp(6px,.8vw,10px);
    opacity:0; transform:translateY(6px); transition:opacity .6s ease, transform .6s ease; pointer-events:none; }
  body.playing.winder-ready .winder{ opacity:1; transform:none; pointer-events:auto; }   /* hidden through the first morph (unobstructed logo reveal); shown once it completes or the user presses an arrow */
  .winder-key{ width:clamp(20px,2.4vw,30px); aspect-ratio:1; border-radius:50%; border:0; padding:0; cursor:pointer;
    display:grid; place-items:center; -webkit-tap-highlight-color:transparent;
    background:#BB6F3C; color:#fff;
    transition:transform .12s cubic-bezier(.3,1.4,.5,1), filter .15s ease; }
  .winder-key svg{ width:58%; height:58%; fill:#fff; stroke:none; }
  .winder-key:hover{ filter:brightness(1.08); }
  /* easter egg: once fully wound (the next press only rings the stop-request), the wind button becomes the
     classic red Muni "STOP" request button */
  .winder-key .stop-label{ display:none; font:400 clamp(6px,.78vw,8.5px)/1 "Helvetica Neue",Helvetica,Arial,sans-serif;
    letter-spacing:.02em; color:#fff; text-shadow:0 1px 1px rgba(0,0,0,.35); }
  .winder-key.stop{ background:var(--bus-red); box-shadow:inset 0 0 0 2px rgba(255,255,255,.22); transition:background .25s ease; }
  .winder-key.stop svg{ display:none; }
  .winder-key.stop .stop-label{ display:block; }
  .winder-key:active, .winder-key.press{ transform:scale(.82); filter:brightness(.92); }
  .winder-key.press{ animation:winderpress .26s ease; }
  @keyframes winderpress{ 0%{transform:scale(1)} 34%{transform:scale(.8); filter:brightness(.88)} 100%{transform:scale(1)} }

  /* ---- top-right controls: help (?) + mute, quiet outline icons ---- */
  .topright{ position:fixed; top:clamp(8px,2.4%,26px); right:clamp(8px,1.8%,22px); z-index:60;
    display:flex; align-items:center; gap:clamp(2px,.6vw,8px); transition:opacity .5s ease; }
  /* clear the chrome through the draw + first morph (like the winder) so nothing competes with the
     reveal; the cluster fades back in with the winder once the map settles */
  body.playing:not(.winder-ready) .topright{ opacity:0; pointer-events:none; }
  .iconbtn{ width:38px; height:38px; padding:8px; border:0; background:none; cursor:pointer;
    color:rgba(247,244,238,.66); -webkit-tap-highlight-color:transparent;
    display:flex; align-items:center; justify-content:center; transition:color .3s ease; }
  .iconbtn:hover, .iconbtn:focus-visible{ color:#fff; outline:none; }
  /* the map / morph screen behind the cluster is light → switch to dark ink so the icons stay legible */
  body.playing .iconbtn{ color:rgba(38,32,24,.5); }
  body.playing .iconbtn:hover, body.playing .iconbtn:focus-visible{ color:rgba(38,32,24,.92); }
  .iconbtn svg{ width:100%; height:100%; display:block;
    fill:none; stroke:currentColor; stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round; }
  .help .qm{ stroke:none; fill:currentColor; text-anchor:middle;
    font:700 12px/1 "Helvetica Neue",Helvetica,Arial,sans-serif; }
  /* "look here" ping on the ? — a radar ring in the accent orange. Only after the morph completes
     (winder-ready, when the caps/legend fade in); retires once the menu's opened or controls are found. */
  .help{ position:relative; }
  .help::after{ content:""; position:absolute; inset:4px; border-radius:50%;
    border:2px solid var(--bus-orange); pointer-events:none; display:none; }
  body.winder-ready .help::after{ display:block; animation:helpPing 2.2s ease-out infinite; }
  @keyframes helpPing{ 0%{ transform:scale(.55); opacity:.85 } 70%{ opacity:0 } 100%{ transform:scale(1.5); opacity:0 } }
  body.winder-ready .help.seen::after{ display:none; }   /* retired on any control key (or a click on ? itself); must out-specify the winder-ready rule above */
  @media (prefers-reduced-motion:reduce){ .help::after{ display:none; } }
  .mute .slash{ display:none; }
  .mute.muted .wave{ display:none; }       /* muted: drop the sound waves, show the slash */
  .mute.muted .slash{ display:inline; }
  .share svg{ stroke-width:2.1; }          /* compensate the larger viewBox so the line weight matches the others */
  .share .ic-check{ display:none; }
  .share.copied .ic-link{ display:none; }  /* on copy: swap the link icon for a check */
  .share.copied .ic-check{ display:inline; }
  .share.copied{ color:#7fae5a; }          /* brief confirming green */
  .help[aria-expanded="true"]{ color:#fff; }
  body.playing .help[aria-expanded="true"]{ color:rgba(38,32,24,.92); }

  /* ---- brief key legend popover (toggled by ?) ---- */
  .keys{ position:fixed; top:calc(clamp(8px,2.4%,26px) + 46px); right:clamp(8px,1.8%,22px); z-index:59;
    width:min(264px,82vw); padding:15px 17px; border-radius:13px;
    background:linear-gradient(157deg,#26201a 0%,#1a1510 52%,#120e0a 100%);   /* match the story panel */
    box-shadow:0 34px 70px -22px rgba(0,0,0,.78), inset 0 1px 0 rgba(255,255,255,.07), 0 0 0 1px rgba(0,0,0,.5);
    color:#f4efe5; opacity:0; visibility:hidden; transform:translateY(-6px);
    transition:opacity .18s ease, transform .18s ease, visibility .18s; }
  .keys.open{ opacity:1; visibility:visible; transform:none; }
  .keys-title{ font:700 10px/1 "Helvetica Neue",Helvetica,Arial,sans-serif; letter-spacing:.26em;
    text-transform:uppercase; color:rgba(243,240,234,.5); margin:0 0 13px; }
  .keys-list{ display:grid; grid-template-columns:auto 1fr; gap:10px 14px; align-items:center; margin:0; }
  .keys-list dt{ display:flex; align-items:center; gap:4px; }
  .keys-list dd{ margin:0; font-size:12.5px; line-height:1.3; color:rgba(243,240,234,.82); }
  .keys .rng{ color:rgba(243,240,234,.45); }
  .keys kbd{ display:inline-flex; align-items:center; justify-content:center; min-width:20px; height:20px; padding:0 5px;
    font:600 11px/1 "Helvetica Neue",Helvetica,Arial,sans-serif; color:#f3f0ea;
    background:rgba(243,240,234,.08); border:1px solid rgba(243,240,234,.22); border-radius:5px; }

  /* ---- intro title: the minimal wordmark + one line of framing, top-centered before tap-in ---- */
  .intro-title{ position:absolute; left:50%; top:clamp(24px,7vh,84px); transform:translateX(-50%);
    z-index:8; display:flex; flex-direction:column; align-items:center; text-align:center;
    pointer-events:none; transition:opacity .55s ease, transform .55s ease; }
  /* soft edgeless scrim: calms the busy photo behind the whole title group so the outline reads */
  .intro-title::before{ content:""; position:absolute; left:50%; top:46%; transform:translate(-50%,-50%);
    width:148%; height:215%; z-index:-1; pointer-events:none;
    background:radial-gradient(58% 56% at 50% 50%, rgba(9,10,13,.74) 0%, rgba(9,10,13,.46) 44%, transparent 76%); }
  .it-logo{ width:clamp(150px,24vw,260px); height:auto; display:block;
    /* tight dark halo hugs the stroke (legibility) + a soft depth shadow */
    filter:drop-shadow(0 0 2px rgba(8,9,12,.85)) drop-shadow(0 2px 10px rgba(0,0,0,.55)); }
  .it-logo path{ fill:none; stroke-width:4; stroke-linejoin:round; stroke-linecap:round; }
  .it-logo-worm path{ stroke:var(--worm); }    /* the worm body — original Landor red */
  .it-logo-i{ stroke:var(--worm-i); }          /* the "i" bar — the logo's slightly more crimson tone */
  .it-line{ margin-top:clamp(10px,1.6vh,18px); font-size:clamp(12px,1.5vw,15px); letter-spacing:.34em;
    text-transform:uppercase; font-weight:700; color:#f3f0ea; text-shadow:0 1px 8px rgba(0,0,0,.85); }
  .it-sub{ margin-top:clamp(6px,1vh,11px); font-size:clamp(11px,1.2vw,13px); letter-spacing:.03em;
    color:rgba(243,240,234,.6); text-shadow:0 1px 6px rgba(0,0,0,.8); max-width:34ch; }
  /* ---- byline: quiet bottom-left credit, intro only ---- */
  .credit{ position:fixed; left:clamp(8px,1.8%,22px); bottom:clamp(10px,3vh,28px); z-index:9;
    font-size:clamp(9.5px,1vw,11px); letter-spacing:.18em; text-transform:uppercase; font-weight:700;
    color:rgba(243,240,234,.4); text-shadow:0 1px 6px rgba(0,0,0,.85); transition:opacity .5s ease; }
  .credit a{ color:rgba(243,240,234,.66); text-decoration:none;
    border-bottom:1px solid rgba(243,240,234,.22); padding-bottom:1px;
    transition:color .2s ease, border-color .2s ease; }
  .credit a:hover{ color:#fff; border-color:rgba(243,240,234,.6); }
  body.playing .credit{ opacity:0; pointer-events:none; }   /* fades with the intro on tap-in */

  /* ---- intro: reader (left) + Clipper card (right), tightened toward center for less drag travel ---- */
  .reader{ position:absolute; top:56%; left:38%; transform:translate(-50%,-50%); z-index:6;   /* centered in the frame between the title and the hint, not on raw page-center */
    width:min(33vmin,330px); height:min(33vmin,330px); border-radius:50%;
    background:url("clipper-reader.webp") center/cover no-repeat;
    box-shadow:0 10px 30px rgba(0,0,0,.5), inset 0 0 0 2px rgba(0,0,0,.18);
    transition:opacity .55s ease, box-shadow .15s ease; }
  .reader.armed{ box-shadow:0 0 0 6px rgba(167,194,67,.7), 0 10px 30px rgba(0,0,0,.5); }
  .reader.tap{ box-shadow:0 0 0 10px rgba(167,194,67,.9), 0 0 54px 16px rgba(167,194,67,.55); }
  .ccard{ position:absolute; top:56%; left:62%; transform:translate(-50%,-50%); z-index:12;  /* above the intro title (8), hint (8) and exit (9) text */
    aspect-ratio:200/310; height:min(36vmin,293px); border-radius:11px; cursor:grab; touch-action:none; will-change:transform;
    background:#11568f url("clipper-card.png") center/cover no-repeat;
    box-shadow:0 18px 40px rgba(0,0,0,.45);
    transition:opacity .55s ease, transform .35s cubic-bezier(.3,1.3,.5,1);
    animation:cardInvite 2.4s ease-in-out infinite; }   /* breathing glow → "pick me up"; 2.4s matches .hint's hintpulse so they swell in sync */
  /* a soft halo swells and fades around the resting card; pairs with the pulsing hint text */
  @keyframes cardInvite{
    0%,100%{ box-shadow:0 18px 40px rgba(0,0,0,.45), 0 0 0 0 rgba(190,212,255,0); }
    50%{ box-shadow:0 20px 44px rgba(0,0,0,.5), 0 0 26px 4px rgba(190,212,255,.5); } }
  .ccard.dragging{ cursor:grabbing; transition:opacity .55s ease; z-index:30; box-shadow:0 34px 64px rgba(0,0,0,.55); animation:none; }   /* glow off once grabbed */
  .ccard.placed{ animation:none; }                              /* glow off once it lands on the reader */
  @media (prefers-reduced-motion:reduce){ .ccard{ animation:none; } }
  .hint{ position:absolute; left:50%; bottom:clamp(28px,9vh,90px); transform:translateX(-50%); z-index:8;
    font-size:clamp(12px,1.5vw,15px); letter-spacing:.18em; text-transform:uppercase; font-weight:700; color:#f3f0ea;
    text-shadow:0 1px 6px rgba(0,0,0,.85); text-align:center; max-width:min(88vw,36ch); line-height:1.5;
    transition:opacity .4s ease; animation:hintpulse 2.4s ease-in-out infinite; }
  .hint.gone{ opacity:0; pointer-events:none; animation:none; }
  @keyframes hintpulse{ 0%,100%{opacity:.5} 50%{opacity:1} }
  /* the quiet "way back" — fades in after the morph, then fades out */
  .exit{ position:fixed; left:50%; bottom:clamp(22px,5vh,46px); transform:translateX(-50%); z-index:9; pointer-events:none;
    font-size:11px; letter-spacing:.22em; text-transform:uppercase; font-weight:700; color:rgba(255,255,255,.7);
    text-shadow:0 1px 6px rgba(0,0,0,.9); opacity:0; transition:opacity .6s ease; }
  .exit.show{ opacity:1; }
  /* once tapped in, the intro pieces fade away */
  body.playing .reader, body.playing .ccard, body.playing .hint{ opacity:0; pointer-events:none; }
  body.playing .intro-title{ opacity:0; transform:translateX(-50%) translateY(-14px); }

  /* stop-request cord — appears after the morph */
  .stopctl{ position:absolute; left:50%; bottom:clamp(18px,5vh,46px); transform:translateX(-50%); z-index:6;
    opacity:0; pointer-events:none; transition:opacity .5s ease; }
  .stopctl.shown{ opacity:1; pointer-events:auto; }
  .cord{ display:flex;flex-direction:column;align-items:center;gap:6px;cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent }
  .cordpull{ display:flex;flex-direction:column;align-items:center }
  .cordline{ width:4px;height:46px;border-radius:2px;background:linear-gradient(#866039,#5b4027);box-shadow:0 1px 2px rgba(0,0,0,.4) }
  .cordknob{ width:26px;height:26px;border-radius:50%;margin-top:-3px;background:radial-gradient(circle at 35% 30%,#cf9156,#8a5a30);
    box-shadow:0 3px 5px rgba(0,0,0,.45), inset 0 1px 0 rgba(255,255,255,.3) }
  .cord:hover .cordknob{ filter:brightness(1.07) }
  .cord.pulled .cordpull{ animation:pull .55s cubic-bezier(.3,1.5,.5,1) }
  @keyframes pull{ 0%{transform:translateY(0)} 38%{transform:translateY(16px)} 100%{transform:translateY(0)} }
  .cordlamp{ font-size:10px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:#fff;
    background:#9a4036;padding:4px 9px;border-radius:4px;opacity:.85;transition:.18s;text-shadow:0 1px 2px rgba(0,0,0,.5);box-shadow:0 1px 3px rgba(0,0,0,.4), inset 0 0 0 1px rgba(0,0,0,.2) }
  .cord.pulled .cordlamp{ opacity:1;background:#e23a2e;box-shadow:0 0 16px 0 #e23a2e }

  /* ============ line explorer: focus a single line, dim the rest, show its story ============ */
  /* lines/legend only respond on the finished map */
  #lines path, #linesTop path{ transition:opacity .32s ease, filter .32s ease; pointer-events:none; }   /* visible lines are display-only; hit-testing lives on #hit. #linesTop holds the lifted (focused) line */
  /* transparent hit layer, pinned on top: wide stroke = forgiving target; never reordered, so hover is stable over overlaps */
  #hit path.lnhit{ fill:transparent; stroke:transparent; stroke-width:17px; stroke-linejoin:round; pointer-events:none; }
  body.map-ready #hit path.lnhit{ pointer-events:all; cursor:pointer; }    /* hit the ribbon fill OR the padded band */
  #lines path.dim, #linesTop path.dim{ opacity:.1; }                                   /* the other routes recede */
  #lines path.hot, #linesTop path.hot{ filter:brightness(1.04) drop-shadow(0 0 5px rgba(0,0,0,.28)); }
  #land.show.dim{ opacity:.2; transition:opacity .3s ease; } #caps.show.dim{ opacity:.22; transition:opacity .3s ease; }   /* darken landform + end caps so the chosen line pops (snappy dim-in; gentle fade back) */
  body.map-ready .legend{ pointer-events:auto; }   /* contiguous hit region: pointerleave fires only when leaving the whole list, and gaps between chips don't drop the focus */
  body.map-ready .chip{ pointer-events:auto; cursor:pointer; }
  .legend .chip{ transition:opacity .3s ease; }
  .chip.mut{ opacity:.16 !important; }                             /* dim non-selected legend chips (overrides .on) */
  .chip.cur{ opacity:1 !important; }

  /* the story placard — a fragment of the map itself: a route spine with two terminus markers
     brackets a dark Muni-platform plate, colored to the line. Fixed (not scaled with the map). */
  .lineinfo{ --c:#888; position:fixed; right:clamp(8px,1.8%,22px); bottom:clamp(10px,3vh,28px); z-index:40;
    width:min(404px,85vw); min-height:272px; padding:22px 26px 22px 20px; border-radius:13px;
    display:flex; gap:19px; align-items:stretch;
    background:linear-gradient(157deg,#26201a 0%,#1a1510 52%,#120e0a 100%); color:#f4efe5;
    box-shadow:0 34px 70px -22px rgba(0,0,0,.78), inset 0 1px 0 rgba(255,255,255,.07), 0 0 0 1px rgba(0,0,0,.5);
    font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;
    opacity:0; transform:translateY(16px) scale(.985); transform-origin:bottom right; pointer-events:none;
    transition:opacity .42s ease, transform .42s cubic-bezier(.2,.85,.25,1); }
  /* stays pointer-events:none even when shown — it's a passive info panel, and the T line runs behind it;
     if the card captured the pointer it would steal hover from the line and flicker on/off. */
  .lineinfo.show{ opacity:1; transform:none; }

  /* the route spine: terminus · rail · terminus, drawn in the line color (echoes the map's end-caps) */
  .li-spine{ position:relative; z-index:1; flex:0 0 16px; display:flex; flex-direction:column; align-items:center; padding:5px 0 3px; }
  .li-term{ flex:0 0 auto; width:15px; height:15px; border-radius:50%; background:transparent;
    border:3px solid var(--c); box-sizing:border-box; }   /* open ring in the route color, empty center (like the map end-caps) */
  .li-rail{ width:4px; flex:1 1 auto; margin:-2px 0; border-radius:3px; background:var(--c);
    transform:scaleY(0); transform-origin:top center; }
  .lineinfo.show .li-rail{ animation:railDraw .5s cubic-bezier(.4,0,.2,1) .12s both; }
  .lineinfo.show .li-term-b{ animation:termPop .32s cubic-bezier(.3,1.5,.5,1) .52s both; }
  @keyframes railDraw{ from{transform:scaleY(0)} to{transform:scaleY(1)} }
  @keyframes termPop{ 0%{transform:scale(0)} 100%{transform:scale(1)} }

  .li-body{ flex:1 1 auto; min-width:0; position:relative; z-index:1; display:flex; flex-direction:column; }
  .li-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:14px; }
  .li-title{ display:flex; flex-direction:column; gap:7px; min-width:0; }
  .li-name{ font-weight:800; font-size:27px; letter-spacing:-.02em; line-height:.95; }
  .li-sub{ font-size:9px; letter-spacing:.26em; text-transform:uppercase; font-weight:700; color:var(--c); }
  .li-badge{ flex:0 0 auto; width:46px; height:46px; border-radius:50%; background:var(--c); color:#fff;
    display:grid; place-items:center; font-weight:800; font-size:24px; line-height:1; }
  .lineinfo.worm .li-badge{ background:#0C6CB5 url("muni-worm-icon.png") center/cover no-repeat; }
  .li-text{ margin-top:16px; font-size:13.5px; line-height:1.62; color:#d8d1c5; }
  /* termini row — the line runs from ◀ to ▶ */
  .li-termini{ margin-top:auto; padding-top:15px; display:flex; align-items:center; gap:9px;
    font-size:11px; letter-spacing:.04em; font-weight:700; color:#efe9dd; }
  .li-end{ white-space:nowrap; }
  .li-arrow{ flex:0 0 auto; color:var(--c); font-weight:800; font-size:14px; transform:translateY(-1px); }

  /* ============ overhead LED "STOP REQUEST" marquee ============
     Lights up when you wind right at the end of the line — the in-vehicle "stop requested" sign.
     Two aligned amber dot grids: a dim one across the whole housing (unlit LEDs) and a bright one
     clipped to the letters (lit LEDs). Panel padding is a multiple of the 5px dot cell so the two
     grids stay in phase, reading as one continuous matrix with some dots lit. */
  .stopsign{ position:fixed; top:clamp(12px,3.4vh,32px); left:50%; z-index:45; pointer-events:none;
    padding:15px 30px;                                   /* multiples of the 5px cell → the two grids align */
    border-radius:13px;                                  /* match the story panel / keys popover */
    /* unlit-LED dot grid over the same warm-dark card surface the other panels use */
    background-image:radial-gradient(circle, rgba(255,168,46,.13) 1.2px, transparent 1.7px),
                     linear-gradient(157deg,#26201a 0%,#1a1510 52%,#120e0a 100%);
    background-size:5px 5px, auto;
    box-shadow:0 34px 70px -22px rgba(0,0,0,.78), inset 0 1px 0 rgba(255,255,255,.07), 0 0 0 1px rgba(0,0,0,.5);   /* shared card shadow */
    opacity:0; transform:translateX(-50%) translateY(-14px);
    transition:opacity .35s ease, transform .5s cubic-bezier(.2,.9,.3,1); }
  .stopsign.show{ opacity:1; transform:translateX(-50%) translateY(0);
    box-shadow:0 34px 70px -22px rgba(0,0,0,.78), inset 0 1px 0 rgba(255,255,255,.07), 0 0 0 1px rgba(0,0,0,.5), 0 0 36px rgba(255,150,30,.28); }   /* + amber bloom when lit */
  .stoptext{ display:block; white-space:nowrap;
    font:900 clamp(26px,4.4vw,44px)/1 "Arial Black","Helvetica Neue",Helvetica,Arial,sans-serif;
    letter-spacing:.08em; text-transform:uppercase;
    background-image:radial-gradient(circle, #ffb12c 1.2px, transparent 1.7px);   /* lit LEDs, same phase as the housing grid */
    background-size:5px 5px;
    -webkit-background-clip:text; background-clip:text;
    -webkit-text-fill-color:transparent; color:transparent;
    filter:drop-shadow(0 0 2px rgba(255,150,20,.95)) drop-shadow(0 0 7px rgba(255,120,0,.5)); }
  .stopsign.show .stoptext{ animation:ledwarm .42s ease-out both; }   /* LED warm-up flicker on switch-on */
  @keyframes ledwarm{
    0%{filter:brightness(.15) drop-shadow(0 0 1px rgba(255,150,20,.4))}
    9%{filter:brightness(1.7)} 15%{filter:brightness(.4)} 25%{filter:brightness(1.5)}
    34%{filter:brightness(.75)} 46%{filter:brightness(1.2)}
    100%{filter:brightness(1) drop-shadow(0 0 2px rgba(255,150,20,.95)) drop-shadow(0 0 7px rgba(255,120,0,.5))} }
  @media (prefers-reduced-motion:reduce){ .stopsign.show .stoptext{ animation:none; } }

