/* ════════════════════════════════════════════════════════════════════
   VYOBHA — MOBILE OPTIMIZATION LAYER
   ────────────────────────────────────────────────────────────────────
   Loaded after the Next.js chunks so its rules win cascade ties.
   Inline styles still need !important to override.

   Strategy:
   · Phones (≤ 600px) get a complete reflow.
   · Wide phones / small tablets (601–880px) get a softer reflow.
   · Pinned scroll-jack heights get capped so mobile scroll feels
     responsive instead of "stuck."
   · Tiny mono labels get a marquee fallback when they would clip.
   · Forms hit ≥16px to suppress iOS focus zoom.
   ════════════════════════════════════════════════════════════════════ */

/* Universal hard guard — never let any descendant overflow horizontally.
   Several inline-styled sections use 100vw or absolute positioning that
   can poke past the viewport on phones. */
@media (max-width: 880px) {
  /* `clip` (not `hidden`) — `overflow: hidden` on html/body breaks
     `position: sticky` on descendants in iOS Safari, which kills the
     scroll-pinned hero animations. `clip` prevents horizontal overflow
     without establishing a scroll container. */
  html, body { overflow-x: clip !important; }
  body { max-width: 100vw; }

  /* Belt-and-braces guard for the "one swipe scrolls the whole page" bug
     reported on some Android browsers. The real fix is in JS: Lenis is
     now skipped on touch devices (see SmoothScroll). But just in case a
     stale chunk still loads, contain the momentum chain so a single fling
     can't traverse through more than one pinned section at a time, and
     ensure native vertical pan is what the OS interprets. */
  html, body {
    overscroll-behavior-y: contain;
    -webkit-overflow-scrolling: touch;
  }
  body { touch-action: pan-y; }

  /* Standardize horizontal section padding across phone widths.
     The desktop sheet defines --viewport-gutter as
     clamp(1.25rem, 3vw, 2.5rem) — at 320–600px that pins to a flat
     20px because 3vw stays under the 1.25rem floor. We swap to
     clamp(18px, 5vw, 32px) so:
     · 320px viewport  → 18px (slightly tighter, was 20px)
     · 360px viewport  → 18px → 18px (5vw=18px hits the floor)
     · 414px viewport  → 20.7px
     · 480px viewport  → 24px
     · 600px+ viewport → 30px (was still 20px on the old curve)
     This keeps the gutter visibly responsive across the full phone
     range instead of a flat 20px wall, and every section that uses
     var(--viewport-gutter) inherits the same scale. */
  :root {
    --viewport-gutter: clamp(18px, 5vw, 32px) !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   HEADER (every page)
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 600px) {
  header.fixed > div > .grid {
    padding: 10px var(--viewport-gutter) !important;
    min-height: 56px !important;
    gap: 8px !important;
  }
  /* Tighten the brand wordmark so MENU + VYOBHA fit on a 320px viewport */
  header.fixed a[aria-label="Vyobha home"] span.font-mono {
    font-size: 12px !important;
    letter-spacing: 0.26em !important;
  }
  header.fixed a[aria-label="Vyobha home"] svg {
    width: 22px !important;
    height: 22px !important;
  }
  header.fixed button[aria-label="Open menu"] span.font-mono {
    font-size: 11px !important;
    letter-spacing: 0.24em !important;
  }
  header.fixed button[aria-label="Open menu"] span.relative.block {
    width: 24px !important;
    height: 14px !important;
  }
  header.fixed button[aria-label="Open menu"] span.relative.block > span {
    width: 24px !important;
  }
}
@media (max-width: 380px) {
  /* On tiny phones, hide the MENU label leaving just the icon */
  header.fixed button[aria-label="Open menu"] span.font-mono {
    display: none !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   HOME — HERO ("The ground is a suggestion.")
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 880px) {
  /* Cap the 250vh hero pin — desktop's slow zoom-into-frame becomes
     dead empty scrolling on a phone. */
  section#hero {
    height: clamp(160vh, 180vh, 200vh) !important;
  }
}
@media (max-width: 600px) {
  section#hero { height: 150vh !important; }
  section#hero h1 {
    font-size: clamp(2.6rem, 12vw, 4.2rem) !important;
    max-width: 100% !important;
    line-height: 0.95 !important;
  }
  section#hero .font-body,
  section#hero div[style*="max-width:480px"] {
    font-size: 0.95rem !important;
    line-height: 1.5 !important;
    max-width: 100% !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   HOME — "The future has arrived." (centered nowrap line)
   The desktop layout uses white-space:nowrap with clamp(...8.5rem). On
   a 360px viewport that overflows the screen. We let it wrap and keep
   the per-word stagger animation intact.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 880px) {
  /* Target the centered headline section by structure: it has a single
     h2 with white-space:nowrap among its inline styles. */
  main > section[style*="min-height:34vh"] h2[style*="white-space:nowrap"] {
    white-space: normal !important;
    font-size: clamp(2.2rem, 12vw, 5rem) !important;
    line-height: 1.05 !important;
  }
  main > section[style*="min-height:34vh"] h2 > span {
    margin-right: 0.22em !important;
  }
  main > section[style*="min-height:34vh"] {
    min-height: 28vh !important;
    padding: 8vh 0 !important;
  }
  main > section[style*="min-height:34vh"] .font-mono {
    font-size: 10px !important;
    letter-spacing: 0.28em !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   HOME — CINEMATIC FRAMES (.cf-section, 500vh sticky desktop)
   The desktop pins the section and animates 4 frames in/out via
   clip-path keyed to scroll progress. On phones, that scroll-driven
   activation is unreliable (frames 2 and 3 stay clipped) and the
   500vh pin makes scrolling feel "stuck." On mobile we drop the
   scroll-jack entirely: every frame becomes a normal stacked block
   with its image above the text, the tab strip is hidden, and the
   section scrolls naturally like the rest of the page.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 880px) {
  .cf-section {
    height: auto !important;
    min-height: 0 !important;
  }
  .cf-sticky {
    position: relative !important;
    height: auto !important;
    top: auto !important;
    overflow: visible !important;
    display: flex !important;
    flex-direction: column !important;
    /* Generous gap between frames so body text + specs of one frame
       have a clear visual end before the next frame's image begins. */
    gap: clamp(64px, 10vh, 112px) !important;
    padding: clamp(40px, 6vh, 80px) var(--viewport-gutter) clamp(56px, 8vh, 96px) !important;
    width: 100% !important;
    max-width: 100% !important;
    box-sizing: border-box !important;
  }
  /* Each frame becomes a normally-flowing block */
  .cf-frame,
  .cf-frame--idle,
  .cf-frame--active,
  .cf-frame--exiting {
    position: relative !important;
    inset: auto !important;
    opacity: 1 !important;
    clip-path: none !important;
    -webkit-clip-path: none !important;
    transform: none !important;
    transition: none !important;
    pointer-events: auto !important;
    z-index: auto !important;
    background: transparent !important;
    width: 100% !important;
    max-width: 100% !important;
    box-sizing: border-box !important;
  }
  .cf-grid {
    display: flex !important;
    flex-direction: column !important;
    gap: 20px !important;
    grid-template-columns: none !important;
    grid-template-rows: none !important;
    padding: 0 !important;
    height: auto !important;
    width: 100% !important;
    box-sizing: border-box !important;
  }
  .cf-image-col {
    height: auto !important;
    aspect-ratio: 4 / 3 !important;
    min-height: 0 !important;
    border-radius: 14px !important;
    width: 100% !important;
  }
  .cf-image-col img {
    width: 100% !important;
    height: 100% !important;
    object-fit: cover !important;
  }
  .cf-text-col {
    grid-row: auto !important;
    max-width: 100% !important;
    /* Real bottom padding so the body's last line + specs don't kiss
       the next frame's image. The headline / eyebrow already have
       their own vertical rhythm above. */
    padding: 4px 2px 24px !important;
    width: 100% !important;
    box-sizing: border-box !important;
  }
  /* Body copy: kill the desktop max-width:46ch (which capped at desk
     widths but on phones can leave the line ending mid-sentence near
     the right edge) and give it real bottom margin into the specs. */
  .cf-body {
    max-width: 100% !important;
    margin: 0 0 26px !important;
  }
  .cf-specs {
    max-width: 100% !important;
    margin: 0 !important;
  }
  /* Tab strip — desktop pins it via its sticky parent. On mobile the
     parent stops being sticky, so we promote the strip to fixed at
     the top of the viewport (under the header). JS (mobile.js)
     adds .cf-tabs--pinned only while the cf-section is in view; the
     same JS toggles cf-tab--active + auto-scrolls the rail so the
     current frame's title sits centered. */
  .cf-tabs {
    position: fixed !important;
    top: var(--header-height, 56px) !important;
    left: 0 !important;
    right: 0 !important;
    width: 100% !important;
    max-width: none !important;
    margin: 0 !important;
    padding: 11px 14px 9px !important;
    background: rgba(245, 240, 232, 0.94) !important;
    backdrop-filter: blur(12px) saturate(1.1);
    -webkit-backdrop-filter: blur(12px) saturate(1.1);
    border-bottom: 1px solid rgba(43, 27, 23, 0.10) !important;
    box-shadow: 0 8px 24px -16px rgba(43, 27, 23, 0.18);
    z-index: 40 !important;
    overflow-x: auto !important;
    overflow-y: hidden !important;
    scroll-behavior: smooth;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    flex-wrap: nowrap !important;
    gap: 18px !important;
    /* Hidden by default — JS reveals it while cf-section is visible. */
    opacity: 0;
    pointer-events: none;
    transform: translateY(-6px);
    transition: opacity 240ms var(--ease-authority), transform 240ms var(--ease-authority);
  }
  .cf-tabs.cf-tabs--pinned {
    opacity: 1 !important;
    pointer-events: auto !important;
    transform: translateY(0) !important;
  }
  .cf-tabs::-webkit-scrollbar { display: none !important; }
  .cf-tab {
    flex-shrink: 0 !important;
    scroll-snap-align: center;
    font-size: 12px !important;
    padding: 4px 2px !important;
    transition: color 280ms var(--ease-authority), opacity 280ms var(--ease-authority);
    opacity: 0.55;
  }
  .cf-tab--active {
    opacity: 1 !important;
    font-weight: 600 !important;
    color: var(--color-ink) !important;
  }
}
@media (max-width: 600px) {
  .cf-headline { font-size: 1.7rem !important; line-height: 1.08 !important; margin-bottom: 14px !important; }
  .cf-body {
    font-size: 1rem !important;
    line-height: 1.55 !important;
    margin-bottom: 18px !important;
    font-style: italic !important;
  }
  .cf-eyebrow { font-size: 10.5px !important; letter-spacing: 0.24em !important; margin-bottom: 12px !important; }
  .cf-spec-row { padding: 12px 0 !important; gap: 12px !important; font-size: 13.5px !important; }
}

/* ════════════════════════════════════════════════════════════════════
   HOME — NETWORK SECTION (#network, height:330vh sticky desktop)
   The desktop pin runs a JS scroll-driven city cycler over 330vh of
   scroll. On mobile that feels stuck. We shorten the pin to ~120vh
   (just over one screen) so users see the section, glance the
   destination list, and the next section arrives quickly.
   The headline (absolute top) and destination list (absolute bottom)
   stay in place — the structure remains intact, just compressed.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 880px) {
  section#network { height: 130vh !important; }
  section#network h2.font-display {
    font-size: clamp(2rem, 9vw, 3.4rem) !important;
    line-height: 1 !important;
  }
  .vy-net-list li button { padding: 16px 4px !important; }
}
@media (max-width: 600px) {
  section#network { height: 120vh !important; }
  .vy-net-list .font-display {
    font-size: 1.05rem !important;
    line-height: 1.15 !important;
  }
  .vy-net-list .font-mono {
    font-size: 10px !important;
    letter-spacing: 0.18em !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   HOME — FOUNDERS PANEL (.vy-fp-section)
   ────────────────────────────────────────────────────────────────────
   Mobile path: every slide stays centred in the sticky pane and
   crossfades on scroll progress (the React tick-loop sets
   `transform: translate3d(0, 4vh, 0) scale(0.9)` and writes opacity
   inline per slide). The bundled CSS already handles mobile slide
   geometry (78vw × 50vh, centred) and mobile caption position
   (`inset:auto auto 5vh 8vw`).
   The previous flatten-everything override (`position:relative !important`
   on slides + caps + sticky, plus `opacity:1 !important; transform:none
   !important`) was killing the animation — we drop those entirely and
   only keep targeted phone polish: cream-bg-from-start (so no dark coal
   flash before the bg-flip threshold fires), legible body type, and a
   readable ghost-watermark colour on cream. The ghost (active founder's
   name) is rendered above the photo by React using inline
   `bottom:78vh; left:11vw; right:11vw`; we leave its position alone and
   only nudge contrast.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 880px) {
  /* Background scheme is left to the React tick-loop: the section
     starts coal/brown and the scroll-driven `.is-light` toggle (fired
     at p > 0.06) crossfades it to cream — same beat as desktop. We
     deliberately do NOT force a starting colour here. */

  /* Texture: a touch more presence than the desktop default so the
     panel doesn't read as flat. */
  .vy-fp-texture { opacity: 0.55 !important; }

  /* Body copy inside the caption — phone-tier sizing only. The bundle
     already centres the caption at the bottom of the sticky pane and
     widens it to 84vw. We keep React's per-word stagger intact (do NOT
     force opacity/transform on .vy-fp-cap-word). */
  .vy-fp-cap-bio {
    font-size: clamp(0.98rem, 3.6vw, 1.1rem) !important;
    line-height: 1.55 !important;
    margin: 0 0 14px !important;
  }
  .vy-fp-cap-link {
    font-size: 0.95rem !important;
    text-decoration: underline;
    text-underline-offset: 4px;
  }
}

/* Tighter caption on the smallest phones. */
@media (max-width: 380px) {
  .vy-fp-cap-bio { font-size: 0.95rem !important; line-height: 1.5 !important; }
}

/* ════════════════════════════════════════════════════════════════════
   HOME — FOUNDERS scroll-length cap
   ────────────────────────────────────────────────────────────────────
   .vy-fp-section is 520vh on desktop (3 slides × ~170vh of scroll-jack).
   On a phone that's ~5 full screens of scrolling for content that boils
   down to three founder cards — and contributes to the "endless scroll"
   feel reported on some Android devices. Cap it to ~280vh (≈ one screen
   per slide, which is plenty for the crossfade JS to register progress).
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 880px) {
  .vy-fp-section { height: 280vh !important; }
}
@media (max-width: 600px) {
  .vy-fp-section { height: 240vh !important; }
}

/* ════════════════════════════════════════════════════════════════════
   AIRCRAFT — ARCHITECTURE pin
   The 460vh PIN_VH from aircraft-architecture.tsx is only capped at
   ≤600px (line ~565). Add an earlier cap so tablets and large phones
   also get a sane scroll-length on what is essentially a 3-card stack.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 880px) and (min-width: 601px) {
  section[aria-label="Architecture"] { height: 200vh !important; }
}

/* ════════════════════════════════════════════════════════════════════
   FORTIMARK COLOPHON (.fm) — 3D card scene
   The Canvas can fall back to a static gradient (.fm__stage-fallback)
   when WebGL is unavailable. Make sure the section still reads as the
   designed gradient even when the fallback is showing, and keep the
   CTA legible on small screens.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 600px) {
  .fm {
    min-height: clamp(560px, 90vh, 760px) !important;
    padding: clamp(48px, 7vh, 96px) var(--viewport-gutter) !important;
  }
  .fm__cta {
    height: 52px !important;
    padding: 0 24px !important;
    font-size: clamp(1rem, 4.5vw, 1.2rem) !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   HOME — FOOTER CINEMA (.vy-footer-cinema)
   Existing rule sets headline at ≤760px. We add safer padding so the
   CTA and sub-line don't get cropped on small phones.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 600px) {
  .vy-footer-cinema { padding: 12vh var(--viewport-gutter) !important; }
  .vy-footer-stage { padding: 0 !important; }
  .vy-footer-sub { font-size: 0.95rem !important; line-height: 1.5 !important; max-width: 36ch !important; }
  /* Keep email + arrow on a single inline line — wrapping puts the
     arrow on its own line under the email and looks broken. Shrink
     font-size so the whole pill fits the narrowest phones. */
  .vy-footer-cta {
    font-size: clamp(0.78rem, 3.6vw, 0.95rem) !important;
    padding: 13px 18px !important;
    flex-wrap: nowrap !important;
    justify-content: center !important;
    gap: 10px !important;
    white-space: nowrap !important;
    max-width: calc(100vw - 32px) !important;
  }
  .vy-footer-cta-text {
    word-break: keep-all !important;
    white-space: nowrap !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   HOME — CONTACT SECTION (vy-hc-grid)
   The page ships an 880px @media in an inline <style>. We complement
   with phone-tier tweaks: form padding, label sizing, button height.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 600px) {
  /* Section padding compress */
  section[style*="--color-coal"][style*="padding:clamp(120px"] {
    padding: clamp(72px, 10vh, 120px) var(--viewport-gutter) clamp(64px, 8vh, 96px) !important;
  }
  /* Contact form internal padding */
  .vy-hc-grid form {
    padding: 22px !important;
    border-radius: 10px !important;
  }
  /* Form fields ≥16px to defeat iOS auto-zoom on focus */
  .vy-hc-grid input,
  .vy-hc-grid textarea {
    font-size: 16px !important;
    padding: 12px 14px !important;
  }
  .vy-hc-grid label > span {
    font-size: 9.5px !important;
    letter-spacing: 0.24em !important;
    margin-bottom: 8px !important;
  }
  .vy-hc-grid button[type="submit"] {
    padding: 16px 18px !important;
    font-size: 11px !important;
    letter-spacing: 0.24em !important;
  }
  /* The contact "Get in touch" h2 */
  section[style*="--color-coal"] h2[style*="font-size:clamp(2.4rem, 4.8vw, 4.4rem)"] {
    font-size: clamp(2.2rem, 9vw, 3.4rem) !important;
  }
  /* dl rows in contact: keep aligned but tighter */
  section[style*="--color-coal"] dl > div {
    grid-template-columns: minmax(80px, 96px) 1fr !important;
    gap: 12px !important;
    padding: 12px 0 !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   AIRCRAFT — Marquee speed (the rotating "VA-04 · SIX TILTING ROTORS"
   strip animates at 22s desktop. On phones, give it a faster pass so
   the small text feels alive instead of stalled.)
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 760px) {
  .vy-marquee-track {
    animation-duration: 16s !important;
  }
  /* Soften the marquee text size on phones — the clamp lets it grow
     too large at very narrow viewports because of the 6vw tier. */
  .vy-marquee-track .font-display {
    font-size: clamp(1.6rem, 9vw, 3rem) !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   AIRCRAFT — Page header & hero h1
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 600px) {
  /* Page-top header inside <main> */
  main > header[style*="padding:calc(72px + 12vh)"] {
    padding: calc(var(--header-height) + 36px) var(--viewport-gutter) clamp(48px, 8vh, 96px) !important;
  }
  main > header h1.font-display {
    font-size: clamp(2.4rem, 11vw, 4rem) !important;
  }
  main > header p {
    font-size: 0.95rem !important;
    line-height: 1.6 !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   AIRCRAFT — INSTRUMENT (#instrument · "The Airframe")
   ────────────────────────────────────────────────────────────────────
   The bundled section is a 1.55fr / 1fr split. The Next.js bundle
   already collapses the grid to 1 column at ≤900px (so the 3D viewer
   stacks above the text), and the React + Three.js Canvas keeps the
   assembly intro, rotor spin, tilt sweep and mode-selector animations
   alive on mobile via the same useFrame loop. We only need to polish
   the mobile layout: shrink the section padding, cap the 3D-stage
   height so the user can scroll past it, and let the corner controls
   wrap so they don't overflow the canvas on tiny phones. We also let
   the header row's TRL pill drop to its own line — it's pure metadata
   and shouldn't fight with the eyebrow for space on a 320px viewport.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  /* Section padding — desktop's clamp(80px, 12vh, 140px) is generous on
     mobile too. Tighten it just a notch to match the rest of the page. */
  section#instrument {
    padding: clamp(64px, 10vh, 120px) var(--viewport-gutter) clamp(64px, 10vh, 120px) !important;
  }
  /* Header row (eyebrow + TRL): allow it to wrap so the metadata can
     drop beneath the eyebrow on narrow widths. */
  section#instrument > div > div:first-child {
    margin-bottom: 22px !important;
    gap: 10px 24px !important;
  }
  /* The split grid → 1 column is already done by the bundled CSS at
     ≤900px. Tighten the inter-row gap so the headline sits closer to
     the viewer. */
  section#instrument .instrument-split {
    gap: clamp(20px, 3vh, 32px) !important;
    grid-template-columns: 1fr !important;
  }
  /* 3D stage height: cap to a portrait-ish box so the viewer doesn't
     eat a full screen and leave the CTA buried. The original inline
     `height:clamp(460px, 70vh, 820px)` is too tall stacked above the
     copy. */
  section#instrument .instrument-split > div:first-child {
    height: clamp(300px, 56vh, 440px) !important;
  }
  /* Headline + body */
  section#instrument h2.font-display {
    font-size: clamp(1.7rem, 7.4vw, 2.5rem) !important;
    line-height: 1.05 !important;
  }
  section#instrument p[style*="44ch"] {
    font-size: 14.5px !important;
    line-height: 1.65 !important;
    max-width: 100% !important;
  }
}
@media (max-width: 600px) {
  /* Tighter still on phones */
  section#instrument {
    padding: clamp(56px, 9vh, 96px) var(--viewport-gutter) clamp(56px, 9vh, 96px) !important;
  }
  section#instrument .instrument-split > div:first-child {
    height: clamp(280px, 62vw, 380px) !important;
  }
  /* Mode-selector pills inside the canvas — they live in an absolutely-
     positioned row at bottom-right. On a 320px viewport, three pills
     can poke past the canvas. Allow them to wrap and right-align. */
  section#instrument .instrument-split > div:first-child > div[style*="position:absolute"][style*="bottom:12px"][style*="right:12px"] {
    flex-wrap: wrap !important;
    justify-content: flex-end !important;
    max-width: calc(100% - 24px) !important;
    gap: 6px !important;
  }
  section#instrument .instrument-split > div:first-child > div[style*="bottom:12px"] button {
    padding: 6px 10px !important;
    font-size: 9.5px !important;
    letter-spacing: 0.2em !important;
  }
  /* Detail-card mode list (Hover / Transition / Cruise) under the body. */
  section#instrument ul li > button {
    padding: 14px 14px !important;
  }
  section#instrument ul li > button > div > span.font-display {
    font-size: 16px !important;
  }
  section#instrument ul li > button > span:last-child {
    font-size: 12.5px !important;
    line-height: 1.45 !important;
  }
}

/* Aircraft architecture stack already has 640px rules. Cap the pinned
   container height so it doesn't waste a full viewport. */
@media (max-width: 600px) {
  section[aria-label="Architecture"] {
    height: 130vh !important;
  }
  section[aria-label="Architecture"] > div[style*="position:sticky"] {
    padding: clamp(56px, 9vh, 96px) var(--viewport-gutter) clamp(56px, 8vh, 80px) !important;
  }
  section[aria-label="Architecture"] h2.font-display {
    font-size: clamp(2rem, 8.4vw, 3rem) !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   SAFETY — Hero stat row (very small numbers)
   The page ships strong mobile rules. We add tiny-phone polish.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 600px) {
  .sa-hero-stats {
    flex-wrap: wrap !important;
    gap: 16px 24px !important;
  }
  /* The hero subtitle / sa-hero-sub readability */
  .sa-hero-sub { max-width: 36ch !important; }
  /* Layer panel meta-strip readability */
  .sa-layer-tag,
  .sa-metric { white-space: nowrap !important; overflow: hidden !important; text-overflow: ellipsis !important; }
}

/* ════════════════════════════════════════════════════════════════════
   CONTACT (/contact — vy-rsv-section)
   The page ships @media (max-width:920px). We polish the letter card on
   phones so it breathes.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 600px) {
  .vy-rsv-section {
    padding: clamp(96px, 14vh, 140px) var(--viewport-gutter) clamp(72px, 10vh, 120px) !important;
  }
  .vy-rsv-letter {
    padding: 28px 22px !important;
    transform: translateY(20px) rotate(-0.4deg) !important;
  }
  .vy-rsv-letter h3 {
    font-size: clamp(1.7rem, 7vw, 2.4rem) !important;
  }
  .vy-rsv-section h2 {
    font-size: clamp(2rem, 8.5vw, 3.2rem) !important;
  }
  /* Tier list — keep three columns (number, title, price) but tighter */
  .vy-rsv-section li[role="button"],
  .vy-rsv-section li[style*="opacity:0.5"] {
    grid-template-columns: 24px 1fr auto !important;
    gap: 12px !important;
    padding: 16px 0 !important;
  }
  /* Bar-chart of remaining tier 1 — let it wrap on tiny screens */
  .vy-rsv-section li > div > div[style*="display:flex;gap:3px;align-items:flex-end"] {
    flex-wrap: wrap !important;
  }
  /* Letter form fields — iOS focus-zoom guard */
  .vy-rsv-letter input,
  .vy-rsv-letter textarea {
    font-size: 16px !important;
  }
  /* The wax seal button — keep round but slightly smaller */
  .vy-rsv-letter button[type="submit"] {
    width: 72px !important;
    height: 72px !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   COMPANY (/company — d-* classes)

   ── Hero (.d-zoom) ────────────────────────────────────────────────
   Desktop pins the section for 480vh and animates a single-line title
   "Our story starts" | [portal] | "in Kanpur, India." — text splits
   apart, an image portal opens between them, then goes fullscreen.

   On a phone the horizontal layout cramps and the JS-computed portal
   width caps at Math.min(180, 0.13×vw) ≈ 47px (a sliver). We restructure
   without removing the scroll animation:
   · Stack the title vertically — line / portal / line
   · Override the JS-set portal width/height to scale to a viewport-
     sized portrait box, still driven by --k01/--k12/--k23 so the
     portal opens, then fills as the user scrolls
   · Keep .d-zoom-stage sticky so the section pins (the global guard
     uses overflow-x: clip rather than hidden so iOS Safari sticky
     still works)
   · Floor --title-scale at 0.78 so headline doesn't shrink to ~7px
   · Compress the pin to 240vh (was 480vh desktop / 320vh shipped)
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 760px) {
  .d-zoom { height: 240vh !important; }

  /* Title stack — vertical with portal as the middle item. */
  .d-zoom-title {
    flex-direction: column !important;
    align-items: center !important;
    justify-content: center !important;
    gap: clamp(16px, 2.6vh, 28px) !important;
    white-space: normal !important;
    text-align: center !important;
    padding: 0 14px !important;
    font-size: calc(clamp(24px, 6.8vw, 36px) * max(0.78, var(--title-scale, 1))) !important;
  }
  .d-zoom-l { display: block !important; text-align: center !important; }
  /* Keep position:relative so the absolute --b overlays --a (JS
     cross-fades them); without relative, --b lands at the wrap's
     top-left and the two lines visibly overlap. */
  .d-zoom-r-wrap {
    display: block !important;
    position: relative !important;
    text-align: center !important;
    width: auto !important;
    min-width: 0 !important;
  }
  .d-zoom-r--b {
    left: 0 !important; right: 0 !important;
    width: 100% !important;
    text-align: center !important;
  }

  /* Portal: a portrait card. Width/height scale to viewport via the
     same --k01/--k12/--k23 progress vars JS sets on .d-zoom, so the
     portal opens with scroll the way the desktop one does. */
  .d-zoom-portal-wrap {
    transform: none !important;
    display: flex !important;
    width: 100% !important;
    justify-content: center !important;
  }
  .d-zoom-portal {
    /* Portal grows from 0 → 78vw across stage 0→1, then nudges up to
       86vw across stage 1→2 / 2→3 (a subtle "fills the frame" beat
       without pushing surrounding text off-screen on mobile). */
    width: calc(
      min(78vw, 360px) * max(var(--k01, 0), 0.001)
      + min(8vw, 40px) * (var(--k12, 0) + var(--k23, 0))
    ) !important;
    height: calc(
      (min(78vw, 360px) * 1.28) * max(var(--k01, 0), 0.001)
      + (min(8vw, 40px) * 1.28) * (var(--k12, 0) + var(--k23, 0))
    ) !important;
    border-radius: clamp(18px, 4.5vw, 28px) !important;
    transform: none !important;
    opacity: 1 !important;
  }
  /* Gallery slides pinned inside the portal box (so the cycling JS
     swaps their opacity in place rather than appearing to scroll). */
  .d-zoom-gallery,
  .d-zoom-slide {
    position: absolute !important;
    inset: 0 !important;
  }
  .d-zoom-slide-img {
    width: 100% !important;
    height: 100% !important;
    object-fit: cover !important;
  }
  /* JS fades title-l / title-r / portal opacity to 0 across stage
     2→3 (because on desktop the portal is fullscreen at that point
     and the text is supposed to vanish). On mobile our portal stays
     78vw, so when JS hits opacity 0 the section goes empty cream.
     Lock the wrap + title-l + portal to opacity 1 so the layout
     always has visible content. */
  .d-zoom-l,
  .d-zoom-r-wrap,
  .d-zoom-portal-wrap {
    opacity: 1 !important;
  }
  /* JS cross-fades --a ("in Kanpur, India.") and --b ("back in
     2024.") within scroll progress 0 → 0.08, then fades both to 0
     at stage 3. The mid-state where both are at ~0.5 opacity is
     fine on a desktop scrubbing past it in milliseconds, but on a
     phone — slower scroll, momentum stalls, sometimes sits on the
     mid-frame — both lines visibly overlap.
     Drop the JS-driven smooth cross-fade and replace with a hard
     step at p = 0.04: --a visible when p<0.04, --b visible when
     p>=0.04. The clamp(0, calc(...) * 1000, 1) collapses the
     transition to a single frame so the two lines are never both
     visible at once, and never fades them out at stage 3 either
     (so the section doesn't go empty). The JS-set inline opacity
     is overridden because we use !important and the calc resolves
     to a numeric value. */
  .d-zoom-r--a {
    opacity: clamp(0, calc((0.04 - var(--p, 0)) * 1000), 1) !important;
  }
  .d-zoom-r--b {
    opacity: clamp(0, calc((var(--p, 0) - 0.04) * 1000), 1) !important;
    display: inline !important;
  }
}

/* Very narrow phones — tighten the title so it breathes inside
   ~320–380px viewports. */
@media (max-width: 420px) {
  .d-zoom-title {
    gap: clamp(12px, 2vh, 20px) !important;
    padding: 0 10px !important;
    font-size: calc(clamp(22px, 6.4vw, 30px) * max(0.78, var(--title-scale, 1))) !important;
  }
  .d-zoom-portal {
    width: calc(
      min(82vw, 320px) * max(var(--k01, 0), 0.001)
      + min(8vw, 36px) * (var(--k12, 0) + var(--k23, 0))
    ) !important;
    height: calc(
      (min(82vw, 320px) * 1.28) * max(var(--k01, 0), 0.001)
      + (min(8vw, 36px) * 1.28) * (var(--k12, 0) + var(--k23, 0))
    ) !important;
  }
}
@media (max-width: 380px) {
  .d-num-deck { font-size: 15px !important; }
  .d-cr-bio-name { font-size: 28px !important; }
}

/* ════════════════════════════════════════════════════════════════════
   GLOBAL — small-text safety
   Mono "eyebrows" of the form clamp(...,...,...) at 11–13px sometimes
   overflow on a 320px screen because they ride on rows with other
   content. Allow them to wrap rather than push the row wider.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 600px) {
  .font-mono { word-break: break-word; }
}

/* ════════════════════════════════════════════════════════════════════
   GLOBAL — touch / scrolling smoothness
   Many sticky+scroll-driven sections on this site rely on the host
   browser's smooth scrolling. iOS Safari has a known issue where
   sticky elements stutter unless backface-visibility is hinted.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 880px) {
  .cf-sticky,
  .vy-fp-sticky,
  section#network > div[style*="position:sticky"],
  section[aria-label="Architecture"] > div[style*="position:sticky"] {
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
  }
}

/* Footer letter marquee — the per-letter staggered title is heavy on
   underpowered devices; if user prefers reduced motion or on phones,
   show the title statically */
@media (max-width: 600px) {
  .vy-footer-letter {
    opacity: 1 !important;
    filter: none !important;
    transform: none !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   FORM INPUT iOS FOCUS-ZOOM GUARD (catch-all)
   Any text input on phones gets ≥16px so iOS Safari doesn't zoom on
   focus. Pages that already enforce this from their own sheet are
   simply re-affirmed here.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 600px) {
  input[type="text"],
  input[type="email"],
  input[type="tel"],
  input[type="search"],
  input[type="url"],
  input[type="password"],
  textarea,
  select {
    font-size: max(16px, 1rem) !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   UTILITY — Marquee animation for tiny labels that risk clipping.
   Apply by adding `data-vy-marquee` to a wrapper; we leave the raw
   utility here for any future templates that need it.
   ════════════════════════════════════════════════════════════════════ */
@keyframes vy-mobile-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (max-width: 600px) {
  [data-vy-marquee] {
    display: flex !important;
    overflow: hidden !important;
    white-space: nowrap !important;
  }
  [data-vy-marquee] > * {
    animation: vy-mobile-marquee 18s linear infinite;
    flex-shrink: 0;
  }
}
