/* ════════════════════════════════════════════════════════════════════
   Scenes layer — section-specific styles. Everything here consumes the
   --pg-* tokens from core.css; CSS defaults are the resolved pose so
   every scene reads complete without JS.
   ════════════════════════════════════════════════════════════════════ */

/* ── product showcase: tab chips over one card, mock left / copy right.
   All four panels share one grid cell, so the card always stands at
   tallest-panel height — switching tabs cannot shift layout (no CLS).
   Inactive panels are visibility:hidden (out of the a11y tree and the
   tab order) rather than display:none, which would collapse the stack.
   JS drives .is-active + roving tabindex; with JS off the tab row hides
   and all four panels stack — the page stays complete. ── */
/* negative top margin lifts the card over the hero's bottom edge — a teaser
   glimpse above the fold. Desktop peek stays ≤28px so the lip never crosses
   the minimap (bottom:28px, overlaps the card's footprint at 1280-1366px). */
.showcase{width:min(940px,calc(100% - 48px));margin:-26px auto 0;scroll-margin-top:96px}
/* grid/flex children default to min-width:auto, so a wide readout can push a
   column past the viewport — pin them all to 0 and let the content wrap */
.net__cloud>div,.net__cards>*,.net__client>*,.net__rollout,.net__clients{min-width:0}
.net__legend,.net__rhead,.net__chead{flex-wrap:wrap}
.net__legend b,.net__far{margin-left:auto}
.net__cname,.net__mbps{overflow-wrap:anywhere}

@media (max-width:980px){
  .showcase{margin-top:-42px}
}
.showcase__card{border:1px solid var(--pg-hairline);border-radius:20px;overflow:hidden;background:var(--pg-bg-2)}
.showcase__tabs{display:flex;gap:8px;padding:12px 14px;border-bottom:1px solid var(--pg-hairline);
  overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none}
.showcase__tabs::-webkit-scrollbar{display:none}
.showcase__tab{flex:none;font:600 13.5px/1 var(--pg-font);color:var(--pg-mute);background:none;
  border:1px solid var(--pg-hairline);border-radius:999px;padding:10px 18px;cursor:pointer;
  white-space:nowrap;transition:color .2s,background-color .2s,border-color .2s}
.showcase__tab:hover{color:var(--pg-ink)}
.showcase__tab[aria-selected="true"]{color:var(--pg-emerald-hi);background:rgba(21,184,127,.13);border-color:rgba(21,184,127,.5)}
html[data-theme="light"] .showcase__tab[aria-selected="true"]{color:var(--pg-emerald)}
.showcase__panels{display:grid}
.showcase__panel{grid-area:1/1;display:grid;grid-template-columns:minmax(240px,44%) 1fr;
  visibility:hidden;opacity:0;transition:opacity .28s var(--pg-ease)}
.showcase__panel.is-active{visibility:visible;opacity:1}
.showcase__media{position:relative;min-height:210px;background:var(--pg-bg);
  display:flex;align-items:center;justify-content:center;padding:18px}
.showcase__copy{padding:24px 28px;display:flex;flex-direction:column;justify-content:center;align-items:flex-start}
.showcase__copy h3{margin:0 0 8px;font-size:17px;font-weight:800;letter-spacing:-.01em;color:var(--pg-ink)}
.showcase__copy p{margin:0 0 6px;font-size:13.5px;line-height:1.6;color:var(--pg-ink-soft)}
.showcase__copy .sec__cta{margin-top:8px}
.no-js .showcase__tabs{display:none}
.no-js .showcase__panel{visibility:visible;opacity:1;grid-area:auto}
@media (max-width:700px){
  .showcase__panel{grid-template-columns:1fr}
  .showcase__media{min-height:0;padding:16px}
  .showcase__copy{padding:18px 20px 20px}
}
@media (prefers-reduced-motion:reduce){
  .showcase__panel,.showcase__tab{transition:none}
}
/* ?static rides body.no-anim (hero.js stamps it), not the OS media query */
.no-anim .showcase__panel,.no-anim .showcase__tab{transition:none}

/* ── shmock: compact CSS recreations of the product UI, used where no
   brand-safe capture exists (see section comment in index.html). All
   tokens, no images — they theme with the page and can never ship a
   stray zero or an unapproved partner name. ── */
.shmock{width:100%;max-width:360px;font-family:var(--pg-font)}
.shmock__pill{display:inline-flex;align-items:center;gap:6px;font-size:9px;font-weight:800;letter-spacing:.14em;
  color:var(--pg-emerald-hi);background:rgba(21,184,127,.12);border:1px solid rgba(21,184,127,.35);
  border-radius:999px;padding:4px 9px;align-self:flex-start}
.shmock__pill i{width:5px;height:5px;border-radius:50%;background:currentColor}
.shmock__pill--amber{color:#f0b06a;background:rgba(240,176,106,.12);border-color:rgba(240,176,106,.4)}
html[data-theme="light"] .shmock__pill{color:var(--pg-emerald)}
html[data-theme="light"] .shmock__pill--amber{color:#a86419}
/* portal phone */
.shmock--portal{display:flex;justify-content:center}
.shmock__phone{width:min(210px,100%);background:var(--pg-surface);border:1px solid var(--pg-hairline);
  border-radius:22px;padding:16px 14px 14px;display:flex;flex-direction:column;gap:8px;box-shadow:var(--pg-shadow)}
.shmock__brand{display:flex;align-items:center;gap:7px;font-size:10px;font-weight:800;letter-spacing:.06em;
  color:var(--pg-mute);text-transform:uppercase}
.shmock__brand i{width:8px;height:8px;border-radius:3px;background:var(--pg-emerald);flex:none}
.shmock__phone strong{font-size:13px;line-height:1.35;letter-spacing:-.01em;color:var(--pg-ink)}
.shmock__field{font-size:11px;color:var(--pg-faint);border:1px solid var(--pg-hairline);border-radius:10px;
  padding:8px 10px;background:var(--pg-bg-2)}
.shmock__btn{font-size:11px;font-weight:700;text-align:center;color:#06281c;background:var(--pg-emerald);
  border-radius:10px;padding:8px 10px}
.shmock__btn--alt{color:var(--pg-ink);background:none;border:1px solid var(--pg-hairline)}
.shmock__phone small{font-size:9.5px;color:var(--pg-faint);text-align:center}
/* analytics strip */
.shmock--analytics .shmock__strip{background:var(--pg-surface);border:1px solid var(--pg-hairline);
  border-radius:14px;padding:14px;display:flex;flex-direction:column;gap:12px;box-shadow:var(--pg-shadow)}
.shmock__kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
.shmock__kpis span{display:flex;flex-direction:column;gap:3px;min-width:0}
.shmock__kpis small{font-size:8px;font-weight:800;letter-spacing:.1em;color:var(--pg-faint);white-space:nowrap}
.shmock__kpis b{font-size:17px;font-weight:800;letter-spacing:-.02em;color:var(--pg-ink);font-variant-numeric:tabular-nums}
.shmock__spark{width:100%;height:34px;display:block}
.shmock__spark path{stroke:var(--pg-emerald);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
/* marketing campaign card */
.shmock--marketing .shmock__campaign{background:var(--pg-surface);border:1px solid var(--pg-hairline);
  border-radius:14px;padding:14px;display:flex;flex-direction:column;gap:7px;box-shadow:var(--pg-shadow)}
.shmock__campaign strong{font-size:14.5px;letter-spacing:-.01em;color:var(--pg-ink)}
.shmock__campaign > small{font-size:10.5px;color:var(--pg-mute)}
.shmock__stats{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:5px;padding-top:10px;
  border-top:1px solid var(--pg-hairline-soft)}
.shmock__stats span{display:flex;flex-direction:column;gap:2px}
.shmock__stats b{font-size:15px;font-weight:800;color:var(--pg-ink);font-variant-numeric:tabular-nums}
.shmock__stats small{font-size:8px;font-weight:800;letter-spacing:.1em;color:var(--pg-faint)}
/* ad studio — header stays dark in both themes (same rule as .calc2's
   receipt panel: an intentionally-dark mini-panel keeps literals) */
.shmock--ads{background:var(--pg-surface);border:1px solid var(--pg-hairline);border-radius:14px;
  overflow:hidden;box-shadow:var(--pg-shadow)}
.shmock__adshead{display:flex;align-items:center;justify-content:space-between;gap:10px;background:#0a0e14;padding:12px 14px}
.shmock__adshead > span:first-child{font-family:var(--pg-display);font-size:15px;color:#eef2f6}
.shmock__adshead em{font-style:italic;color:#9aa3ad}
.shmock__adstats{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--pg-hairline-soft);
  border-bottom:1px solid var(--pg-hairline-soft)}
.shmock__adstats span{display:flex;flex-direction:column;gap:2px;background:var(--pg-surface);padding:9px 12px}
.shmock__adstats small{font-size:8px;font-weight:800;letter-spacing:.12em;color:var(--pg-faint)}
.shmock__adstats b{font-size:16px;font-weight:800;color:var(--pg-ink);font-variant-numeric:tabular-nums}
.shmock__engines{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;padding:10px 12px 12px}
.shmock__engine{display:flex;flex-direction:column;gap:2px;border:1px solid var(--pg-hairline);border-radius:10px;
  padding:8px 46px 8px 10px;position:relative;min-width:0}
.shmock__engine b{font-size:11.5px;color:var(--pg-ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.shmock__engine small{font-size:9.5px;color:var(--pg-mute);white-space:nowrap}
.shmock__engine i{position:absolute;top:9px;right:9px;font-style:normal;font-size:8px;font-weight:800;
  letter-spacing:.1em;color:var(--pg-emerald-hi)}
html[data-theme="light"] .shmock__engine i{color:var(--pg-emerald)}
.shmock--ads-lg{max-width:none}
.shmock--ads-lg .shmock__engines{grid-template-columns:repeat(3,1fr)}
@media (max-width:480px){
  .shmock--ads-lg .shmock__engines{grid-template-columns:1fr 1fr}
  .shmock--ads-lg .shmock__engine:nth-child(3){display:none}
}

/* ── phone hero: bring the wow above the fold. hero.css is frozen (the
   PERF-FIREFOX mirror contract), so these same-specificity overrides win
   by load order instead. The art anchor is hero.js's --fy = height*.70 —
   min-height is the only knob that moves the cluster: ~1000px seats the
   router + guests card + venue caption inside a 390×844 first viewport,
   and on short phones the art tops into the fold instead of vanishing
   below a dead band. (Was 920px — measured on a 412×915 phone, that parked
   the plan sheet's top 36px ABOVE the trust line's bottom, dimension labels
   bleeding between the text lines. 1000px clears it by ~20px; the caption
   still lands at ~812px on a 390×844 viewport, inside the fold.) ── */
@media (max-width:980px){
  /* at the 36–52px phone/tablet sizes the desktop marker stops strike the
     glyphs (olive band mid-letter on night); ride the baseline like an
     underline-marker instead */
  .dhero__title strong{background-image:linear-gradient(transparent 78%, rgba(255,216,77,.6) 78%, rgba(255,216,77,.6) 96%, transparent 96%)}
}
@media (max-width:480px){
  .dhero{min-height:max(100svh,1000px)}
  .dhero__sub{font-size:15px;line-height:1.55;margin-top:16px}
  .dhero__actions{margin-top:22px}
  .dhero__ghost{padding:8px 0 4px;margin-top:2px}
  .dhero__trust{margin-top:20px}
  .frouter{width:180px;height:180px;left:-90px;top:-100px}
  /* narrower plan + edge fade so the room labels that overhang the frame
     read as cinematic bleed, not sliced words */
  .venue__plan{width:min(118vw,470px);
    -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
    mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent)}
  .acard--guests{left:28px;top:34px}
  .focus__caption{top:112px}
  .showcase{margin-top:-56px}
}
@media (max-width:400px){
  /* the guests card measures ~156px from anchor+left; at 360 viewports the
     980-tier left:36 pushes its corner off screen */
  .acard--guests{left:10px}
}

/* ── trust strip (client-logo marquee) ── */
.trust{max-width:1180px;margin:0 auto;padding:64px 24px 8px;text-align:center}
.trust__caption{margin:0 0 26px;font-size:12.5px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--pg-faint)}
.trust__viewport{
  overflow:hidden;
  -webkit-mask-image:linear-gradient(to right,transparent,#000 12%,#000 88%,transparent);
  mask-image:linear-gradient(to right,transparent,#000 12%,#000 88%,transparent);
}
.trust__track{display:flex;width:max-content;animation:trust-scroll 36s linear infinite}
.trust__viewport:hover .trust__track{animation-play-state:paused}
.trust__row{display:flex;align-items:center;gap:84px;padding-right:84px;list-style:none;margin:0}
/* real client logos, unified to one muted tone; grayscale+invert lifts dark
   marks on the dark canvas */
.trust__logo{display:block;height:30px;width:auto;max-width:150px;object-fit:contain;
  opacity:.72;filter:grayscale(1) invert(1) brightness(1.75)}
.trust__logo--tall{height:46px}
@keyframes trust-scroll{to{transform:translateX(-50%)}}
.is-ff .trust__track{animation:none;width:auto;justify-content:center}
.is-ff .trust__row[aria-hidden]{display:none}

/* ── solution rail (scroll-snap, no library) ── */
.rail-wrap{position:relative}
/* Scoped to .rail-wrap, and it has to stay that way: the book-a-demo modal
   renders its own <aside class="rail"> on every page that loads this file, so
   a bare .rail here reaches inside the overlay. #bd-scrim .rail wins the
   properties both rules declare, but gap/margin/scroll-snap are declared only
   here — which leaked 18px between every rail block and pulled the whole
   column 24px left, on / and /home-v2 but not on the sub pages. */
.rail-wrap .rail{
  display:flex;gap:18px;overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory;padding:4px 24px 18px;margin:0 -24px;
  scrollbar-width:none;
}
.rail-wrap .rail::-webkit-scrollbar{display:none}
.rail__card{
  flex:0 0 min(36.75rem,84vw);scroll-snap-align:start;min-height:21rem;
  position:relative;overflow:hidden;display:flex;flex-direction:column;gap:12px;
  background:var(--pg-surface);border:1px solid var(--pg-hairline);
  border-radius:24px;padding:34px 34px 30px;
}
.rail__card h3{margin:0;font-size:clamp(22px,2.2vw,28px);font-weight:600;letter-spacing:-.02em;color:var(--pg-ink)}
.rail__card p{margin:0;font-size:15.5px;line-height:1.6;color:var(--pg-mute);max-width:46ch}
.rail__card .vig{margin-top:auto;padding-top:18px}
.rail__card--invert{background:#0a0e14;border-color:rgba(238,242,246,.1)}
.rail__card--image{justify-content:flex-end}
.rail__card--image h3,.rail__card--image p{position:relative}
.rail__wash{
  position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(80% 90% at 85% 0%, rgba(21,184,127,.26), rgba(21,184,127,0) 60%),
    linear-gradient(160deg, rgba(21,184,127,.14), rgba(21,184,127,0) 55%);
}
.rail__nav{display:flex;gap:10px;justify-content:flex-end;margin-top:8px}


  /* resolved: BOTH live (✓ LIVE · DAY 14 / ✓ LIVE · DAY 0 — the day count is
     the receipt, aliveness is shared); JS resets both to ink for the run */


   /* resolved: the chamber we lit */


             /* resolved: paid and dim; JS raises to .55 to wait */
   /* JS-only flash */


   /* resolved: collected; JS re-poses ghost */
   /* resolved: stamped; JS hides */


  /* transient, JS-only. CSS `translate` centers; gsap x/y writes `transform`, which composes */

  /* chamber sits left-of-centre on OUR board so the go-live cascade gets the
     open field on the router's right. This wrapper is the handoff landing
     slot: it is never transformed (JS scales only the img inside), so its
     rect stays true for initHandoff's measurements. */


                                  /* resolved: bloomed; JS dims to 0, run re-blooms */
   

  

  

  


  


/* ── dashboard showcase: a screen lighting up a dark room. The .canvas__room
   vignette is the dark; JS raises it to .65 and scrubs it away as the lid
   opens. CSS default = the resolved pose (undimmed, opacity 0). The emerald
   glow behind the laptop is static box-shadow, never animated. ── */
.pg-canvas{position:relative;max-width:1180px;margin:0 auto;padding:84px 24px 96px;text-align:center}
.canvas__room{position:absolute;inset:0;pointer-events:none;opacity:0;
  background:radial-gradient(120% 92% at 50% 44%, rgba(11,16,24,0) 26%, rgba(11,16,24,.94) 82%)}
.pg-canvas__kicker{
  margin:0 0 34px;font-size:clamp(28px,3.6vw,44px);font-weight:400;line-height:1.12;   /* 2026-09-06: was 20-27px / 700 — bigger, lighter, a statement not a label */
  letter-spacing:-.02em;color:var(--pg-ink);
}
.pg-canvas__kicker span{white-space:nowrap}   /* phones break between sentences, never inside one */
.pg-canvas__persp{perspective:1100px}
.pg-canvas__asset{
  position:relative;margin:0;border-radius:22px;overflow:hidden;
  background:var(--pg-surface);border:1px solid var(--pg-hairline);
  box-shadow:var(--pg-shadow),var(--pg-glow);
  aspect-ratio:2840/1749;   /* = the dashboard-live-day-<region>.webp variants (2026-09-08; the single asset was 2880/1764) */
  will-change:transform;
}
.pg-canvas__asset img{display:block;width:100%;height:100%;object-fit:cover}
/* power-on flash (home-v2, created by scenes.js): a pale wash over the
   screen that the scroll fades away as it opens — opacity only */
.canvas__flash{position:absolute;inset:0;pointer-events:none;opacity:0;
  background:radial-gradient(60% 50% at 50% 50%, rgba(238,242,246,.9) 0%, rgba(238,242,246,.35) 60%, rgba(238,242,246,0) 100%)}
/* the zoom layer (image + chips). --cz lives on the figure: 1 by default;
   scenes.js drives it 1.96 → 1 on phones as the screen scrolls up. The
   origin is the numbers-only crop (sessions card + the two right target
   cards, x 40–91%, y 17–68% of the screenshot at 1.96). */
.canvas__zoom{position:absolute;inset:0;transform:scale(var(--cz,1));transform-origin:81.6% 34.7%;will-change:transform}
.canvas__chips{position:absolute;inset:0;pointer-events:none}
.canvas__chip{
  position:absolute;left:var(--chip-x,50%);top:var(--chip-y,50%);
  /* 2026-09-08 (Kumar, phone screenshot): the screen shrinks to ~358px wide
     under 560px but the chips stayed 12.5px, so "Network uptime" spanned a
     third of the canvas. Font now scales with the viewport — 10px at 390,
     12.5px from ~820px up (desktop unchanged) — and the padding is in em so
     it follows. Anchors (--chip-x/--chip-y) are unchanged. */
  padding:.64em 1.12em;border-radius:999px;white-space:nowrap;
  /* 2026-09-08 round 2 (Kumar): a notch smaller still — 9px at 360, 12.5px
     from ~860px up — and never two lines. Inside the zoom layer the chip
     counter-scales about its own top-left, so it stays this size while its
     anchor rides the zoomed screen. */
  font-size:clamp(9px, 6.5px + .7vw, 12.5px);font-weight:600;color:var(--pg-ink);
  background:var(--pg-glass);border:1px solid var(--pg-hairline);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  box-shadow:0 12px 30px -12px rgba(0,0,0,.5);
  transform-origin:0 0;
  opacity:0;transform:translateY(8px) scale(calc(1 / var(--cz,1)));
  transition:opacity .5s var(--pg-ease),transform .5s var(--pg-ease);
}
.canvas__chips.is-on .canvas__chip{opacity:1;transform:scale(calc(1 / var(--cz,1)))}
/* phones: "Live sessions" moves from above the sessions card (outside the
   zoomed window) to the trend line under its figure */
@media (max-width:480px){.canvas__chip:nth-child(1){--chip-x:57% !important;--chip-y:30% !important}}
.canvas__chips.is-on .canvas__chip:nth-child(2){transition-delay:.1s}
.canvas__chips.is-on .canvas__chip:nth-child(3){transition-delay:.2s}
.is-ff .canvas__chip{backdrop-filter:none;-webkit-backdrop-filter:none;background:var(--pg-bg-2)}

/* ── network: five live regions, one fleet push, guest analytics. Panels are
   "instrument" surfaces and stay night-dark in BOTH themes (same convention
   as .worth__out); only the section ground and the header text theme. Every
   loop is an HTML overlay driven by transform/opacity and armed by
   .net.is-live — no SVG content animation anywhere (PERF-FIREFOX.md). The
   resting CSS pose is the finished pose: all 50 tiles live, bar full, no
   packets in flight, so the section reads complete without JS. ── */
.net{position:relative;padding:112px 0 96px}
.net__head{padding-top:0;padding-bottom:0}
.net__eyebrow{margin:0 0 22px;display:flex;align-items:center;gap:10px;
  font:600 11px/1 var(--bs-mono);letter-spacing:.22em;text-transform:uppercase;color:var(--pg-mute)}
.net__eyebrow b{font-weight:600;color:var(--pg-ink-soft)}
/* the section's live language in miniature: the same emerald as the pins,
   pinging only once the scene arms (.is-live); a hairline takes the middot's
   place. Guards mirror the live-dot set: is-ff, reduced-motion, ?static. */
.net__eyebrow-dot{position:relative;flex:none;width:6px;height:6px;border-radius:50%;
  background:var(--pg-emerald-hi);box-shadow:0 0 8px rgba(46,212,154,.45)}
.net__eyebrow-dot::after{content:"";position:absolute;inset:-4px;border-radius:50%;
  border:1px solid rgba(46,212,154,.65);opacity:0}
.net.is-live .net__eyebrow-dot::after{animation:net-eyebrow-ping 2.8s ease-out infinite}
@keyframes net-eyebrow-ping{0%{transform:scale(.5);opacity:.9}70%,100%{transform:scale(1.8);opacity:0}}
.net__eyebrow-sep{flex:none;width:18px;height:1px;background:linear-gradient(90deg,var(--pg-faint),transparent)}
html.is-ff .net__eyebrow-dot::after{animation:none!important;opacity:0}
.net__wrap{max-width:1180px;margin:0 auto;padding:0 24px;box-sizing:border-box}
.net__kicker{margin:0;font:600 10px/1 var(--bs-mono);letter-spacing:.18em;text-transform:uppercase;color:#9aa3ad}
.net__h3{margin:18px 0 0;font-family:var(--pg-display);font-size:34px;line-height:1.15;font-weight:500;color:#eef2f6}
.net__copy{margin:14px 0 0;font-size:15px;line-height:1.65;color:#9aa3ad}

/* the map */
.net__map{position:relative;margin:64px 0 0;aspect-ratio:2000/864;overflow:hidden}
.net__land,.net__arcs{position:absolute;inset:0;width:100%;height:100%;display:block}
/* the land is one flat fill inside an <img>, so day inverts it to a soft
   grey instead of shipping a second file — labels then read in both themes */
html[data-theme="light"] .net__land{filter:invert(1) saturate(0)}
.net__arcs path{fill:none;stroke:rgba(46,212,154,.3);stroke-width:2.4;stroke-dasharray:5 14;stroke-linecap:round}
.net__packets{position:absolute;left:0;top:0;width:2000px;height:864px;transform-origin:0 0;
  transform:scale(var(--net-s,1));pointer-events:none}
.net__packets i{position:absolute;left:0;top:0;width:9px;height:9px;margin:-4.5px 0 0 -4.5px;
  border-radius:50%;background:#2ed49a;box-shadow:0 0 10px rgba(46,212,154,.9);opacity:0;offset-rotate:0deg}
.net.is-live .net__packets i{animation-name:net-packet;animation-timing-function:linear;animation-iteration-count:infinite}
@keyframes net-packet{0%{offset-distance:0%;opacity:0}10%{opacity:1}85%{opacity:1}100%{offset-distance:100%;opacity:0}}
.net__pin{position:absolute;width:10px;height:10px;margin:-5px 0 0 -5px;border-radius:50%;
  background:#2ed49a;box-shadow:0 0 0 3px rgba(46,212,154,.15)}
.net__pin i{position:absolute;inset:0;border-radius:50%;background:rgba(46,212,154,.5);opacity:0}
.net.is-live .net__pin i{animation:net-pulse 3s var(--d,0s) ease-out infinite}
@keyframes net-pulse{0%{transform:scale(.5);opacity:.8}70%,100%{transform:scale(2.6);opacity:0}}
.net__label{position:absolute;font:600 10px/1.5 var(--bs-mono);letter-spacing:.14em;white-space:nowrap}
.net__label b{display:block;font-weight:600;color:var(--pg-ink)}
.net__label em{display:block;font-style:normal;color:var(--pg-mute)}
.net__label--b{transform:translate(-50%,12px);text-align:center}
.net__label--t{transform:translate(12px,-34px)}
.net__label--r{transform:translate(12px,-6px)}
.net__mapfoot{display:flex;justify-content:space-between;gap:16px;margin:16px 0 0;
  font:600 10px/1.5 var(--bs-mono);letter-spacing:.18em;text-transform:uppercase;color:var(--pg-mute)}

/* cloud-control panel */
.net__cloud{margin:56px 0 0;background:#141b25;border:1px solid rgba(255,255,255,.07);border-radius:16px;
  padding:48px;display:grid;grid-template-columns:400px 1fr;gap:56px;align-items:start;box-sizing:border-box}
.net__push{display:inline-flex;align-items:center;gap:10px;margin-top:26px;background:#2ed49a;color:#0b1018;
  border-radius:999px;padding:14px 24px;font-weight:600;font-size:14px}
.net__push svg,.net__report svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2.2;
  stroke-linecap:round;stroke-linejoin:round}
.net__pushmeta{margin:16px 0 0;font:600 10px/1 var(--bs-mono);letter-spacing:.16em;text-transform:uppercase;color:#9aa3ad}
.net__kpis{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:26px;padding-top:22px;
  border-top:1px solid rgba(255,255,255,.08)}
.net__kpis span{display:block;min-height:2.1em;font:600 9px/1.15 var(--bs-mono);letter-spacing:.16em;text-transform:uppercase;color:#9aa3ad}
.net__kpis b{display:block;margin-top:8px;font-size:18px;font-weight:700;color:#eef2f6;font-variant-numeric:tabular-nums}
.net__rhead,.net__chead{display:flex;justify-content:space-between;align-items:center;gap:14px;margin:0 0 18px}
.net__live{display:inline-flex;align-items:center;gap:8px;font:600 10px/1 var(--bs-mono);letter-spacing:.16em;
  text-transform:uppercase;color:#2ed49a}
.net__live i{width:6px;height:6px;border-radius:50%;background:#2ed49a;box-shadow:0 0 0 3px rgba(46,212,154,.15);flex:none}
.net__live b{font-weight:600;font-variant-numeric:tabular-nums}
.net__far{font:600 10px/1 var(--bs-mono);letter-spacing:.16em;text-transform:uppercase;color:#9aa3ad;text-align:right}

/* the 50-tile rollout */
.net__rollout{position:relative;overflow:hidden}
.net__chips{display:grid;grid-template-columns:repeat(10,1fr);gap:10px}
.net__chip{height:38px;border-radius:8px;background:#0b1018;border:1px solid rgba(255,255,255,.07);
  display:flex;align-items:center;justify-content:center;position:relative}
.net__chip::before{content:"";width:6px;height:6px;border-radius:50%;background:#6b7480}
.net__chip i{position:absolute;width:6px;height:6px;border-radius:50%}
.net__chip-up{background:#ffd84d;opacity:0}
.net__chip-on{background:#2ed49a}
.net.is-live .net__chip-up{animation:net-upd 2.4s linear both}
.net.is-live .net__chip-on{animation:net-on 2.4s linear backwards}
@keyframes net-upd{0%,30%{opacity:0}42%,80%{opacity:1}100%{opacity:0}}
@keyframes net-on{0%,80%{opacity:0}100%{opacity:1}}
.net__sweep{position:absolute;top:0;bottom:56px;left:-60px;width:60px;opacity:0;pointer-events:none;
  background:linear-gradient(90deg,rgba(46,212,154,0),rgba(46,212,154,.12),rgba(46,212,154,0))}
.net.is-live .net__sweep{animation:net-sweep 9.5s linear}
@keyframes net-sweep{0%{transform:translateX(0);opacity:0}8%{opacity:1}92%{opacity:1}100%{transform:translateX(808px);opacity:0}}
.net__bar{margin-top:18px;height:4px;border-radius:2px;background:rgba(255,255,255,.08);overflow:hidden}
.net__bar i{display:block;height:100%;width:100%;background:#2ed49a;border-radius:2px;transform-origin:left}
.net.is-live .net__bar i{animation:net-fill 9.5s linear}
@keyframes net-fill{0%,15%{transform:scaleX(0)}75%,100%{transform:scaleX(1)}}
.net__legend{display:flex;align-items:center;gap:18px;margin:10px 0 0;
  font:600 9px/1 var(--bs-mono);letter-spacing:.14em;text-transform:uppercase;color:#9aa3ad}
.net__legend span{display:inline-flex;align-items:center;gap:6px}
.net__legend b{margin-left:auto;font:600 10px/1 var(--bs-mono);letter-spacing:.16em;color:#9aa3ad}
.net__legend i,.net__keys i,.net__device i{width:6px;height:6px;border-radius:50%;flex:none}
.net__dot--wait{background:#6b7480}
.net__dot--upd{background:#ffd84d}
.net__dot--on{background:#2ed49a}

/* live client telemetry */
.net__clients{margin-top:24px;padding-top:20px;border-top:1px solid rgba(255,255,255,.08)}
.net__chead>span:first-child{font:600 9px/1 var(--bs-mono);letter-spacing:.16em;text-transform:uppercase;color:#9aa3ad}
.net__client{display:grid;grid-template-columns:190px 1fr 90px;gap:20px;align-items:center;margin-bottom:12px}
.net__client:last-child{margin-bottom:0}
.net__cname{font:600 10px/1.4 var(--bs-mono);letter-spacing:.12em;color:#eef2f6}
.net__cname em{display:block;font-style:normal;color:#9aa3ad}
.net__spark{display:flex;align-items:flex-end;justify-content:space-between;height:20px}
.net__spark i{width:3px;border-radius:1px;background:rgba(46,212,154,.55);transition:height .45s linear}
.net__mbps{text-align:right;font:600 9px/1 var(--bs-mono);letter-spacing:.1em;color:#9aa3ad}
.net__mbps b{font:700 15px/1 var(--pg-font);color:#eef2f6;font-variant-numeric:tabular-nums;margin-right:5px}

/* the three cards */
.net__cards{margin:24px 0 0;display:grid;grid-template-columns:repeat(3,1fr);gap:24px}
.net__card{background:#141b25;border:1px solid rgba(255,255,255,.07);border-radius:16px;padding:28px;
  box-sizing:border-box;display:flex;flex-direction:column}
.net__cardline{margin:16px 0 0;font-family:var(--pg-display);font-size:28px;line-height:1.25;font-weight:500;color:#eef2f6}
.net__cardline em{font-style:normal;color:#9aa3ad}
.net__card .net__kpis{margin-top:20px;padding-top:18px}
.net__heat{display:flex;flex-direction:column;gap:2px;margin-top:24px}
.net__heat-row{display:flex;align-items:center;gap:2px}
.net__heat-row b{width:22px;font:500 8px/1 var(--bs-mono);font-weight:500;color:#9aa3ad}
.net__heat-row i{flex:1;aspect-ratio:1;border-radius:2px;min-width:0}
.net__heat-ax{display:flex;justify-content:space-between;margin:4px 0 0 24px;
  font:500 8px/1 var(--bs-mono);color:#9aa3ad}
.net__scale{display:flex;align-items:center;gap:5px;margin:14px 0 0;font:500 9px/1 var(--bs-mono);color:#9aa3ad}
.net__scale i{width:10px;height:10px;border-radius:2px}
.net__split{display:flex;align-items:center;gap:26px;margin-top:26px}
.net__donut{width:140px;height:140px;border-radius:50%;flex:none;
  background:conic-gradient(#2ed49a 0 223.2deg,#ffd84d 223.2deg 360deg);
  -webkit-mask:radial-gradient(closest-side,transparent 61%,#000 62%);mask:radial-gradient(closest-side,transparent 61%,#000 62%)}
.net__keys{display:flex;flex-direction:column;gap:14px;flex:1;min-width:0}
.net__keys>span,.net__device>span{display:flex;align-items:center;gap:9px;font-size:14px;color:#eef2f6}
.net__keys b,.net__device b{margin-left:auto;font:600 11px/1 var(--bs-mono);color:#9aa3ad;white-space:nowrap}
.net__device{margin-top:auto;padding-top:22px;border-top:1px solid rgba(255,255,255,.08);
  display:flex;flex-direction:column;gap:12px}
.net__device>span{font-size:13px}
.net__card--perf{border-color:rgba(46,212,154,.22);
  background:radial-gradient(120% 100% at 25% 0%,rgba(46,212,154,.6),rgba(46,212,154,0) 60%),
  linear-gradient(165deg,#14372a 0%,#0d1a24 55%,#0b1018 100%)}
.net__card--perf .net__kicker{color:rgba(238,242,246,.8)}
.net__card--perf .net__copy{color:rgba(238,242,246,.85);max-width:30ch}
.net__perfline{margin:18px 0 0;font-family:var(--pg-display);font-size:40px;line-height:1.1;font-weight:500;color:#fff}
.net__perfline b{font-family:var(--pg-font);font-weight:800;font-variant-numeric:tabular-nums}
.net__perffoot{margin-top:auto;padding-top:40px}
.net__report{display:inline-flex;align-items:center;gap:10px;margin-top:16px;background:#eef2f6;color:#0b1018;
  border-radius:999px;padding:13px 22px;font-weight:600;font-size:14px;text-decoration:none;transition:transform .18s}
.net__report:hover{transform:translateY(-1px);color:#0b1018}

@media (max-width:980px){
  .net{padding:76px 0 64px}
  .net__wrap{padding:0 20px}
  .net__cloud{grid-template-columns:1fr;gap:36px;padding:32px 24px}
  .net__cards{grid-template-columns:1fr}
  .net__label em{display:none}
}
@media (max-width:700px){
  .net__map{margin-top:40px}
  .net__label{font-size:8.5px;letter-spacing:.08em}
  .net__chips{grid-template-columns:repeat(5,1fr);gap:7px}
  .net__chip{height:30px}
  .net__client{grid-template-columns:130px 1fr 74px;gap:12px}
  .net__mapfoot{flex-direction:column;gap:5px}
  .net__split{gap:18px}
  .net__donut{width:104px;height:104px}
}
@media (max-width:480px){
  /* 320px: donut (104) + gap (18) leaves ~120px for a key row whose min-content
     is ~170px (the figure carries white-space:nowrap), so the row pushed
     scrollWidth to 331 against a 320 viewport. body{overflow-x:clip} hid the
     sideways scroll but the text was still being squeezed. Stack the donut
     above its keys on the narrowest phones and the pressure goes away. */
  .net__split{flex-wrap:wrap;gap:14px;justify-content:center}
  .net__keys{flex-basis:100%}
  .net__label--t,.net__label--r{transform:translate(-50%,12px);text-align:center}
  .net__cloud,.net__card{padding:22px 18px}
  .net__h3{font-size:26px}
  .net__cardline,.net__perfline{font-size:24px}
  .net__spark i{width:2px}
}
/* ?static rides body.no-anim, not the OS media query */
@media (prefers-reduced-motion:reduce){
  .net__spark i{transition:none}
  .net .is-live *{animation:none!important}
  .net.is-live .net__eyebrow-dot::after{animation:none!important;opacity:0}
}
.no-anim .net__spark i{transition:none}
.no-anim .net__eyebrow-dot::after{animation:none!important;opacity:0}

/* ── wifi-worth: the venue's own first screen. Left column makes the
   channel visible (a phone running the venue's spot, then its text);
   right column separates the two registers — reach as a COUNT, paid WiFi
   as MONEY — so a reader can never blur them. Red appears exactly once,
   on the demo ask. ── */
.worth{scroll-margin-top:96px}
.worth__legacy-anchor{position:absolute;top:0;height:0}
.worth__head{max-width:none;margin-bottom:clamp(36px,5vw,56px)}
.worth__headrow{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}
.worth__headrow .sec__badge{margin:0}
.worth__title{max-width:15ch}
.worth__ccy{display:flex;gap:6px;flex-wrap:wrap}
.worth__ccybtn{font:800 10px/1 var(--pg-font);letter-spacing:.14em;color:var(--pg-mute);
  background:none;border:1px solid var(--pg-hairline);border-radius:8px;padding:8px 11px;cursor:pointer;
  transition:color .18s,border-color .18s,background .18s}
/* 44px minimum (WCAG 2.2 / HIG). These chips sit in a 6px-gap flex row, so the
   box itself grows — a stretched pseudo would overlap the neighbouring chip,
   which the audit explicitly warns against. */
.worth__ccybtn{min-height:44px;min-width:44px}
.worth__ccybtn:hover{color:var(--pg-ink);border-color:var(--pg-faint)}
.worth__ccybtn[aria-pressed="true"]{color:var(--pg-bg);background:var(--pg-ink);border-color:var(--pg-ink)}

.worth__grid{display:grid;grid-template-columns:minmax(0,430px) minmax(0,1fr);
  gap:clamp(28px,4vw,56px);align-items:start}

/* small uppercase labels — the section's connective tissue */
.worth__label{display:block;margin:0;font:800 9.5px/1.5 var(--pg-font);letter-spacing:.18em;
  text-transform:uppercase;color:var(--pg-mute)}
.worth__label--dim{color:var(--pg-faint)}
.worth__label--em{color:var(--pg-emerald-hi)}

/* ── left: the channel ── */
.worth__channel{margin:0;background:var(--pg-bg-2);border:1px solid var(--pg-hairline);
  border-radius:20px;padding:clamp(18px,3vw,26px)}
.worth__chead{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;
  margin-bottom:18px}
.worth__own{font:800 9.5px/1.5 var(--pg-font);letter-spacing:.18em;text-transform:uppercase;
  color:var(--pg-emerald-hi)}
.worth__clabel{margin:0 0 14px;font:800 9px/1.5 var(--pg-font);letter-spacing:.16em;
  text-transform:uppercase;color:var(--pg-faint);text-align:center}

/* the phone: a fixed 290x630 stage so the internals can be tuned in px.
   Everything inside is HTML — the two static SVGs are icons, never animated. */
.worth__phone{position:relative;width:min(290px,100%);aspect-ratio:290/630;margin:0 auto;
  border-radius:34px;overflow:hidden;background:#05070b;
  box-shadow:0 30px 58px rgba(0,0,0,.4),0 0 0 1px rgba(255,255,255,.07)}
.worth__island{position:absolute;top:8px;left:50%;transform:translateX(-50%);width:91px;height:27px;
  border-radius:17px;background:#000;z-index:5}
.worth__status{position:absolute;top:0;left:0;right:0;z-index:4;display:flex;align-items:center;
  justify-content:space-between;padding:15px 18px 0;color:#fff}
.worth__time{font:600 12px/1 var(--pg-font);font-variant-numeric:tabular-nums}
.worth__icons{display:flex;align-items:center;gap:5px}
.worth__icons svg{display:block;fill:currentColor}
.worth__home{position:absolute;bottom:7px;left:50%;transform:translateX(-50%);width:100px;height:4px;
  border-radius:2px;background:rgba(255,255,255,.7);z-index:6;pointer-events:none}

/* two moments, one stage. Opacity-only crossfade on an HTML overlay: never
   animate inside an SVG (Gecko re-rasterises per frame — PERF-FIREFOX.md).
   Resting pose = portal finished, thread at 0, so no-JS/?static read whole. */
.worth__screens{position:absolute;inset:0;display:grid}
.worth__screen{grid-area:1/1;position:relative;overflow:hidden}
@keyframes worthCardA{0%,44%{opacity:1}52%,94%{opacity:0}100%{opacity:1}}
@keyframes worthCardB{0%,44%{opacity:0}52%,94%{opacity:1}100%{opacity:0}}
.worth__screen--portal{opacity:1;animation:worthCardA 16s linear infinite;
  background:linear-gradient(135deg,#16281f,#1e3a2f 55%,#2c4d3c)}
.worth__screen--sms{opacity:0;animation:worthCardB 16s linear infinite;background:#000;
  display:flex;flex-direction:column;
  font-family:-apple-system,"SF Pro",system-ui,var(--pg-font),sans-serif}

/* card A — the portal, mid-roll on the venue's own spot. The spot is real
   footage cropped to this exact aspect at encode time, so object-fit never
   has to crop it further; the gradient underneath only shows before the
   poster paints. */
.worth__vid{position:absolute;inset:0;display:block;width:100%;height:100%;
  object-fit:cover;background:#000;border:0}
/* the play glyph IS the paused pose — it leaves once the spot actually runs
   (and comes back when the observer pauses it off-screen) */
.worth__play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:44px;height:44px;
  border-radius:50%;background:rgba(245,241,232,.92);transition:opacity .3s}
.worth__screen--portal.is-playing .worth__play{opacity:0}
.worth__play::after{content:"";position:absolute;top:50%;left:52%;transform:translate(-50%,-50%);
  width:0;height:0;border-left:13px solid #1e3a2f;border-top:8px solid transparent;
  border-bottom:8px solid transparent}
.worth__pshade{position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(5,7,11,.6),rgba(5,7,11,0) 32%,rgba(5,7,11,0) 55%,rgba(5,7,11,.75))}
.worth__ptop{position:absolute;top:0;left:0;right:0;padding:50px 14px 0;display:flex;
  align-items:flex-start;justify-content:space-between;gap:10px}
.worth__ptop > span{display:flex;flex-direction:column;gap:6px;min-width:0}
.worth__venue{font:500 15px/1 var(--pg-display);letter-spacing:.14em;text-transform:uppercase;color:#f5f1e8}
.worth__ptop small{font:800 6.5px/1 var(--pg-font);letter-spacing:.2em;color:#c9d6cc}
.worth__ptop em{flex:none;font:800 6.5px/1 var(--pg-font);letter-spacing:.12em;font-style:normal;
  color:#fff;background:rgba(5,7,11,.7);border-radius:4px;padding:4px 6px}
.worth__pbot{position:absolute;left:0;right:0;bottom:0;padding:0 12px 34px;
  display:grid;grid-template-columns:1fr auto;gap:10px 8px;align-items:center}
.worth__prog{height:3px;border-radius:2px;background:rgba(245,241,232,.25);overflow:hidden}
/* 40% == the 0:04 poster frame; page.js drives it from timeupdate once playing */
.worth__prog i{display:block;width:40%;height:100%;border-radius:2px;background:rgba(245,241,232,.85)}
.worth__ptime{font:800 6.5px/1 var(--pg-font);letter-spacing:.08em;color:rgba(245,241,232,.85);
  font-variant-numeric:tabular-nums}
.worth__pcta{grid-column:1/-1;text-align:center;font:700 12.5px/1 var(--pg-font);color:#1e3a2f;
  background:#f5f1e8;border-radius:11px;padding:13px 12px}
.worth__psec{grid-column:1/-1;text-align:center;font:800 6.5px/1 var(--pg-font);letter-spacing:.16em;
  color:rgba(245,241,232,.7)}

/* card B — the follow-up text, after the visit */
.worth__smshead{padding:46px 12px 7px;text-align:center;background:rgba(28,28,30,.94);
  border-bottom:.5px solid rgba(255,255,255,.15)}
.worth__avatar{display:flex;align-items:center;justify-content:center;width:33px;height:33px;
  margin:0 auto;border-radius:50%;background:linear-gradient(180deg,#8a929c,#6a717a);
  font-size:14px;font-weight:600;color:#fff}
.worth__smshead b{display:block;margin-top:5px;font-size:9.5px;font-weight:400;color:#fff}
/* newest message sits against the input bar, the way a real thread does */
.worth__thread{flex:1;display:flex;flex-direction:column;justify-content:flex-end;gap:7px;
  padding:11px 11px 0;overflow:hidden}
.worth__day{font-size:8.5px;color:#8e8e93;text-align:center}
.worth__thread p{align-self:flex-start;max-width:82%;margin:0;padding:7px 10px;border-radius:13px;
  background:#26252a;color:#fff;font-size:11px;line-height:1.35}
.worth__sms-meta{font-size:8px;color:#8e8e93;padding-left:5px}
.worth__smsbar{display:flex;align-items:center;gap:7px;padding:8px 11px 34px}
.worth__smsbar span{display:flex;align-items:center;justify-content:center;width:26px;height:26px;
  border-radius:50%;background:#26252a;color:#8e8e93;font-size:17px;font-weight:300;flex:none}
.worth__smsbar i{flex:1;font-style:normal;font-size:11px;color:#8e8e93;
  border:1px solid rgba(255,255,255,.22);border-radius:13px;padding:6px 10px}

.worth__note{margin:18px 0 0;font-size:13px;line-height:1.6;color:var(--pg-mute)}
.worth__rules{margin-top:16px;padding-top:14px;border-top:1px solid var(--pg-hairline)}
.worth__chips{display:flex;flex-wrap:wrap;gap:6px;margin:12px 0 0;padding:0;list-style:none}
.worth__chips li{font:800 8.5px/1 var(--pg-font);letter-spacing:.12em;text-transform:uppercase;
  color:var(--pg-ink-soft);border:1px solid var(--pg-hairline);border-radius:999px;padding:7px 10px}

/* ── right: the numbers ── */
.worth__panel{display:flex;flex-direction:column;gap:26px;min-width:0}
.worth__inputs{background:var(--pg-surface);border:1px solid var(--pg-hairline);border-radius:16px;
  padding:clamp(18px,2.5vw,22px)}
.worth__inputs .worth__label{margin-bottom:16px}
.worth__fields{display:flex;flex-wrap:wrap;gap:20px 34px}
.worth__field{min-width:0}
.worth__field--full{flex:1 1 100%}
.worth__field label{display:block;margin-bottom:9px;font:800 9px/1.4 var(--pg-font);letter-spacing:.16em;
  text-transform:uppercase;color:var(--pg-mute)}
.worth__fieldhead{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  margin-bottom:11px}
.worth__fieldhead label{margin:0}
.worth__fieldhead b{font:800 13px/1 var(--pg-font);color:var(--pg-ink);font-variant-numeric:tabular-nums}
.worth__step{display:flex;align-items:center;gap:4px}
/* 44x44 (WCAG 2.2 / HIG) — the steppers are the phone-side way to change these
   figures, so the box itself grows; the 4px row gap keeps them from touching. */
.worth__step button{width:44px;height:44px;flex:none;border-radius:9px;border:1px solid var(--pg-hairline);
  background:none;color:var(--pg-ink);font:600 16px/1 var(--pg-font);cursor:pointer;
  transition:border-color .18s,color .18s}
.worth__step button:hover{border-color:var(--pg-emerald);color:var(--pg-emerald-hi)}
.worth__step input{width:62px;min-height:44px;background:none;border:0;padding:0;text-align:center;
  font:800 20px/1 var(--pg-font);color:var(--pg-ink);font-variant-numeric:tabular-nums}
.worth__step--wide input{width:80px}
/* the remaining bare number fields in the calculator */
.worth input[type="number"],.worth input[type="text"]{min-height:44px}
.worth__unit{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--pg-hairline);
  border-radius:9px;padding:7px 11px}
.worth__unit b{font:800 13px/1 var(--pg-font);color:var(--pg-mute)}
.worth__unit input{width:84px;background:none;border:0;padding:0;font:800 18px/1 var(--pg-font);
  color:var(--pg-ink);font-variant-numeric:tabular-nums}
.worth__unit--suffix input{width:52px;text-align:right}
/* the spinners fight the stepper buttons for the same job */
.worth input[type="number"]{-moz-appearance:textfield;appearance:textfield}
.worth input[type="number"]::-webkit-inner-spin-button,
.worth input[type="number"]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}
/* 44px tall so the thumb is draggable with a thumb; the track keeps its own
   painted height, the extra is transparent box around it. */
.worth input[type="range"]{width:100%;accent-color:var(--pg-emerald-hi);cursor:pointer;min-height:44px}

/* REACH — a count. Nothing here is styled as money. */
.worth__reachhead{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  flex-wrap:wrap;margin:0}
.worth__fig{margin:12px 0 0;font:800 clamp(40px,6vw,62px)/1.05 var(--pg-font);color:var(--pg-ink);
  font-variant-numeric:tabular-nums;letter-spacing:-.02em;min-height:1.05em;overflow-wrap:anywhere}
.worth__reachnote{margin:10px 0 0;font-size:15px;line-height:1.6;color:var(--pg-mute);max-width:46ch}
.worth__reachnote b{color:var(--pg-ink-soft);font-weight:700}

/* PAID WIFI — the one direct line. Both states share a grid cell so the block
   is always as tall as the taller of the two: flipping the switch cannot shove
   the CTA down the page at ANY width, which a fixed min-height cannot promise.
   visibility (not display) keeps a typed price alive across a flip, and still
   drops the inert half out of the a11y tree and the tab order. */
.worth__paid{border:1px solid rgba(46,212,154,.38);border-radius:16px;
  padding:clamp(18px,2.5vw,22px)}
.worth__paidstack{display:grid}
.worth__paidbody,.worth__paidoff{grid-area:1/1}
.worth__paidbody{visibility:hidden;opacity:0;transition:opacity .2s}
.worth__paid.is-selling .worth__paidbody{visibility:visible;opacity:1}
.worth__paid.is-selling .worth__paidoff{visibility:hidden;opacity:0}
.worth__paidoff{transition:opacity .2s}
.worth__paidhead{display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap}
.worth__switch{display:inline-flex;align-items:center;gap:9px;background:none;border:0;padding:0;min-height:44px;
  cursor:pointer;font:700 11.5px/1 var(--pg-font);color:var(--pg-ink)}
.worth__knob{position:relative;width:42px;height:24px;flex:none;border-radius:999px;
  border:1px solid var(--pg-hairline);background:none;transition:background .2s,border-color .2s}
.worth__knob i{position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;
  background:var(--pg-mute);transition:transform .2s,background .2s}
.worth__switch[aria-checked="true"] .worth__knob{background:var(--pg-emerald-hi);
  border-color:var(--pg-emerald-hi)}
.worth__switch[aria-checked="true"] .worth__knob i{transform:translateX(18px);background:#0b1018}
.worth__paidbody .worth__fields{margin-top:18px}
.worth__money{margin:18px 0 0;font:800 clamp(22px,2.8vw,30px)/1.2 var(--pg-font);
  color:var(--pg-emerald-hi);font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
.worth__money small{font:700 14px/1 var(--pg-font);color:var(--pg-mute)}
.worth__paidnote{margin:8px 0 0;font-size:13px;line-height:1.6;color:var(--pg-mute)}
.worth__paidoff{margin-top:18px}
.worth__paidoff > p:first-child{margin:0;max-width:44ch;font-size:13px;line-height:1.6;color:var(--pg-mute)}
.worth__paidoff .worth__label{margin:20px 0 0}
.worth__paidnote em{font-style:normal;font-weight:800;font-size:9px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--pg-faint)}

.worth__back{display:flex;align-items:baseline;gap:18px;flex-wrap:wrap;padding-top:20px;
  border-top:1px solid var(--pg-hairline)}
.worth__back .worth__label{white-space:nowrap}
.worth__back p{flex:1 1 280px;margin:0;font-size:14px;line-height:1.65;color:var(--pg-mute)}
.worth__ctas{display:flex;align-items:center;gap:22px;flex-wrap:wrap}

.worth__formula{display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap;
  margin:clamp(40px,5vw,60px) 0 0;font:800 9px/1.8 var(--pg-font);letter-spacing:.14em;
  text-transform:uppercase;color:var(--pg-faint)}

@media (max-width:900px){
  /* stacked: the card runs full width (a 470px cap strands it beside 300px
     of dead space at ~768) and the phone centres inside it */
  .worth__grid{grid-template-columns:1fr;gap:34px}
}
@media (max-width:560px){
  .worth__fields{gap:18px 22px}
  .worth__back{gap:10px}
}
/* ?static rides body.no-anim, not the OS media query */
@media (prefers-reduced-motion:reduce){
  .worth__screen{animation:none!important}
  .worth__paidbody,.worth__paidoff,.worth__knob,.worth__knob i,.worth__play{transition:none}
}
.no-anim .worth__screen{animation:none!important}
.no-anim .worth__play{transition:none}
.no-anim .worth__paidbody,.no-anim .worth__paidoff,
.no-anim .worth__knob,.no-anim .worth__knob i{transition:none}

/* ── products: the hardware lineup (2026-09-06, canvas 4708b901 round 2) ──
   One open surface, two rows of two family cells. Each cell stacks the name
   block (eyebrow, blurb, giant watermark) over the device row, which pulls
   up into the watermark's lower line by 0.568 of the giant size (50px at
   88px). Everything below is the RESOLVED pose: scenes.js initProducts sets
   the hidden states (name faded, devices 96px lower) and scrubs them in, so
   ?static, reduced-motion and no-JS render this exactly. The giant scales
   with the viewport (88px at ≥1228, 52px floor) so two nameplates fit side
   by side down to the 720px stack point. */
.hw{--hw-giant:clamp(52px,6.1vw,88px);padding:152px 24px 128px}
.hw .sec__head{margin-bottom:88px}
.hw__grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:64px 48px;align-items:start}
.hw__cell{display:flex;flex-direction:column;align-items:center;text-align:center;min-width:0}
.hw__name{display:flex;flex-direction:column;align-items:center;will-change:transform,opacity}
.hw__eyebrow{margin:0;font-size:12px;line-height:1.3;font-weight:700;letter-spacing:.22em;text-transform:uppercase;color:var(--pg-mute)}
.hw__eyebrow b{font-weight:700;color:var(--pg-emerald)}
.hw__blurb{margin:6px 0 0;font-size:14.5px;line-height:1.5;color:var(--pg-mute);text-wrap:pretty}
.hw__giant{
  margin-top:12px;font-size:var(--hw-giant);font-weight:800;line-height:.9;letter-spacing:-.01em;
  text-transform:uppercase;white-space:nowrap;color:rgba(238,242,246,.06);user-select:none;pointer-events:none;
}
.hw__giant-thin{display:block;font-weight:200;letter-spacing:.04em}
.hw__devices{
  position:relative;display:flex;justify-content:center;align-items:flex-end;gap:32px;width:100%;
  margin-top:calc(var(--hw-giant) * -.568);will-change:transform;
}
.hw__dev{display:flex;flex-direction:column;align-items:center;gap:14px;min-width:0;max-width:46%;text-decoration:none;color:var(--pg-ink)}
.hw__devices--solo .hw__dev{max-width:88%}
.hw__dev img{
  display:block;max-height:clamp(156px,14.2vw,204px);max-width:100%;width:auto;height:auto;
  filter:drop-shadow(0 12px 18px rgba(0,0,0,.5));
}
.hw__cap{
  display:inline-flex;align-items:center;gap:8px;font-size:15px;line-height:1.3;font-weight:600;color:var(--pg-ink);
  border-bottom:1px solid var(--pg-hairline);padding-bottom:3px;white-space:nowrap;transition:color .25s,border-color .25s;
}
.hw__dev:hover .hw__cap,.hw__dev:focus-visible .hw__cap{color:var(--pg-emerald-hi);border-color:var(--pg-emerald)}
.hw__demo{margin-top:56px}
@media(max-width:720px){
  .hw__grid{grid-template-columns:1fr;gap:48px 0}
  .hw__devices{gap:20px}
  .hw__dev{max-width:44%}
}
@media(max-width:560px){
  .hw{padding:100px 20px 84px}
  .hw .sec__head{margin-bottom:56px}
}

/* ── testimonials: three static quote cards (2026-09-06; canvas 9396e352) ──
   Quote verbatim, lead = a phrase lifted from it. Equal-height grid, the
   quote grows, attribution pinned to the bottom. No hover lift: nothing in a
   card is a link, and a lift would say otherwise. Photos 48px with reserved
   dimensions. Same values as .card (surface, hairline, 20px, 26/26/24). */
/* ═══ testimonials — triptych (2026-09-06, canvas 583486b3 Option D) ═══
   No cards: a rule under the head, hairline dividers between three equal
   columns, byline first, then the lead in the display face with the signature
   highlighter stroke (same recipe as .sec__title strong), then the quote.
   Columns end where their quotes end. The dividers are pseudo-elements centred
   in the column gap rather than borders on padded columns, so the grid never
   bleeds past .sec's side padding (a -36px margin bleed overflowed the viewport
   at 900px). --tq-gap shrinks with the viewport so three columns still breathe
   down to the 860px stack point. */
.tq{border-top:1px solid var(--pg-hairline);padding-top:44px}
.tq__grid{--tq-gap:clamp(40px,5vw,72px);display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--tq-gap);align-items:stretch}
.tq__col{position:relative;display:flex;flex-direction:column;margin:0;min-width:0}
.tq__col+.tq__col::before{content:"";position:absolute;top:0;bottom:0;left:calc(var(--tq-gap) / -2);width:1px;background:var(--pg-hairline)}
/* byline height is fixed so the three leads start on one line whether the
   context line wraps or not (Linkbase's does) */
.tq__who{display:flex;align-items:flex-start;gap:12px;min-height:72px}
.tq__who img{width:44px;height:44px;flex:0 0 44px;border-radius:50%;object-fit:cover;border:1px solid var(--pg-hairline);background:var(--pg-bg-2)}
.tq__meta{display:flex;flex-direction:column;gap:2px;min-width:0}
.tq__name{font-size:14px;line-height:1.3;font-weight:600;color:var(--pg-ink)}
.tq__role{font-size:12.5px;line-height:1.35;font-weight:500;color:var(--pg-mute)}
.tq__ctx{font-size:12.5px;line-height:1.35;font-weight:500;color:var(--pg-faint)}
.tq__lead{margin:26px 0 0;font-family:var(--pg-display);font-size:clamp(22px,2.2vw,28px);line-height:1.12;font-weight:500;letter-spacing:-.015em;color:var(--pg-ink);text-wrap:pretty}
.tq__lead strong{
  font-weight:700;
  background-image:linear-gradient(transparent 70%, var(--pg-marker) 70%, var(--pg-marker) 94%, transparent 94%);
  background-repeat:no-repeat;background-position:0 0;background-size:100% 100%;
}
.tq__quote{margin:14px 0 0;font-size:16px;line-height:1.6;font-weight:500;color:var(--pg-ink-soft);text-wrap:pretty}
.tq__link{margin:18px 0 0}
.tq__link .sec__cta{margin-top:0;font-size:14px}
.tq__more{margin:48px 0 0;text-align:center}
.tq__more .sec__cta{margin-top:0}
@media(max-width:860px){
  .tq{padding-top:32px}
  .tq__grid{grid-template-columns:1fr;gap:0}
  .tq__col{padding-bottom:32px}
  .tq__col+.tq__col{padding-top:32px;border-top:1px solid var(--pg-hairline)}
  .tq__col+.tq__col::before{display:none}
  .tq__col:last-child{padding-bottom:0}
  .tq__who{min-height:0}
  .tq__lead{font-size:24px}
  .tq__more{margin-top:40px}
}

/* ═══════════ worldmap (§8A, ported — consumes --pg tokens) ═══════════ */
.wm{position:relative;padding:100px 0 80px;text-align:center;overflow:hidden}
.wm__head{max-width:820px;margin:0 auto 18px;padding:0 24px}
.wm__eyebrow{font-size:12px;font-weight:700;letter-spacing:.18em;text-transform:uppercase;color:var(--pg-faint);margin:0 0 12px}
.wm__stage{position:relative;width:min(1180px,96vw);aspect-ratio:2/1;margin:0 auto;
  -webkit-mask-image:linear-gradient(to right,transparent,#000 7%,#000 93%,transparent),linear-gradient(to bottom,transparent,#000 9%,#000 88%,transparent);
  -webkit-mask-composite:source-in;
  mask-image:linear-gradient(to right,transparent,#000 7%,#000 93%,transparent),linear-gradient(to bottom,transparent,#000 9%,#000 88%,transparent);
  mask-composite:intersect}
.wm__map{display:block;width:100%;height:100%}
.wm-cam{transform-box:view-box;transform-origin:0 0;transform:translate(-139.1px,-32.8px) scale(.7);will-change:transform}
.wm-sea{fill:transparent}
.wm-land{fill:#1a222d;stroke:rgba(238,242,246,.06);stroke-width:.7;vector-effect:non-scaling-stroke}
.wm-country{fill:rgba(160,172,186,.12);stroke:rgba(160,172,186,.2);stroke-width:1;vector-effect:non-scaling-stroke;
  transition:fill .8s cubic-bezier(.22,1,.36,1),fill-opacity .8s ease,stroke .8s ease;fill-opacity:1}
.wm-country.is-active{fill:var(--c,#2ed49a);fill-opacity:.55;stroke:var(--c,#2ed49a);stroke-opacity:.95;
  filter:drop-shadow(0 0 10px var(--c,#2ed49a))}
.is-ff .wm-country.is-active{filter:none}
.wm-pin{opacity:0;transition:opacity .6s ease}
.wm-pin__dot{fill:var(--c,#2ed49a)}
.wm-pin__halo{fill:var(--c,#2ed49a);opacity:.18}
.wm-pin__ring{fill:none;stroke:var(--c,#2ed49a);stroke-width:2.5;opacity:0;vector-effect:non-scaling-stroke}
.wm-pin.is-active{opacity:1}
[data-wm-static] .wm-pin{opacity:1}
.wm-bubble{position:absolute;left:50%;top:50%;width:340px;opacity:0;pointer-events:none;-webkit-font-smoothing:antialiased}
.wm-bubble.is-on{opacity:1}
.wm-bubble__box{position:relative;text-align:left;background:rgba(16,22,30,.9);backdrop-filter:blur(18px) saturate(1.4);
  -webkit-backdrop-filter:blur(18px) saturate(1.4);border:1px solid var(--pg-hairline);border-radius:22px;padding:17px 19px 15px;
  box-shadow:0 2px 6px rgba(0,0,0,.15),0 26px 58px rgba(0,0,0,.4),0 0 44px -20px var(--c,#2ed49a)}
.is-ff .wm-bubble__box{backdrop-filter:none;-webkit-backdrop-filter:none;background:rgba(16,22,30,.97)}
/* accent enters as a wash and a kicker dot, not a bar: the night flight accent grammar */
.wm-bubble__box::before{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:radial-gradient(120% 90% at 12% 0%, var(--c,#2ed49a), transparent 55%);opacity:.1}
.wm-bubble__head{position:relative;display:flex;align-items:center;gap:9px;margin:0 0 12px}
.wm-bubble__flag{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:8px;
  background:rgba(238,242,246,.06);font-size:15px;flex:none;box-shadow:inset 0 0 0 1px rgba(238,242,246,.08)}
.wm-bubble__country{display:inline-flex;align-items:center;gap:7px;font-size:11px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--pg-mute)}
.wm-bubble__country::before{content:"";width:6px;height:6px;border-radius:50%;flex:none;
  background:var(--c,#2ed49a);box-shadow:0 0 10px 1px var(--c,#2ed49a)}
.wm-bubble__live{display:inline-flex;align-items:center;gap:5px;margin-left:auto;font-size:10.5px;font-weight:600;
  letter-spacing:.04em;text-transform:uppercase;color:var(--pg-emerald-hi)}
.wm-bubble__live i{width:6px;height:6px;border-radius:50%;background:var(--pg-emerald-hi);animation:wm-livedot 2.4s ease-out infinite}
@keyframes wm-livedot{0%{box-shadow:0 0 0 0 rgba(21,184,127,.45)}70%,100%{box-shadow:0 0 0 7px rgba(21,184,127,0)}}
/* the quote is the payload: display face, site quote idiom */
.wm-bubble__msg{position:relative;margin:0;font-family:var(--pg-display);font-size:16.5px;line-height:1.48;
  font-weight:500;letter-spacing:-.01em;color:var(--pg-ink);min-height:74px}
.wm-bubble__msg::before{content:"\201C\2009";color:var(--c,#2ed49a);opacity:.85}
.wm-bubble__venue{display:flex;align-items:center;gap:6px;margin:12px 0 0;padding-top:12px;
  border-top:1px solid var(--pg-hairline-soft);font-size:12px;color:var(--pg-mute)}
.wm-bubble__venue svg{width:13px;height:13px;flex:none;fill:none;stroke:var(--pg-mute);stroke-width:1.6;opacity:.8}
.wm-bubble__typing{display:none;gap:5px;align-items:center;height:1.48em}
.wm-bubble__typing.is-on{display:inline-flex}
.wm-bubble__typing i{width:6px;height:6px;border-radius:50%;background:var(--pg-faint);animation:wm-typing 1.2s ease-in-out infinite}
.wm-bubble__typing i:nth-child(2){animation-delay:.18s}
.wm-bubble__typing i:nth-child(3){animation-delay:.36s}
@keyframes wm-typing{0%,60%,100%{opacity:.35;transform:translateY(0)}30%{opacity:1;transform:translateY(-4px)}}
.wm-bubble__tail{position:absolute;left:50%;bottom:-9px;transform:translateX(-50%);width:0;height:0;
  border-left:10px solid transparent;border-right:10px solid transparent;border-top:11px solid rgba(16,22,30,.9);
  filter:drop-shadow(0 7px 5px rgba(0,0,0,.2))}
.wm-bubble::after{content:"";position:absolute;left:50%;bottom:-20px;transform:translateX(-50%);width:2px;height:18px;
  background:linear-gradient(var(--c,#2ed49a),rgba(0,0,0,0));border-radius:2px}
.wm__cta{margin:30px auto 0;max-width:620px;padding:0 24px}
.wm__cta-line{margin:0 0 16px;font-size:15px;color:var(--pg-mute)}
.wm__cta-btn{display:inline-flex;align-items:center;gap:8px;height:48px;padding:0 24px;border-radius:999px;
  background:var(--pg-cta);color:#fff !important;font-size:15px;font-weight:700;text-decoration:none;
  box-shadow:0 18px 40px -14px rgba(226,59,52,.55);
  transition:transform .3s var(--pg-ease),background-color .25s;will-change:transform}
.wm__cta-btn:hover{background:var(--pg-cta-hover);transform:translateY(-2px)}
.wm__cta-btn svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.wm__fallback{max-width:820px;margin:26px auto 0;padding:0 24px}
.wm-fb{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(2,1fr);gap:14px;text-align:left}
.wm-fb__item{display:flex;gap:10px;padding:14px 16px;border:1px solid var(--pg-hairline);border-radius:14px;background:var(--pg-surface)}
.wm-fb__flag{font-size:20px;flex:none}
.wm-fb__msg{margin:0;font-size:13.5px;line-height:1.45;color:var(--pg-ink-soft)}
.wm-fb__venue{margin:6px 0 0;font-size:11.5px;color:var(--pg-mute)}
[data-wm-upgraded] .wm__fallback{display:none}

/* ── about / founder ── */
.about-card{
  position:relative;overflow:hidden;
  background:var(--pg-surface);border:1px solid var(--pg-hairline);border-radius:28px;
  padding:clamp(36px,5vw,64px);
}
.about-card::before{
  content:"";position:absolute;right:-140px;top:-140px;width:460px;height:460px;border-radius:50%;
  background:radial-gradient(50% 50% at 50% 50%, rgba(21,184,127,.14) 0%, rgba(21,184,127,0) 70%);
  pointer-events:none;
}
.about-card h2{margin:0;font-size:clamp(24px,3vw,34px);font-weight:700;letter-spacing:-.02em;color:var(--pg-ink);max-width:22ch}
.about-card p{margin:18px 0 0;font-size:16px;line-height:1.7;color:var(--pg-mute);max-width:68ch}
.about-card a{
  display:inline-flex;margin-top:24px;font-size:15px;font-weight:600;color:var(--pg-ink);
  text-decoration:none;border-bottom:1px solid var(--pg-hairline);padding-bottom:2px;
}
.about-card a:hover{color:var(--pg-emerald-hi);border-color:var(--pg-emerald)}

/* ── final CTA ── */
.final{position:relative;max-width:760px;margin:0 auto;padding:120px 24px 130px;text-align:center}
/* city lights behind the ask: the inline dot-field SVG. CSS default = the
   dimmed resolved pose (.08); scenes.js starts it at .5 and scrubs it down
   so the red button ends as the only light on. Opacity only. */
.final__lights{position:absolute;inset:0;z-index:-1;pointer-events:none;opacity:.08;
  -webkit-mask-image:radial-gradient(92% 86% at 50% 42%, #000 30%, transparent 98%);
  mask-image:radial-gradient(92% 86% at 50% 42%, #000 30%, transparent 98%)}
.final__lights svg{display:block;width:100%;height:100%}
html.is-ff .final__lights{-webkit-mask-image:none;mask-image:none}
.final__title{margin:0;font-family:var(--pg-display);font-size:clamp(36px,5.6vw,64px);font-weight:500;line-height:1.04;letter-spacing:-.02em;color:var(--pg-ink)}
.final__blurb{margin:18px auto 0;font-size:16.5px;line-height:1.65;color:var(--pg-mute);max-width:52ch}
.final__cta-wrap{position:relative;display:inline-block;margin-top:36px}
.final__cta-wrap::before{
  content:"";position:absolute;inset:-18px -30px;border-radius:999px;
  background:radial-gradient(50% 50% at 50% 50%, rgba(226,59,52,.22) 0%, rgba(226,59,52,0) 70%);
  pointer-events:none;
}
.final__reassure{margin:14px 0 0;font-size:13px;letter-spacing:.02em;color:var(--pg-faint)}
.final__rescue{margin:24px 0 0;font-size:14px;color:var(--pg-mute)}
.final__rescue a{color:var(--pg-ink);font-weight:600;text-decoration:none;border-bottom:1px solid var(--pg-hairline);padding-bottom:2px}
.final__rescue a:hover{color:var(--pg-emerald-hi);border-color:var(--pg-emerald)}

/* ── responsive ── */
@media (max-width:980px){
}
@media (max-width:900px){
  .rail-wrap .rail{margin:0 -20px;padding:4px 20px 18px}   /* keep the bleed equal to the section padding */
}
@media (max-width:720px){.wm-fb{grid-template-columns:1fr}.wm-bubble{width:280px}.wm__stage{aspect-ratio:3/2}}
@media (max-width:620px){
}
@media (max-width:560px){
  .rail__card{flex-basis:88vw;padding:26px 24px;min-height:20rem}
  .pg-canvas{padding:56px 16px 64px}
  .trust__row{gap:48px;padding-right:48px}
}

/* ── router handoff: a fixed clone that flies the hero router across the
   hero-to-stack seam into the relay's right-pane router chamber (the stable
   .mzr__router wrapper). Hidden IS the resolved pose here (the clone is a
   JS-only continuity effect; without JS both real routers simply render in
   place), so the CSS default stays hidden and scenes.js only ever toggles
   visibility and transforms x/y/scale.
   z-index: above .page-body (1) and the hero (0), below the nav (120),
   the sticky bar (1200) and the modal scrim (1400). */
#handoff-layer{position:fixed;inset:0;z-index:80;pointer-events:none;visibility:hidden}
#handoff-layer img{position:absolute;left:0;top:0;width:330px;height:auto;
  transform-origin:0 0;will-change:transform;
  filter:drop-shadow(0 26px 40px rgba(0,0,0,.45))}
html.is-ff #handoff-layer{display:none}

/* reduced motion: no marquee/chips transitions; sections are complete as-is */
@media (prefers-reduced-motion: reduce){
  .trust__track{animation:none;width:auto;justify-content:center}
  .trust__row[aria-hidden]{display:none}
  .canvas__chip{transition:none;opacity:1;transform:scale(calc(1 / var(--cz,1)))}
  .wm-bubble__typing i,.wm-bubble__live i{animation:none}
}

/* ════════════════════════════════════════════════════════════════════
   DAY THEME — FULL THEMING: every scene goes light with the room (relay,
   dashboard canvas, worldmap, final CTA included). Only the intentional
   mini-objects stay dark in both themes: .net__cloud, .net__card,
   .rail__card--invert and the .calc2__out receipt — their literals hold.
   Day palette: pure white #ffffff page, ink #101016, deep emerald
   #0f9e6c for accents on white, red untouched, amber fills stay #ffd84d
   while amber TEXT darkens to the #8a6116 family.
   ════════════════════════════════════════════════════════════════════ */
/* client marks are dark artwork — render them natively on light, no invert lift */
html[data-theme="light"] .trust__logo{filter:grayscale(1) opacity(.75)}
/* products: the hardware lineup — the watermark keeps its alpha; white
   devices on a white room get a soft lift + tight edge definition */
html[data-theme="light"] .hw__giant{color:rgba(16,16,22,.055)}
html[data-theme="light"] .hw__dev img{
  filter:drop-shadow(0 12px 18px rgba(16,16,22,.28))
         drop-shadow(0 7px 12px rgba(16,16,22,.22))
         drop-shadow(0 1px 2px rgba(16,16,22,.14))}


/* ── dashboard canvas by day: the night screenshot stays as CONTENT (the
   night-watch story) in a light frame; the room dim washes white ── */
html[data-theme="light"] .canvas__room{
  background:radial-gradient(120% 92% at 50% 44%, rgba(255,255,255,0) 26%, rgba(255,255,255,.96) 82%)}
html[data-theme="light"] .canvas__chip{box-shadow:0 12px 30px -12px rgba(16,16,22,.2)}

/* ── worldmap by day: a warm sky room, one step deeper land, present
   pins; white bubble card; the per-country premium colors (--c) stay ── */
/* warm sky backdrop inside the section (z-index:-1 keeps it under the
   head, stage and cards; .wm has no background of its own) */
html[data-theme="light"] .wm::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:
    radial-gradient(76% 66% at 50% 40%, #f5f1e8 0%, rgba(245,241,232,.6) 56%, rgba(245,241,232,0) 88%),
    linear-gradient(180deg, rgba(245,241,232,0) 0%, rgba(245,241,232,.55) 22%, rgba(245,241,232,.55) 80%, rgba(245,241,232,0) 100%)}
html[data-theme="light"] .wm-land{fill:#e2dfd6;stroke:rgba(18,22,28,.11)}
/* day-only band softening for the shared-geometry artifacts (arctic
   band edge, mid sliver) is an SVG mask whose defs AND rule live in
   index.html: fragment url(#...) references resolve against the sheet
   when written here, so the rule must stay inline with its document.
   coverage.html has no defs and keeps the shipped band. */
html[data-theme="light"] .wm-country{fill:rgba(120,132,146,.16);stroke:rgba(120,132,146,.34)}
/* pin presence: fuller halo, a soft premium-color glow on the dot */
html[data-theme="light"] .wm-pin__halo{opacity:.26}
html[data-theme="light"] .wm-pin__dot{filter:drop-shadow(0 0 7px var(--c,#0f9e6c))}
html[data-theme="light"].is-ff .wm-pin__dot{filter:none}
html[data-theme="light"] .wm-bubble__box{background:rgba(255,255,255,.95);
  border-color:rgba(16,16,22,.1);
  box-shadow:0 2px 6px rgba(18,22,28,.05),0 26px 58px rgba(18,22,28,.18),0 0 44px -20px var(--c,#0f9e6c)}
html[data-theme="light"].is-ff .wm-bubble__box{background:rgba(255,255,255,.97)}
html[data-theme="light"] .wm-bubble__box::before{opacity:.08}
html[data-theme="light"] .wm-bubble__flag{background:rgba(16,16,22,.05);
  box-shadow:inset 0 0 0 1px rgba(16,16,22,.06)}
html[data-theme="light"] .wm-bubble__tail{border-top-color:rgba(255,255,255,.95);
  filter:drop-shadow(0 7px 5px rgba(18,22,28,.08))}

/* ── final CTA by day: the city dots go ink (tiers ride the existing
   per-path opacities), the accent dots deep emerald ── */
html[data-theme="light"] .final__lights{opacity:.45}
html[data-theme="light"] .final__lights svg g{fill:rgba(16,16,22,.5)}
html[data-theme="light"] .final__lights svg > path{fill:#0f9e6c}

/* ── wifi-worth by day: the section ground is the neutral #f5f6f8 whisper
   band, so the channel card lifts to white to stay separate from it. The
   PHONE stays dark in both themes on purpose — it is a real device screen,
   the same "instrument surface" convention as .net__cloud/.net__card — so it
   only needs a shadow that reads against white. ── */
html[data-theme="light"] .worth__channel{background:#fff;box-shadow:0 14px 40px -22px rgba(16,16,22,.4)}
html[data-theme="light"] .worth__inputs{box-shadow:0 14px 40px -22px rgba(16,16,22,.4)}
html[data-theme="light"] .worth__paid{border-color:rgba(15,158,108,.42)}
html[data-theme="light"] .worth__phone{
  box-shadow:0 30px 58px rgba(16,16,22,.24),0 0 0 1px rgba(16,16,22,.14)}

/* ── router handoff clone: lighter flight shadow over a white room ── */
html[data-theme="light"] #handoff-layer img{filter:drop-shadow(0 26px 40px rgba(16,16,22,.3))}

/* ═══════════════════ §STACK — the deployment maze (#maze) ═══════════════════
   Arcade board ported from the DC export; markup keeps the export's inline
   styles, this block carries what inline can't: the font, keyframes,
   hover/active states, the mobile collapse, and the standing rules
   (no-js, reduced motion). The panel stays dark in BOTH themes on purpose —
   it reads as an arcade cabinet, not a page surface. */
@font-face{font-family:"Press Start 2P";font-style:normal;font-weight:400;font-display:swap;
  src:url("/fonts/press-start-2p/PressStart2P-subset.woff2") format("woff2");
  unicode-range:U+20-21,U+24,U+27-29,U+2B-2E,U+30-39,U+41-5A,U+73,U+B7,U+2013-2014}
@keyframes mzBlink{0%,100%{opacity:1}50%{opacity:.2}}
@keyframes mzShakeX{0%,100%{transform:translateX(0)}20%{transform:translateX(-3px)}40%{transform:translateX(3px)}60%{transform:translateX(-2px)}80%{transform:translateX(2px)}}
@keyframes mzChipFloat{from{opacity:0;transform:translateY(9px)}to{opacity:1;transform:translateY(0)}}
@keyframes mzRingBurst{from{r:6px;opacity:.95}to{r:38px;opacity:0}}
@keyframes mzLiveRise{0%{opacity:0;transform:translateY(46px) scale(.35)}35%{opacity:1}100%{opacity:1;transform:translateY(0) scale(1)}}
@keyframes mzEyeBlink{0%,93%,100%{transform:scaleY(1)}96%{transform:scaleY(.12)}}
@keyframes mzVsGlow{0%,100%{box-shadow:0 10px 30px rgba(0,0,0,.6)}50%{box-shadow:0 0 38px 10px rgba(52,211,153,.65)}}
@keyframes mzPulseBtn{0%,100%{transform:translateY(0)}50%{transform:translateY(-3px)}}
@keyframes mzPopCard{from{opacity:0;transform:scale(.92)}to{opacity:1;transform:scale(1)}}
#maze .mz-leg{display:flex;align-items:center;gap:7px;padding:7px 11px;border:1.5px solid #39447f;
  border-radius:6px;background:rgba(13,17,42,.7);cursor:pointer;font:800 10px/1 inherit;letter-spacing:1px;color:#cdd5f6;
  min-height:44px}
/* the legend doubles as the tally: maze.js lights each button in its ghost's
   colour (--mz-hit) the instant the crawl reaches that blocker, and it stays
   lit for the rest of the run. border-color needs !important because every
   button carries an inline border-color — the maze panel is inline-styled
   markup, same reason as the eyebrow rule below. The one-shot pop is covered
   by the blanket #maze * reduced-motion rule at the foot of this file. */
#maze .mz-leg.is-hit{border-color:var(--mz-hit)!important;color:#fff;
  box-shadow:0 0 0 1px var(--mz-hit),0 0 14px -2px var(--mz-hit);
  animation:mzLegHit .55s ease-out}
@keyframes mzLegHit{0%{transform:translateY(0) scale(1)}35%{transform:translateY(-3px) scale(1.06)}100%{transform:translateY(0) scale(1)}}
#maze .mz-cta:hover{background:#FBBF24}
#maze .mz-cta:active{transform:translateY(3px);box-shadow:0 2px 0 #92610a !important}
/* the arcade eyebrow: keep it to one line on phones. !important because the
   eyebrow's base styles are inline (the maze panel is inline-styled markup) */
@media (max-width:520px){
  #maze .mz-eyebrow{font-size:9px !important;letter-spacing:1px !important;gap:7px !important}
}
/* celebration settles: three bobs / three glow pulses, then rest (was infinite —
   two perpetual loops kept tugging the eye long after the section resolved) */
#maze .mz-cta.is-done{animation:mzPulseBtn 1.5s ease-in-out 3}
#maze .mz-replay:hover{color:#eef1ff;background:rgba(75,97,255,.14)}
#maze .mz-replay:active{transform:translateY(1px)}
#maze .mz-skip:hover{color:#34D399;border-bottom-color:#34D399}
#maze #mz-vs-badge.is-live{animation:mzVsGlow 1.1s ease-in-out 3;border-color:#34D399;color:#34D399}
@media (max-width:767px){
  #maze .mz-row{flex-direction:column !important}
  #maze .mz-right{order:2 !important}
}
/* the boards the maze rides to (maze.js rideTo): on the native-scroll path
   block:'start' must clear the fixed nav pill; 96 matches page.js and the
   showcase/worth anchors above */
#maze #mz-right,#maze #mz-lwrap{scroll-margin-top:96px}
/* board headers ("THE OLD WAY · WK 12 · OUCH", "WITH HALO · HRS 48 · LIVE"):
   the two ends of the flex line had no gap, so at 360px the pixel font's
   label and counter touched (Kumar, 2026-09-08). A guaranteed gap, wrapping
   allowed as the last resort, and one size down under 400px so both still
   share the line. !important against the inline font-size. */
#maze .mz-head{gap:12px;flex-wrap:wrap}
@media (max-width:400px){#maze .mz-head{font-size:9px !important}}
@media (max-width:767px){
  #maze .mz-vs{position:static !important;left:auto !important;top:auto !important;transform:none !important;order:1;display:flex !important;align-items:center;gap:14px;width:100% !important}
  #maze .mz-vs::before,#maze .mz-vs::after{content:'';flex:1;height:2px;background:#232c66}
}
.no-js #maze .mz-hint,.no-js #maze .mz-replay{display:none}
/* 44px touch targets. !important because the maze panel's controls carry inline
   styles (same reason as the eyebrow rule above). */
#maze .mz-replay{min-height:44px !important}
#maze .mz-skip{display:inline-block !important;padding-top:12px !important;padding-bottom:12px !important}
/* screen-reader-only: the maze's narrative summary + blocker definitions
   (the SVG boards and hover card are aria-hidden; this is the AT surface) */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
@media (prefers-reduced-motion: reduce){ #maze *{animation:none !important} }

/* ── worldwide (wv): the second map became words — the field log, in text.
   Static section: no scene, nothing to animate, nothing to flake. ── */
.wv__cols{display:grid;grid-template-columns:1.05fr .95fr;gap:56px;align-items:start}
.wv__prose p{margin:0 0 18px;font-size:15.5px;line-height:1.75;color:var(--pg-mute)}
.wv__prose p strong{color:var(--pg-ink-soft);font-weight:600}
.wv__facts{margin:0;padding:0;list-style:none;border-top:1px solid rgba(238,242,246,.08)}
.wv__facts li{display:grid;grid-template-columns:minmax(150px,38%) 1fr;gap:18px;
  padding:16px 2px;border-bottom:1px solid rgba(238,242,246,.08)}
.wv__cond{font:600 10.5px/1.6 var(--bs-mono);letter-spacing:.14em;text-transform:uppercase;color:var(--pg-faint)}
.wv__answer{margin:0;font-size:14.5px;line-height:1.6;color:var(--pg-ink-soft)}
.wv__foot{margin:40px 0 0;font-size:15px;line-height:1.75;color:var(--pg-mute);max-width:72ch}
.wv__foot a,.wv__prose a{color:var(--pg-ink-soft);text-underline-offset:3px}
html[data-theme="light"] .wv__facts,html[data-theme="light"] .wv__facts li{border-color:rgba(16,16,22,.10)}
@media (max-width:960px){.wv__cols{grid-template-columns:1fr;gap:34px}}
