/* Shared static marketing layout foundation — THE UI LIBRARY.
   Before styling anything page-local, check this index. New repeated
   patterns get promoted here, not re-rolled per page.

   COMPONENT INDEX
   Layout:    .m-section (--hero/--dark/--cream) · .m-container ·
              .m-split · .m-grid (--2/--3/--4) · .m-card
   Type:      .m-kicker · .m-heading · .m-copy
   Bands:     .m-why (kicker + heading + one line, above a stage) ·
              .m-heard (pain → relief cards, below a stage) ·
              .m-hero-grid (THE header grid — first child of a
              platform hero; parent needs position+overflow hidden)
   Pills:     .m-pill · .m-pill--live · .m-pill--soon
   Accordion: .m-acc-item (details) — smooth height + plus→cross morph
              via partials.js jvSetDetailsOpen; [data-exclusive] on the
              container closes siblings
   People:    .jv-avatar
   Phone:     .jv-phone (+ -screen/-notch/-lip, .ph-chrome/.ph-glyphs/
              .ph-rail/.ph-cap) — THE device mockup, container-unit
              scaled; never re-roll a page-local phone
   Scribble:  .jv-scribble (+ .jv-scribble-words)
   Signup:    .jv-signup (+ -form/-meta)
   Motion JS (partials.js): jvOnceInView(el, cb) · jvReducedMotion() ·
              jvSetDetailsOpen(details, open)

   Site themes must define the tokens used here: --rail, --max, --bg-1,
   --hair, --ink, --d-bg, --d-ink, --cream, --serif, --mono, --accent,
   --d-accent.

   Breakpoint policy:
   - 960px: stack dense tablet layouts.
   - 767px: nav and standard mobile boundary.
   - 640px: phone type/density only.
   - 480/380px: component-specific tightening only.
*/

.m-section {
  padding: clamp(64px, 9vh, 110px) var(--rail);
}
.m-section--hero {
  padding: clamp(80px, 12vh, 140px) var(--rail) clamp(40px, 6vh, 72px);
}
.m-section--dark {
  background: var(--d-bg);
  color: var(--d-ink);
}
.m-container {
  max-width: var(--max);
  margin: 0 auto;
}
.m-grid {
  display: grid;
  gap: var(--grid-gap, 16px);
}
.m-grid--2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.m-grid--3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.m-grid--4 {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.m-card {
  background: var(--bg-1);
  border: 1px solid var(--hair);
  border-radius: 10px;
  padding: 24px;
}
.m-kicker {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.m-heading {
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(32px, 4vw, 56px);
  line-height: 1.02;
  letter-spacing: 0;
}
.m-copy {
  font-size: 15px;
  line-height: 1.6;
  max-width: 56ch;
}
/* ── Hero grid band — THE component (Ed 2026-07-18) ──────────────────
   One grid, every platform header, identical by construction. Fixed
   PIXEL geometry cloned from the approved creative-testing render, so
   it cannot vary with hero height, viewport tricks or page CSS: lines
   strongest behind the title, gone by ~370px down, fading at the far
   edges. Put it as the FIRST CHILD of the hero section; the section
   (position:relative from site.css + overflow:hidden) crops it.
   You should only see it when you look for it. */
.m-hero-grid {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 640px;
  pointer-events: none;
  background-image:
    linear-gradient(to right, var(--d-hair, rgba(255, 255, 255, 0.07)) 1px, transparent 1px),
    linear-gradient(to bottom, var(--d-hair, rgba(255, 255, 255, 0.07)) 1px, transparent 1px);
  background-size: var(--grid-cell, 56px) var(--grid-cell, 56px);
  -webkit-mask-image: radial-gradient(ellipse 1150px 260px at 50% 150px, #000 40%, transparent 100%);
  mask-image: radial-gradient(ellipse 1150px 260px at 50% 150px, #000 40%, transparent 100%);
  opacity: 0.4;
}

/* ── Platform-page bands ──
   .m-why: why-this-exists — one kicker, one serif line, one short
   paragraph between the hero and the stage.
   .m-heard: what-you-told-us — three pain → relief cards straight
   after the stage. Both compose the primitives above. */
.m-why .m-kicker,
.m-why .m-heading em {
  color: var(--d-accent, var(--accent));
}
.m-why .m-heading {
  margin: 14px 0 16px;
}
.m-why .m-heading em {
  font-style: normal;
}
.m-heard .m-grid {
  margin-top: 28px;
}
.m-heard-pain {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(16px, 1.6vw, 19px);
  line-height: 1.3;
  margin: 0 0 8px;
}
.m-heard-fix {
  font-size: 14px;
  line-height: 1.55;
  opacity: 0.72;
  margin: 0;
}
@media (max-width: 960px) {
  .m-grid--4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .m-grid--3 {
    grid-template-columns: 1fr;
  }
}
@media (max-width: 640px) {
  .m-section {
    padding: clamp(48px, 8vh, 72px) var(--rail);
  }
  .m-grid--2,
  .m-grid--4 {
    grid-template-columns: 1fr;
  }
  .m-heading {
    font-size: clamp(28px, 7.2vw, 36px);
    line-height: 1.12;
  }
  .m-copy {
    font-size: clamp(14px, 3.7vw, 16px);
  }
}


/* ═══ Marketing UI components — the shared library ═══════════════════
   One class per repeated pattern, ported 1:1 from the platform's
   primitives so both surfaces stay visually identical. Custom-coded
   one-offs on pages should migrate here as they recur.

   .jv-avatar — the platform's HaloAvatar (packages/ui/primitives/
   halo-avatar.tsx, default ring): 2px accent ring at 30%, offset 2px
   from the image by the surface colour. Set --jv-halo-offset on dark
   surfaces so the gap matches the background. */
/* Avatars ship AVIF with the PNG as fallback, so each <img> sits in a
   <picture>. `display: contents` keeps the wrapper out of the layout — the
   <img> stays the direct flex/grid child, so the inline `flex: none` several
   of them carry still applies. 50KB -> 10KB across 14 pages. */
.jv-avatar-pic {
  display: contents;
}
.jv-avatar {
  border-radius: 50%;
  object-fit: cover;
  box-shadow:
    0 0 0 2px var(--jv-halo-offset, #ffffff),
    0 0 0 4px rgba(0, 191, 255, 0.3);
}
.on-dark .jv-avatar,
.slab-dark .jv-avatar,
[class*="dark"] .jv-avatar {
  --jv-halo-offset: #101114;
}

/* .jv-scribble — the hand-drawn nudge (words write on, arrow draws) used
   for "look here" moments. Add .is-on (IntersectionObserver) to play.
   Needs the Caveat font loaded by the page. */
.jv-scribble{ position: absolute; color: var(--accent-ink, #0a5bcc); pointer-events: none; z-index: 5; }
.jv-scribble-words{
  display: inline-block; font-family: 'Caveat', cursive; font-size: 22px;
  font-weight: 600; white-space: nowrap; clip-path: inset(0 100% 0 0);
}
.jv-scribble svg{ width: 60px; height: 46px; display: block; }
.jv-scribble path{ stroke-dasharray: 190; stroke-dashoffset: 190; }
.jv-scribble.is-on .jv-scribble-words{ animation: jvWrite 1s steps(20) forwards; }
.jv-scribble.is-on path{ animation: jvDraw 0.7s ease 1s forwards; }
@keyframes jvWrite{ to{ clip-path: inset(-6px -10px -8px 0); } }
@keyframes jvDraw{ to{ stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: reduce){
  .jv-scribble-words{ clip-path: none; }
  .jv-scribble path{ stroke-dashoffset: 0; }
  .jv-scribble.is-on .jv-scribble-words, .jv-scribble.is-on path{ animation: none; }
}
@media (max-width: 900px){
  /* Mobile placements: below their anchors instead of beside them. */
  .jv-scribble{ position: static; display: flex !important; justify-content: center; align-items: center; gap: 6px; margin-top: 10px; transform: none; }
  .jv-scribble svg{ width: 40px; height: 32px; }
}

/* ── jv-signup-meta ─ the reassurance row under a footer signup form ────────
   Usage: place directly after the email form inside a dark closer band.
   Ticks inherit the accent; the demo link opens the canonical Calendly
   dialog via the /?contact=sales interceptor in partials.js.             */
.jv-signup-meta {
  display: flex;
  width: 100%;
  gap: 16px;
  flex-wrap: wrap;
  justify-content: center;
  margin: 16px 0 0;
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--d-ink-mid, rgba(255, 255, 255, 0.55));
}
.jv-signup-meta > span {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.jv-signup-meta svg {
  stroke: var(--d-accent, #00bfff);
  flex: none;
}
.jv-signup-meta a {
  color: var(--d-ink-soft, rgba(255, 255, 255, 0.78));
  text-decoration: none;
}
.jv-signup-meta a:hover {
  color: #fff;
}

/* ── jv-signup ─ THE footer signup unit: email pill + Start for free +
   reassurance row, centred as one block. One component, every footer.   */
.jv-signup {
  width: 100%;
  max-width: 440px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}
.jv-signup-form {
  display: flex;
  gap: 6px;
  padding: 6px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--d-hair-3, rgba(255, 255, 255, 0.12));
  border-radius: 999px;
}
.jv-signup-form input {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: 0;
  outline: 0;
  color: var(--d-ink, #fff);
  font-family: var(--sans, inherit);
  font-size: 14px;
  padding: 10px 18px;
}
.jv-signup-form input::placeholder {
  color: rgba(255, 255, 255, 0.4);
}
.jv-signup-form button {
  background: var(--d-ink, #fff);
  color: var(--d-bg, #0f1011);
  border: 0;
  padding: 10px 22px;
  border-radius: 999px;
  font-family: var(--sans, inherit);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  flex: none;
  cursor: pointer;
}
.jv-signup .jv-signup-meta {
  margin: 14px 0 0;
}

/* ── Pills (.m-pill) ─────────────────────────────────────────────────
   The mono uppercase pill used for status tags: coming-soon markers,
   live indicators, category chips. One definition, themed by context
   (inherits currentColor at 55% via the default colours below; set
   color on a modifier or parent for variants). */
.m-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 8.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--pill-ink, rgba(128, 131, 138, 0.9));
  border: 1px solid var(--pill-hair, rgba(128, 131, 138, 0.35));
  border-radius: 999px;
  padding: 2px 8px;
  white-space: nowrap;
}
.m-pill--soon {
  --pill-ink: var(--d-ink-dim, rgba(128, 131, 138, 0.9));
  --pill-hair: var(--d-hair-2, rgba(128, 131, 138, 0.3));
}

/* ── Accordion (.m-acc-item) ─────────────────────────────────────────
   <details class="m-acc-item"><summary>…</summary>…</details>
   Smooth height animation + plus→cross icon morph come from
   partials.js (jvSetDetailsOpen; the delegated click handler in
   00-motion). Put data-exclusive on the wrapping element to close
   siblings when one opens. Colours inherit; the icon keeps a quiet
   grey in both states by design (Ed 2026-07-11). */
.m-acc-item {
  border-bottom: 1px solid var(--acc-hair, var(--hair, rgba(128, 131, 138, 0.25)));
}
.m-acc-item summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 10px;
}
.m-acc-item summary::-webkit-details-marker {
  display: none;
}
.m-acc-item summary::after {
  content: '';
  margin-left: auto;
  flex: none;
  width: 11px;
  height: 11px;
  color: var(--acc-icon, rgba(128, 131, 138, 0.8));
  background:
    linear-gradient(currentColor, currentColor) center / 11px 1.5px no-repeat,
    linear-gradient(currentColor, currentColor) center / 1.5px 11px no-repeat;
  transition: transform 420ms cubic-bezier(0.65, 0, 0.35, 1);
}
.m-acc-item.is-open summary::after {
  transform: rotate(45deg);
}
.m-acc-item.acc-anim {
  overflow: hidden;
}
@media (prefers-reduced-motion: reduce) {
  .m-acc-item summary::after {
    transition: none;
  }
}


/* ══ STAGE SYSTEM — the shared scroll-scrubbed stage ══════════════
   Single source of truth for every signature animation (Ed 2026-07-16).
   Pace comes from partials.js jvStageBeats (JV_BEAT_VH per beat);
   look comes from here. A page provides: a .jv-stage section with
   data-ph, a .jv-scene (height set by jvStageBeats), a .jv-stick,
   .jv-beat cards with data-beat="1..N", and .jv-cap captions with
   data-cap="1..N". Exactly one beat on stage; its predecessor recedes. */
.jv-stage { position: relative; background: var(--d-bg); overflow: clip; }
.jv-scene { position: relative; }
.jv-stick {
  position: sticky; top: 0; min-height: 100vh;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 28px; padding: 0 var(--rail);
}
.jv-beats { position: relative; width: min(560px, calc(100vw - 40px)); height: 400px; }
/* Beats travel LEFT→RIGHT like a timeline (Ed 2026-07-16: cards
   zooming at the viewer felt sick-making — no scale, no launch). */
.jv-beat {
  position: absolute; left: 50%; top: 50%;
  width: min(400px, calc(100vw - 56px));
  transform: translate(-50%, -50%) translateX(48px);
  background: #101215; border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 18px; padding: 18px;
  opacity: 0; pointer-events: none;
  transition: opacity 0.6s, transform 0.8s cubic-bezier(0.22, 0.8, 0.24, 1);
}
[data-ph="1"] .jv-beat[data-beat="1"],
[data-ph="2"] .jv-beat[data-beat="2"],
[data-ph="3"] .jv-beat[data-beat="3"],
[data-ph="4"] .jv-beat[data-beat="4"],
[data-ph="5"] .jv-beat[data-beat="5"],
[data-ph="6"] .jv-beat[data-beat="6"],
[data-ph="7"] .jv-beat[data-beat="7"],
[data-ph="8"] .jv-beat[data-beat="8"],
[data-ph="9"] .jv-beat[data-beat="9"],
[data-ph="10"] .jv-beat[data-beat="10"] {
  opacity: 1; transform: translate(-50%, -50%); transition-delay: 0.3s;
}
[data-ph="2"] .jv-beat[data-beat="1"],
[data-ph="3"] .jv-beat[data-beat="2"],
[data-ph="4"] .jv-beat[data-beat="3"],
[data-ph="5"] .jv-beat[data-beat="4"],
[data-ph="6"] .jv-beat[data-beat="5"],
[data-ph="7"] .jv-beat[data-beat="6"],
[data-ph="8"] .jv-beat[data-beat="7"],
[data-ph="9"] .jv-beat[data-beat="8"],
[data-ph="10"] .jv-beat[data-beat="9"] {
  opacity: 0.12; transform: translate(-50%, -50%) translateX(-44px) scale(0.97); transition-delay: 0s;
}
.jv-caps { position: relative; height: 24px; width: min(560px, calc(100vw - 40px)); }
.jv-cap {
  position: absolute; inset: 0; margin: 0; text-align: center;
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.12em;
  text-transform: uppercase; color: rgba(255, 255, 255, 0.6);
  opacity: 0; transform: translateY(6px);
  transition: opacity 0.45s, transform 0.5s;
}
[data-ph="1"] .jv-cap[data-cap="1"],
[data-ph="2"] .jv-cap[data-cap="2"],
[data-ph="3"] .jv-cap[data-cap="3"],
[data-ph="4"] .jv-cap[data-cap="4"],
[data-ph="5"] .jv-cap[data-cap="5"],
[data-ph="6"] .jv-cap[data-cap="6"],
[data-ph="7"] .jv-cap[data-cap="7"],
[data-ph="8"] .jv-cap[data-cap="8"],
[data-ph="9"] .jv-cap[data-cap="9"],
[data-ph="10"] .jv-cap[data-cap="10"] { opacity: 1; transform: none; }
@media (max-width: 640px) {
  .jv-beats { height: 340px; }
}
@media (prefers-reduced-motion: reduce) {
  .jv-beat, .jv-cap { transition: none; }
}

/* ── Scroll cue — soft chevrons + "Scroll" while beats remain ── */
.jv-scroll-cue {
  position: absolute;
  left: 50%;
  bottom: 26px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  color: rgba(255, 255, 255, 0.38);
  pointer-events: none;
  transition: opacity 0.5s;
}
.jv-scroll-cue-word {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}
.jv-scroll-cue svg {
  width: 14px;
  height: 17px;
  animation: jvCueBob 2.4s ease-in-out infinite;
}
/* The stage controls — top-right cluster while a story plays: step
   arrows (walk one beat back or forward; the story carries on playing)
   and the SKIP pill. Subtle until needed; ignored scroll attempts
   nudge the pill so it teaches itself. */
.jv-ctl {
  position: absolute;
  /* below the fixed nav band */
  top: 74px;
  right: 26px;
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 8px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease;
}
.jv-ctl.is-on {
  opacity: 1;
  pointer-events: auto;
}
/* a told story stays explorable: the arrows survive, skip retires
   (nothing left to skip) — ◀ steps back in and the story plays on.
   visibility (not display) so the cluster keeps its shape and the
   arrows never jump position under the pointer. */
.jv-ctl.is-done .jv-skip {
  visibility: hidden;
}
.jv-skip {
  position: relative;
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 999px;
  padding: 7px 16px;
  cursor: pointer;
  transition: color 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}
/* the step arrows — same quiet recipe as the pill, circular */
.jv-step {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  color: rgba(255, 255, 255, 0.55);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 50%;
  cursor: pointer;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.jv-step svg {
  width: 12px;
  height: 12px;
}
.jv-step:hover,
.jv-step:focus-visible {
  color: rgba(255, 255, 255, 0.92);
  border-color: rgba(255, 255, 255, 0.45);
}
/* the blue dot rides the pill's top-right curvature — same recipe as
   the pricing annual badge */
.jv-skip-dot {
  position: absolute;
  top: -1px;
  right: -1px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent, #00bfff);
}
.jv-skip:hover,
.jv-skip:focus-visible {
  color: rgba(255, 255, 255, 0.92);
  border-color: rgba(255, 255, 255, 0.45);
}
/* transform-only: GPU-composited, identical feel on mobile + desktop */
@keyframes jvSkipNudge {
  0% { transform: scale(1); }
  40% { transform: scale(1.22); }
  100% { transform: scale(1); }
}
.jv-skip.is-nudged {
  animation: jvSkipNudge 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
  color: rgba(255, 255, 255, 0.92);
  border-color: rgba(255, 255, 255, 0.45);
}
@media (max-width: 640px) {
  .jv-ctl {
    top: 66px;
    right: 16px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .jv-ctl {
    display: none;
  }
}

/* First visit: while the cookie banner is up it owns the bottom of the
   viewport — the cue yields until the visitor chooses. */
body:has(.cookie-banner-open) .jv-scroll-cue {
  opacity: 0;
}
.jv-scroll-cue.is-hidden {
  opacity: 0;
}
@keyframes jvCueBob {
  0%, 100% { transform: translateY(0); opacity: 0.65; }
  50% { transform: translateY(4px); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .jv-scroll-cue svg { animation: none; }
}

/* ── Exit ramp — the stage eases away as the pin releases ──
   --jv-exit runs 0→1 across the tail scroll AFTER the final beat, so
   leaving a stage is a gentle lift-and-fade, never a hard unpin. */
.jv-exit-target {
  transform: translateY(calc(var(--jv-exit, 0) * -6vh));
  opacity: calc(1 - var(--jv-exit, 0) * 0.85);
}
@media (prefers-reduced-motion: reduce) {
  .jv-exit-target { transform: none; opacity: 1; }
}

/* ── THE PHONE — the estate's single device mockup ──────────────────
   One iPhone for every page: bezel plate (::before), screen, island
   notch, status chrome with a live-clock slot, engagement rail,
   avatar caption, home-indicator lip. Every internal measurement is
   in container units (basis: the 168px measurement phone), so the
   identical component serves a 130px stack phone and a 340px hero
   phone with the same proportions.
   Markup:
     <div class="jv-phone">
       <div class="jv-phone-screen">
         <video|img …>
         <span class="jv-phone-notch" aria-hidden="true"></span>
         <span class="ph-chrome" aria-hidden="true"><b>9:41</b>
           <span class="ph-glyphs">signal · wifi · battery svgs</span></span>
         <span class="ph-rail" aria-hidden="true">heart/comment/share</span>
         <span class="ph-cap" aria-hidden="true"><img class="jv-avatar">@handle</span>
         <span class="jv-phone-lip" aria-hidden="true"></span>
       </div>
     </div>
   Pages set only width/position on .jv-phone, and may re-seat
   .ph-rail/.ph-cap when something (e.g. a survey) owns the screen's
   foot. Never re-roll a page-local device. */
.jv-phone {
  position: relative;
  aspect-ratio: 9 / 19.5;
  container-type: inline-size;
}
.jv-phone::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 15.5cqw;
  background: linear-gradient(180deg, #17181b, #0a0a0c);
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.12),
    0 15cqw 25cqw -7cqw rgba(0,0,0,0.75),
    0 26cqw 75cqw -14cqw rgba(0,191,255,0.2),
    inset 0 1px 0 rgba(255,255,255,0.08);
}
.jv-phone-screen {
  position: absolute;
  inset: 3cqw 2.4cqw 4.6cqw;
  border-radius: 12.5cqw;
  overflow: hidden;
  background: #0b0d10;
}
.jv-phone-screen video,
.jv-phone-screen > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.jv-phone-notch {
  position: absolute;
  top: 4.2cqw;
  left: 50%;
  transform: translateX(-50%);
  width: 27cqw;
  height: 6.4cqw;
  border-radius: 999px;
  background: #050608;
  z-index: 3;
}
.jv-phone-lip {
  position: absolute;
  bottom: 2.2cqw;
  left: 50%;
  transform: translateX(-50%);
  width: 37cqw;
  height: max(2.5px, 1.5cqw);
  border-radius: 999px;
  background: rgba(255,255,255,0.5);
  z-index: 3;
}
.ph-chrome {
  position: absolute;
  top: 4.2cqw;
  left: 8cqw;
  right: 7cqw;
  height: 6.4cqw;
  z-index: 3;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: var(--mono);
  font-size: max(8px, 5.8cqw);
  font-weight: 600;
  color: rgba(255,255,255,0.92);
  text-shadow: 0 1px 3px rgba(0,0,0,0.6);
}
.ph-glyphs {
  display: inline-flex;
  align-items: center;
  gap: 2.2cqw;
}
.ph-glyphs svg,
.ph-chrome > svg {
  width: 7.8cqw;
  height: 5.6cqw;
  display: block;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.6));
}
.ph-glyphs svg:last-child { width: 9cqw; }
.ph-rail {
  position: absolute;
  right: 5.6cqw;
  bottom: 42cqw;
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: 7.6cqw;
  align-items: center;
  color: #fff;
}
.ph-rail > span {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1cqw;
}
.ph-rail svg {
  width: 13cqw;
  height: 13cqw;
  filter: drop-shadow(0 2px 5px rgba(0,0,0,0.55));
}
.ph-rail b {
  font-family: var(--mono);
  font-size: max(6px, 4.8cqw);
  font-weight: 600;
  text-shadow: 0 1px 3px rgba(0,0,0,0.7);
}
.ph-cap {
  position: absolute;
  left: 7cqw;
  right: 26cqw;
  bottom: 12cqw;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 4cqw;
  font-family: var(--sans);
  font-size: max(8px, 6.4cqw);
  font-weight: 700;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0,0,0,0.7);
  white-space: nowrap;
  overflow: hidden;
}
.ph-cap .jv-avatar {
  width: 13cqw;
  height: 13cqw;
  flex: none;
  --jv-halo-offset: #0e1319;
}
