/* Inter self-hosted (variable, weights 400-800; was Google Fonts CDN -
   removing the render-blocking third-party CSS + font origin cut real
   first-load latency). Files: assets/fonts/. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("../assets/fonts/inter-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("../assets/fonts/inter-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ============================================================
   Tech True Point: dark 3D showpiece stylesheet
   Dark navy + baby blue + glass. Mobile-first.
   IMPORTANT: content is NEVER hidden by CSS. All entrance
   animation is driven from JS (gsap.set/from) and only runs when
   GSAP is present AND prefers-reduced-motion is not set. No-JS,
   reduced-motion, and GSAP-load-failure all render a complete,
   readable static page.
   ============================================================ */

:root {
  /* Base navy palette */
  --bg:          #070C18;
  --bg-2:        #0A1122;
  --panel:       #0E1730;
  --panel-2:     #121D3A;
  --line:        rgba(126, 200, 255, 0.14);
  --line-strong: rgba(126, 200, 255, 0.30);

  /* Blues */
  --primary:      #1E86E6;
  --primary-dark: #0B5FB3;
  --accent:       #2FA7FF;
  --baby:         #7EC8FF;
  --baby-soft:    #A9D8FF;

  /* Text (readable on navy) */
  --heading: #F4F9FF;
  --text:    #E4EDF9;
  --muted:   #9FB4CC;
  --faint:   #6E829C;

  /* Glass */
  --glass:      rgba(255, 255, 255, 0.045);
  --glass-2:    rgba(255, 255, 255, 0.07);
  --glass-brd:  rgba(146, 196, 250, 0.16);
  --glass-brd2: rgba(146, 196, 250, 0.30);

  /* Shadows / glow */
  --shadow:     0 24px 60px -24px rgba(0, 0, 0, 0.75);
  --shadow-lg:  0 44px 90px -30px rgba(0, 0, 0, 0.80);
  --glow-blue:  0 0 44px rgba(47, 167, 255, 0.22);
  --glow-cta:   0 10px 30px -6px rgba(30, 134, 230, 0.55);

  /* Spacing */
  --s-1: .5rem; --s-2: 1rem; --s-3: 1.5rem; --s-4: 2rem;
  --s-6: 3rem;  --s-8: 4rem; --s-12: 6rem;

  --r-sm: 10px; --r-md: 16px; --r-lg: 22px; --r-xl: 30px; --r-pill: 999px;
  --maxw: 1180px;
  --ease: cubic-bezier(.22, .61, .36, 1);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; background-color: var(--bg); /* brand-colored overscroll/rubber-band, never white */ }
body {
  margin: 0;
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--text);
  background: var(--bg);
  line-height: 1.65;
  font-size: 1.0625rem;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}
img, svg { max-width: 100%; display: block; }
a { color: var(--baby); text-decoration: none; }
/* In-prose links must not rely on colour alone (WCAG 2.1 AA 1.4.1). The
   generated pages already got this from content.css; the hand-written root
   pages load only this file, so a link inside a paragraph was distinguished by
   colour and nothing else. axe flagged exactly one (/plans), and /privacy and
   /payments had the same latent problem. Scoped to main prose, so nav, footer,
   cards and buttons keep their clean underline-free treatment. */
main p a:not(.btn) { text-decoration: underline; text-underline-offset: .18em; }
h1, h2, h3, h4 { color: var(--heading); line-height: 1.1; margin: 0 0 var(--s-2); letter-spacing: -0.02em; font-weight: 700; }
p { margin: 0 0 var(--s-2); color: var(--muted); }
ul { margin: 0; padding: 0; list-style: none; }
strong { color: var(--text); }

/* ---------- Fixed animated background ---------- */
.bg { position: fixed; inset: 0; z-index: -3; overflow: hidden; pointer-events: none;
  background:
    radial-gradient(120% 90% at 82% -8%, rgba(30, 90, 170, 0.30) 0%, rgba(10, 17, 34, 0) 55%),
    radial-gradient(90% 80% at 10% 100%, rgba(47, 167, 255, 0.12) 0%, rgba(10, 17, 34, 0) 55%),
    linear-gradient(180deg, #070C18 0%, #060A14 100%);
}
.bg-grid { position: absolute; inset: -2px; z-index: -2;
  background-image:
    linear-gradient(to right, rgba(126, 200, 255, 0.06) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(126, 200, 255, 0.06) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(120% 90% at 50% 0%, #000 0%, transparent 72%);
  mask-image: radial-gradient(120% 90% at 50% 0%, #000 0%, transparent 72%);
}
.bg-orb { position: absolute; border-radius: 50%; filter: blur(60px); opacity: .5; will-change: transform; }
.bg-orb.a { width: 46vw; height: 46vw; top: -12%; right: -8%; background: radial-gradient(circle, rgba(47,167,255,.42), transparent 68%); animation: orbA 22s var(--ease) infinite alternate; }
.bg-orb.b { width: 40vw; height: 40vw; bottom: -14%; left: -10%; background: radial-gradient(circle, rgba(11,95,179,.40), transparent 68%); animation: orbB 27s var(--ease) infinite alternate; }
@keyframes orbA { from { transform: translate3d(0,0,0) scale(1); } to { transform: translate3d(-6%, 5%, 0) scale(1.12); } }
@keyframes orbB { from { transform: translate3d(0,0,0) scale(1); } to { transform: translate3d(7%, -4%, 0) scale(1.15); } }
.bg-beam { position: absolute; top: -20%; left: 50%; width: 60vw; height: 140%;
  transform: translateX(-50%) rotate(14deg);
  background: linear-gradient(90deg, transparent, rgba(126,200,255,.05) 45%, rgba(126,200,255,.09) 50%, rgba(126,200,255,.05) 55%, transparent);
  filter: blur(6px); animation: beam 12s var(--ease) infinite alternate; }
@keyframes beam { from { opacity: .5; transform: translateX(-52%) rotate(14deg); } to { opacity: 1; transform: translateX(-48%) rotate(16deg); } }
#fx { position: fixed; inset: 0; z-index: -1; pointer-events: none; }

/* ---------- Layout ---------- */
.container { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 var(--s-3); }
.section { padding: var(--s-12) 0; position: relative; }
.section-tight { padding: var(--s-8) 0; position: relative; }
.center { text-align: center; }
.section-head { max-width: 52ch; margin: 0 auto var(--s-6); }
.eyebrow {
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: 0.74rem; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--baby); background: var(--glass); border: 1px solid var(--glass-brd);
  padding: 0.4rem 0.85rem; border-radius: var(--r-pill); margin-bottom: var(--s-3);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.eyebrow::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 8px var(--accent); }
.lead { font-size: 1.15rem; color: var(--muted); max-width: 46ch; }
.center .lead, .center .section-head { margin-left: auto; margin-right: auto; }
.grad { background: linear-gradient(100deg, var(--baby) 0%, var(--accent) 55%, var(--primary) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent; }

/* Type scale (mobile) */
h1, .h1 { font-size: 2.3rem; }
h2, .h2 { font-size: 1.8rem; }
h3, .h3 { font-size: 1.2rem; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .55rem;
  font-weight: 600; font-size: 1rem; padding: .9rem 1.5rem; border-radius: var(--r-sm);
  border: 1px solid transparent; cursor: pointer; white-space: nowrap;
  transition: transform .2s var(--ease), box-shadow .2s var(--ease), background .2s var(--ease), border-color .2s var(--ease);
}
.btn svg { width: 18px; height: 18px; }
.btn:active { transform: translateY(0) scale(.985); }
.btn-primary { background: linear-gradient(180deg, var(--accent), var(--primary)); color: #fff; box-shadow: var(--glow-cta); }
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 16px 40px -8px rgba(30,134,230,.7); color: #fff; }
.btn-ghost { background: var(--glass); color: var(--baby-soft); border-color: var(--glass-brd); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
.btn-ghost:hover { transform: translateY(-2px); border-color: var(--glass-brd2); background: var(--glass-2); color: #fff; }
.btn-lg { padding: 1.05rem 1.8rem; font-size: 1.05rem; }
.btn-block { width: 100%; }

/* ---------- Header / nav ---------- */
.site-header { position: sticky; top: 0; z-index: 60; border-bottom: 1px solid var(--line);
  background: rgba(8, 13, 26, 0.62); -webkit-backdrop-filter: saturate(160%) blur(14px); backdrop-filter: saturate(160%) blur(14px); }
.nav { display: flex; align-items: center; justify-content: space-between; height: 70px; }
/* flex:none is load-bearing. Without it the brand is a shrinkable flex item, so
   whenever the nav runs out of room the LOGO silently absorbs the overflow and
   renders squashed (measured 2026-07-16: the old mark rendered at aspect 1.28
   against its natural 2.51 at 2560px, and 2.12 at 1024px, i.e. visibly
   distorted on the owner's own 4K monitor). A distorted logo is never an
   acceptable pressure valve: make the nav fit instead. */
.brand { display: inline-flex; align-items: center; gap: .6rem; font-weight: 700; font-size: 1.2rem; color: var(--heading); letter-spacing: -0.02em; flex: none; }
.brand:hover { color: var(--heading); }
.brand .glyph { width: 30px; height: 30px; flex: none; filter: drop-shadow(0 0 10px rgba(47,167,255,.5)); }
/* Tech True Point lockup (2026-07-26 rebrand, replaces the Tech True Point image
   logo). No final logo art exists yet, so the brand is SET IN TYPE: it is
   crisp at every DPI, adds no request, needs no new asset filename, and cannot
   go stale behind the 4h asset cache. The diamond mark is drawn in CSS from
   this site's own blue and gold so the lockup still reads as an identity.
   `--gold` lives in theme-gold.css, which the homepage does NOT load, so every
   gold reference here carries a literal fallback.
   Markup lives in scripts/lib/chrome.mjs; swap real art in there. */
.brand-mark { width: 22px; height: 22px; flex: none; border-radius: 4px;
  background: linear-gradient(135deg, var(--accent) 0%, var(--primary) 48%, var(--gold, #D4A84F) 100%);
  transform: rotate(45deg);
  box-shadow: 0 2px 10px rgba(0,0,0,.5); }
.brand-word { font-size: 1.32rem; font-weight: 800; letter-spacing: -0.025em;
  line-height: 1; color: var(--heading); white-space: nowrap; }
.brand-word-accent { color: var(--gold, #D4A84F); }
/* Footer stacks the wordmark over the tagline; the header does not, because the
   nav width budget is tight (see the nav breakpoint note below). */
.brand-lockup { display: flex; flex-direction: column; gap: .22rem; }
/* The image logo carried its own optical padding; type does not, so the footer
   blurb needs explicit air or it collides with the tagline. */
.footer-id .brand { margin-bottom: .85rem; }
.brand-tagline { font-size: .72rem; font-weight: 600; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); line-height: 1; white-space: nowrap; }
@media (max-width: 560px) {
  .brand-word { font-size: 1.12rem; }
  .brand-mark { width: 18px; height: 18px; }
  .brand-tagline { font-size: .66rem; letter-spacing: .08em; }
}
.nav-links { display: none; }
.nav-cta { display: none; }
/* 44px minimum: this is a primary touch target and was 36px tall, which is
   under the accessible minimum on every phone. Centred so the three bars stay
   optically where they were. */
.nav-toggle { display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  background: none; border: 0; padding: 10px; cursor: pointer; border-radius: var(--r-sm);
  min-width: 44px; min-height: 44px; }
.nav-toggle span { width: 22px; height: 2px; background: var(--text); border-radius: 2px; transition: transform .2s var(--ease), opacity .2s var(--ease); }
.nav.open .nav-toggle span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav.open .nav-toggle span:nth-child(2) { opacity: 0; }
.nav.open .nav-toggle span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
.nav-toggle:focus-visible { outline: 2px solid var(--baby); outline-offset: 2px; }

/* Sticky shrink. The header is sticky from the start; scrolling only tightens
   it. HEIGHT IS ANIMATED ON .nav, NOT ON THE HEADER ITSELF, and the logo
   scales with it, so nothing below the header reflows: the page does not jump
   at the moment the class flips. --header-h feeds scroll-padding-top so
   in-page anchors never land underneath the bar. */
:root { --header-h: 70px; }
.site-header.is-stuck { background: rgba(6, 10, 20, .82); border-bottom-color: rgba(47,167,255,.16); box-shadow: 0 10px 30px -22px rgba(0,0,0,.9); }
.nav { transition: height .22s var(--ease); }
.site-header.is-stuck .nav { height: 58px; }
/* The old image logo also shrank on scroll (64 -> 54px). The type lockup
   deliberately does NOT: animating font-size reflows the nav on every scroll
   frame, which is exactly the sticky-shrink stutter fixed on 2026-07-23. The
   nav height still shrinks, so the header still reads as compacting. */
html { scroll-padding-top: calc(var(--header-h) + 1rem); }

/* ---------- Mobile panel ---------- */
/* Outcome-led: the first thing a visitor sees is a question, not a sitemap.
   Slides down under the header and fills the rest of the viewport. */
.mobile-menu { display: none; border-bottom: 1px solid var(--line); background: rgba(8,13,26,.98);
  -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px);
  padding: var(--s-3) 0 var(--s-5); max-height: calc(100dvh - 58px); overflow-y: auto; overscroll-behavior: contain; }
.mobile-menu.open { display: block; }
/* No-JS: the toggle button cannot work, so show the panel inline rather than
   stranding every link behind a control that does nothing. */
html:not(.js) .mobile-menu { display: block; max-height: none; }
html:not(.js) .nav-toggle { display: none; }

.mob-q { font-size: 1.24rem; font-weight: 700; color: var(--heading); letter-spacing: -.02em; margin-bottom: var(--s-3); }
.mob-outcomes { display: grid; gap: .6rem; margin-bottom: var(--s-4); }
.mob-outcome { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2);
  min-height: 56px; padding: .85rem 1rem; border: 1px solid var(--glass-brd); border-radius: var(--r-md, 12px);
  background: var(--glass); color: var(--heading); font-weight: 600; font-size: 1.02rem; }
.mob-outcome .mob-arrow { color: var(--baby); transition: transform .18s var(--ease); }
.mob-outcome:hover, .mob-outcome:focus-visible { border-color: var(--baby); color: var(--heading); }
.mob-outcome:hover .mob-arrow { transform: translateX(3px); }
.mob-outcome:focus-visible { outline: 2px solid var(--baby); outline-offset: 2px; }
.mobile-menu .btn { margin-top: 0; margin-bottom: .6rem; min-height: 48px; }
.mob-call { margin-bottom: var(--s-4); }
/* Conventional links, deliberately quieter than the outcomes above. Still 44px
   minimum: the secondary list is exactly where touch targets usually slip. */
.mob-links { display: grid; border-top: 1px solid var(--line); padding-top: var(--s-2); }
.mob-links a { display: flex; align-items: center; min-height: 44px; padding: .35rem .1rem;
  color: var(--muted); font-size: .96rem; font-weight: 500; }
.mob-links a[aria-current="page"] { color: var(--baby); }
.mob-links a:focus-visible { outline: 2px solid var(--baby); outline-offset: 2px; }

/* ---------- Hero ---------- */
.hero { position: relative; padding: var(--s-8) 0 var(--s-6); overflow: clip; }
.hero-grid { display: grid; gap: var(--s-6); align-items: center; }
.hero-copy { max-width: 40ch; }
.hero h1 { font-size: clamp(2.4rem, 8vw, 3rem); margin-bottom: var(--s-3); }
.hero .lead { font-size: 1.18rem; }
.hero-cta { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-4); }
.trust-row { display: flex; flex-wrap: wrap; gap: .5rem 1.2rem; margin-top: var(--s-4); font-size: .88rem; color: var(--muted); }
.trust-row span { display: inline-flex; align-items: center; gap: .45rem; }
.trust-row svg { width: 15px; height: 15px; color: var(--accent); }

/* Floating 3D hexagon / molecular network (the brand shape) */
.hero-3d { perspective: 1100px; display: flex; justify-content: center; align-items: center; min-height: min(88vw, 460px); touch-action: pan-y; }
.hero-shape { position: relative; width: min(460px, 86vw); aspect-ratio: 1; transform-style: preserve-3d; will-change: transform; cursor: grab; }
.hero-shape:active { cursor: grabbing; }
.hero-shape > * { position: absolute; inset: 0; }
.shape-glow { border-radius: 50%; transform: translateZ(-90px); filter: blur(52px);
  background: radial-gradient(circle at 52% 46%, rgba(47,167,255,.55) 0%, rgba(20,120,212,.20) 42%, transparent 70%); }
.shape-net { transform: translateZ(-16px); filter: drop-shadow(0 0 7px rgba(126,200,255,.45)); }
.shape-hex { transform: translateZ(34px); filter: drop-shadow(0 14px 40px rgba(47,167,255,.35)); }
.shape-core { display: grid; place-items: center; transform: translateZ(88px); pointer-events: none; }
.shape-core .glyph { width: 21%; filter: drop-shadow(0 0 20px rgba(47,167,255,.85)); }
/* Floating logo (replaces the hex cluster; inherits .hero-shape float + tilt) */
.shape-logo { display: grid; place-items: center; transform: translateZ(46px); pointer-events: none; }
.shape-logo img { width: 100%; height: auto; -webkit-user-drag: none; user-select: none;
  filter: saturate(1.2) contrast(1.09) brightness(1.05)
    drop-shadow(0 22px 48px rgba(11,95,179,.62))
    drop-shadow(0 0 42px rgba(47,167,255,.45))
    drop-shadow(0 0 10px rgba(169,216,255,.55)); }
/* Glassy specular sweep, masked to the logo shape so the light travels over the glass */
.shape-logo .shine { position: absolute; inset: 0; pointer-events: none; z-index: 2;
  -webkit-mask: url(../assets/logo.png) center / 100% auto no-repeat;
          mask: url(../assets/logo.png) center / 100% auto no-repeat;
  background: linear-gradient(102deg, transparent 40%, rgba(180,224,255,.35) 47%,
    rgba(255,255,255,.92) 50%, rgba(180,224,255,.35) 53%, transparent 60%);
  background-size: 250% 100%; background-repeat: no-repeat;
  mix-blend-mode: screen; opacity: .9;
  animation: logoShine 6s ease-in-out 1.2s infinite; }
@keyframes logoShine { 0% { background-position: 150% 0; } 60%, 100% { background-position: -70% 0; } }
/* pulsing molecular nodes */
.hero-shape .nd { transform-box: fill-box; transform-origin: center; animation: nodePulse 5.5s var(--ease) infinite; }
.hero-shape .nd:nth-of-type(3n)   { animation-duration: 7s;   animation-delay: -2s; }
.hero-shape .nd:nth-of-type(3n+1) { animation-duration: 6.2s; animation-delay: -3.3s; }
@keyframes nodePulse { 0%,100% { opacity: .35; transform: scale(1); } 50% { opacity: 1; transform: scale(1.5); } }

/* ---------- Glass cards / tilt ---------- */
.grid { display: grid; gap: var(--s-3); }
.card {
  position: relative; display: flex; flex-direction: column;
  background: var(--glass); border: 1px solid var(--glass-brd);
  border-radius: var(--r-md); padding: var(--s-4);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  box-shadow: var(--shadow); transition: transform .25s var(--ease), border-color .25s var(--ease), box-shadow .25s var(--ease), background .25s var(--ease);
}
/* Reusable equal-height card layout: inner wrapper fills the card, content grows,
   CTA/footer pinned to the bottom so button rows line up across every card in a row. */
.tilt-inner { flex: 1 1 auto; display: flex; flex-direction: column; }
.card-content { flex: 1 1 auto; }
.card-footer { margin-top: auto; }
.tilt { transform-style: preserve-3d; will-change: transform; }
.tilt .tilt-inner { transform: translateZ(30px); }
.card-hover:hover { border-color: var(--glass-brd2); background: var(--glass-2); box-shadow: var(--shadow), var(--glow-blue); }
.card .ico {
  width: 52px; height: 52px; border-radius: 50%; display: grid; place-items: center; margin-bottom: var(--s-3);
  background: radial-gradient(circle at 30% 25%, rgba(126,200,255,.22), rgba(11,95,179,.18));
  border: 1px solid var(--glass-brd2); color: var(--baby);
  box-shadow: inset 0 0 18px rgba(47,167,255,.18), 0 6px 18px -6px rgba(0,0,0,.6);
  transition: transform .25s var(--ease), box-shadow .25s var(--ease), color .25s var(--ease);
}
.card .ico svg { width: 24px; height: 24px; }
.card-hover:hover .ico { transform: translateY(-2px) scale(1.06); color: #fff;
  background: linear-gradient(160deg, var(--accent), var(--primary-dark)); box-shadow: 0 10px 26px -6px rgba(30,134,230,.7); }
.card h3 { margin-bottom: .4rem; }
.card p { margin-bottom: 0; font-size: .98rem; }

/* ---------- Capability chips (What I do) ---------- */
.chip-row { display: flex; flex-wrap: wrap; gap: .6rem; justify-content: center; margin-top: var(--s-4); }
.pill { display: inline-flex; align-items: center; gap: .5rem; font-size: .92rem; color: var(--baby-soft);
  background: var(--glass); border: 1px solid var(--glass-brd); padding: .55rem 1rem; border-radius: var(--r-pill); }
.pill svg { width: 16px; height: 16px; color: var(--accent); }

/* ---------- Why / value panels ---------- */
.value-num { font-size: .8rem; font-weight: 700; letter-spacing: .1em; color: var(--accent); }
.value-panel h3 { margin-top: .6rem; }

/* ---------- Plans / options ---------- */
.price-card { display: flex; flex-direction: column; }
.price-card.featured { border-color: var(--glass-brd2); box-shadow: var(--shadow), var(--glow-blue); }
.price-tag { position: absolute; top: -.8rem; left: var(--s-4); white-space: nowrap; font-size: .7rem; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: #04101f;
  background: linear-gradient(180deg, var(--baby), var(--accent)); padding: .32rem .8rem; border-radius: var(--r-pill);
  box-shadow: 0 8px 20px -6px rgba(47,167,255,.7); }
.price { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem; margin: var(--s-1) 0 var(--s-3); }
.price .amt { font-size: 1.7rem; font-weight: 700; color: var(--heading); letter-spacing: -.02em; }
.price .per { color: var(--muted); font-size: .95rem; }
.feature-list { margin: var(--s-2) 0 var(--s-4); }
.feature-list li { display: flex; gap: .6rem; align-items: flex-start; padding: .4rem 0; font-size: .97rem; color: var(--text); }
.feature-list li::before { content: ""; flex: none; margin-top: .3rem; width: 18px; height: 18px; border-radius: 50%;
  background: var(--glass-2) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%237EC8FF' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center/12px no-repeat;
  border: 1px solid var(--glass-brd); }
/* .card-footer (margin-top:auto) now pins the CTA; reserve a consistent note height
   so the helper text can wrap to a second line without pushing the buttons out of line. */
.pay-note { font-size: .82rem; color: var(--faint); margin-top: .7rem; min-height: 2.7em; }

/* ---------- CTA band ---------- */
.cta-band { position: relative; overflow: hidden; border-radius: var(--r-xl); padding: var(--s-8) var(--s-4); text-align: center;
  background: radial-gradient(120% 130% at 80% 0%, rgba(30,90,170,.5), rgba(10,18,38,.6)); border: 1px solid var(--glass-brd2);
  box-shadow: var(--shadow-lg), var(--glow-blue); }
.cta-band h2, .cta-band p { color: #fff; }
.cta-band p { color: var(--baby-soft); max-width: 48ch; margin-left: auto; margin-right: auto; }

/* ---------- Forms ---------- */
.form-card { max-width: 560px; margin: 0 auto; }
.field { margin-bottom: var(--s-2); }
.field label { display: block; font-weight: 600; font-size: .9rem; margin-bottom: .4rem; color: var(--text); }
.field input, .field textarea, .field select {
  width: 100%; font: inherit; color: var(--text); padding: .85rem .9rem; border: 1px solid var(--glass-brd); border-radius: var(--r-sm);
  background: rgba(6, 11, 24, 0.6); transition: border-color .15s var(--ease), box-shadow .15s var(--ease); }
.field input::placeholder, .field textarea::placeholder { color: var(--faint); }
.field select { appearance: none; }
.field input:focus, .field textarea:focus, .field select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(47,167,255,.22); }
.field textarea { min-height: 130px; resize: vertical; }
.form-status { margin-top: var(--s-2); font-size: .95rem; font-weight: 600; min-height: 1.2em; }
.form-status:empty { margin-top: 0; min-height: 0; }
.form-status.ok { color: #5fe3a1; }
.form-status.err { color: #ff9b9b; }

/* ---------- Contact meta ---------- */
.contact-meta li { display: flex; gap: .8rem; align-items: center; padding: .55rem 0; color: var(--text); font-size: .98rem; }
.contact-meta .ico { width: 42px; height: 42px; flex: none; border-radius: 50%; display: grid; place-items: center;
  background: linear-gradient(160deg, var(--accent), var(--primary-dark)); color: #fff; box-shadow: 0 6px 16px -4px rgba(30,134,230,.6); }
.contact-meta .ico svg { width: 19px; height: 19px; }
.contact-meta a { color: var(--baby-soft); }

/* ---------- Footer ---------- */
/* no top margin: the last section's own padding is all the air the page
   bottom gets (owner rule: no scrolling through empty space at the end) */
.site-footer { border-top: 1px solid var(--line); margin-top: 0; background: linear-gradient(180deg, rgba(10,17,34,0), rgba(8,13,26,.7)); }
.footer-brand { padding: var(--s-8) 0 var(--s-5); }
.footer-id p { font-size: .95rem; max-width: 34ch; }
.footer-contact { display: flex; flex-wrap: wrap; gap: .4rem 1.4rem; margin-top: var(--s-2); }
.footer-contact a { color: var(--baby-soft); font-size: .95rem; }
.footer-contact a:hover { color: var(--baby); }

/* Footer navigation.
   MOBILE-FIRST (this file is mobile-first: the accordion IS the base state).
   Each group is a <details>, so collapse/expand is native: keyboard operable,
   correct ARIA expanded state, and fully working with JS disabled. No JS. */
.footer-nav { display: grid; gap: 0; padding-bottom: var(--s-4); }
.footer-col { border-top: 1px solid var(--line); }
.footer-acc > summary {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-2); padding: .95rem .2rem; cursor: pointer;
  list-style: none; /* kill the default disclosure triangle */
}
.footer-acc > summary::-webkit-details-marker { display: none; }
.footer-h { font-size: .78rem; text-transform: uppercase; letter-spacing: .12em; color: var(--faint); font-weight: 600; }
.footer-acc[open] .footer-h { color: var(--heading); }
/* Chevron drawn in CSS so it needs no asset and inherits currentColor. */
.footer-chev { width: .62rem; height: .62rem; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; color: var(--faint); transform: rotate(45deg) translate(-2px, -2px); transition: transform .2s var(--ease); flex: none; }
.footer-acc[open] .footer-chev { transform: rotate(225deg) translate(-2px, -2px); }
.footer-links { display: grid; padding: 0 .2rem .9rem; }
.footer-links a { display: block; padding: .42rem 0; color: var(--text); font-size: .95rem; }
.footer-links a:hover { color: var(--baby); }
/* Focus must be visible on every interactive element in the footer, not just
   the summary. There is no global outline reset in this file, so these would
   otherwise inherit the UA default ring, which is not guaranteed to be legible
   against a near-black background. Be explicit. */
.footer-acc > summary:focus-visible,
.footer-links a:focus-visible,
.footer-contact a:focus-visible,
.footer-bottom a:focus-visible { outline: 2px solid var(--baby); outline-offset: 3px; border-radius: var(--r-sm, 6px); }

.footer-bottom { border-top: 1px solid var(--line); padding: var(--s-3) 0; display: flex; flex-direction: column; gap: .6rem; font-size: .86rem; color: var(--faint); }

/* ---------- Mobile action bar ---------- */
/* Visible on small screens ONLY, by CSS alone. JS never has to show it, so it
   survives JS being off (DO_NOT_CHANGE.md no-JS rule). */
.mobile-bar { display: none; }
.mobile-bar-btn { display: inline-flex; align-items: center; justify-content: center; gap: .5rem; font-weight: 600; font-size: 1rem; line-height: 1; padding: .95rem .6rem; border-radius: var(--r-pill); text-align: center; }
.mobile-bar-btn svg { flex: none; }

/* ---------- Misc ---------- */
.tag-list { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: var(--s-3); }
.tag { font-size: .84rem; color: var(--baby-soft); background: var(--glass); border: 1px solid var(--glass-brd); padding: .35rem .8rem; border-radius: var(--r-pill); }
.split { display: grid; gap: var(--s-4); }
.stack-2 > * + * { margin-top: var(--s-3); }
.muted { color: var(--muted); }

/* ============================================================
   Breakpoints
   ============================================================ */
@media (min-width: 640px) {
  .grid-2 { grid-template-columns: repeat(2, 1fr); }
  .hero-cta .btn { min-width: 160px; }
}
@media (min-width: 900px) {
  h1, .h1 { font-size: 3.4rem; }
  h2, .h2 { font-size: 2.4rem; }
  .hero h1 { font-size: clamp(3rem, 4.4vw, 3.9rem); }
  .nav-toggle { display: none; }
  .nav-links { display: flex; align-items: center; gap: var(--s-3); }
  .nav-cta { display: inline-flex; }

  /* Top-level items. Triggers are <button> because they operate a disclosure;
     plain items are <a>. Both are styled identically so the row reads as one
     set of peers rather than a mix of controls and links. */
  .nav-item { position: relative; }
  .nav-link {
    display: inline-flex; align-items: center; gap: .35rem; position: relative;
    background: none; border: 0; padding: .5rem 0; margin: 0; cursor: pointer;
    font: inherit; font-weight: 500; font-size: .96rem; color: var(--muted);
    transition: color .16s var(--ease);
    font-family: inherit; line-height: 1.4;
  }
  .nav-link:hover, .nav-link:focus-visible, .nav-link.is-current, .nav-link[aria-expanded="true"] { color: var(--heading); }
  .nav-link:focus-visible { outline: 2px solid var(--baby); outline-offset: 4px; border-radius: 4px; }

  /* THE BRAND TRAIL. A blue-to-gold underline lifted from the logo's own
     ribbon. It is a pseudo-element scaled on the X axis, so it never changes
     layout: no width animation, no border, nothing that could reflow the nav.
     Hover and focus scale it in; the current page keeps it permanently. */
  .nav-link > span:first-child::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
    border-radius: 2px;
    background: linear-gradient(90deg, var(--accent) 0%, var(--baby) 45%, #E4B24C 100%);
    transform: scaleX(0); transform-origin: left center;
    transition: transform .26s var(--ease);
  }
  .nav-link:hover > span:first-child::after,
  .nav-link:focus-visible > span:first-child::after,
  .nav-link[aria-expanded="true"] > span:first-child::after { transform: scaleX(1); }
  /* Current page: always on, and slightly stronger so it is distinguishable
     from a passing hover rather than identical to it. */
  .nav-link.is-current > span:first-child::after { transform: scaleX(1); height: 2px; opacity: 1; }
  .nav-link:not(.is-current) > span:first-child::after { opacity: .85; }

  .nav-caret { width: .42rem; height: .42rem; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg) translate(-1px, -1px); transition: transform .2s var(--ease); flex: none; opacity: .7; }
  .nav-link[aria-expanded="true"] .nav-caret { transform: rotate(225deg) translate(-1px, -1px); }

  /* ---------- Mega menu ---------- */
  .mega {
    position: absolute; top: calc(100% + .55rem); left: 0; z-index: 70;
    min-width: 17rem; padding: var(--s-3); border-radius: var(--r-md);
    /* Opaque, not translucent. At .97 alpha the page headline was still
       readable through the panel, which looks unfinished and hurts contrast
       for the links on top of it. A menu is a surface, not a scrim. */
    background: #0B1220;
    -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px);
    border: 1px solid var(--glass-brd);
    box-shadow: 0 30px 60px -30px rgba(0,0,0,.9);
    opacity: 0; visibility: hidden; transform: translateY(-4px);
    transition: opacity .18s var(--ease), transform .18s var(--ease), visibility .18s;
  }
  .nav-item.is-open > .mega { opacity: 1; visibility: visible; transform: translateY(0); }
  /* Bridge the gap between the tab and the panel. The panel sits .55rem below
     the trigger, and that strip belongs to neither element: moving the pointer
     down through it fires mouseleave on the item and the menu snaps shut just
     as you reach for it. This invisible extension makes the gap part of the
     menu, so the pointer never leaves. */
  .mega::before { content: ""; position: absolute; left: 0; right: 0; top: -.65rem; height: .65rem; }
  /* No-JS fallback: hover and keyboard focus still open the panel, so the menus
     are never dependent on script. When JS is present the class above drives
     it instead, so the two cannot fight. */
  html:not(.js) .nav-item:hover > .mega,
  html:not(.js) .nav-item:focus-within > .mega { opacity: 1; visibility: visible; transform: translateY(0); }

  .mega-inner { display: grid; gap: var(--s-3) var(--s-4); }
  .mega[id="menu-services"] .mega-inner,
  .mega[id="menu-insights"] .mega-inner { grid-template-columns: repeat(2, minmax(9.5rem, 1fr)); }
  .mega-col { display: grid; align-content: start; gap: .1rem; }
  .mega-h { font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .14em;
    color: var(--faint); margin: 0 0 .45rem; }
  .mega-col a { display: block; padding: .42rem .5rem; margin: 0 -.5rem; border-radius: 6px;
    color: var(--text); font-size: .93rem; line-height: 1.4; transition: background .14s var(--ease), color .14s var(--ease); }
  .mega-col a:hover { background: var(--glass); color: var(--heading); }
  .mega-col a:focus-visible { outline: 2px solid var(--baby); outline-offset: -2px; }
  .mega-all { display: inline-block; margin-top: var(--s-3); padding-top: var(--s-2);
    border-top: 1px solid var(--line); color: var(--baby); font-size: .88rem; font-weight: 600; width: 100%; }
  .mega-all:hover { color: var(--heading); }
  .mega-all:focus-visible { outline: 2px solid var(--baby); outline-offset: 2px; }

  /* Edge safety: menus on the right-hand triggers would otherwise run off the
     viewport and force horizontal scroll. Anchor those to the right instead. */
  .nav-item:nth-last-child(-n+2) .mega { left: auto; right: 0; }
  .grid-3 { grid-template-columns: repeat(3, 1fr); }
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .hero-grid { grid-template-columns: 1.05fr .95fr; gap: var(--s-8); }
  .split { grid-template-columns: 1.05fr .95fr; align-items: center; gap: var(--s-8); }
  .contact-split { display: grid; grid-template-columns: .82fr 1.18fr; gap: var(--s-6); align-items: start; }
  .footer-bottom { flex-direction: row; justify-content: space-between; align-items: center; }

  /* Desktop footer: six columns, all groups permanently open.
     The <details> stays in the markup (one source of truth for both layouts);
     here it is forced open and the summary stops behaving like a control, so a
     desktop keyboard user does not tab through six toggles that do nothing. */
  /* Brand and contact share one row so the right half is not dead space. */
  .footer-brand { padding: var(--s-8) 0 var(--s-4); display: flex; justify-content: space-between; align-items: flex-end; gap: var(--s-6); }
  .footer-contact { margin-top: 0; flex: none; }
  .footer-nav { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--s-4); padding-bottom: var(--s-6); }
  .footer-col { border-top: 0; }
  /* Summary is inert on desktop: it reads as a column heading, not a control.
     The groups are emitted `open` and main.js keeps them open above 900px. */
  .footer-acc > summary { pointer-events: none; padding: 0 0 var(--s-1); }
  .footer-chev { display: none; }
  .footer-links { padding: 0; }
}
/* Nav breakpoint. The links used to appear at 900px, but 7 links + the CTA need
   ~737px and the nav is only ~852px at 900px wide: there is no logo size that
   fits, so the header overflowed and the brand squashed (this predates the
   Tech True Point lockup; the old mark was distorted at 1024 too). Hold the hamburger
   until 1200px, where everything genuinely fits. Verified by sweep across 18
   widths, 360-2560. */
@media (min-width: 900px) and (max-width: 1199px) {
  .nav-toggle { display: inline-flex; }
  .nav-links { display: none; }
  .nav-cta { display: none; }
}
@media (min-width: 1100px) { .grid-4 { grid-template-columns: repeat(4, 1fr); } }

/* FOUC-safe reveal: hide entrance elements BEFORE first paint, but only when JS has
   "armed" it (an inline <head> script adds html.reveal-armed, and only when motion is
   allowed). main.js disarms on init; it also disarms on reduced-motion / GSAP failure,
   and an inline onload failsafe disarms after 1.8s. So no-JS, reduced-motion, and a
   script/GSAP failure all leave a fully visible page — no content is ever stranded. */
html.reveal-armed [data-hero],
html.reveal-armed [data-reveal],
html.reveal-armed .hero-3d { opacity: 0; }

/* ============================================================
   Reduced motion: kill all animation, keep everything visible.
   (Content is never hidden by CSS, so this is fully safe.)
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
  .shape-logo .shine { display: none; }
  /* The nav trail and menus become instant state changes rather than fades.
     The underline must still SHOW for hover/focus/current, it just does not
     travel; removing it entirely would drop a state indicator. */
  .nav-link:hover > span:first-child::after,
  .nav-link:focus-visible > span:first-child::after,
  .nav-link[aria-expanded="true"] > span:first-child::after,
  .nav-link.is-current > span:first-child::after { transform: scaleX(1); }
}
/* Calm ambient layers on small screens */
@media (max-width: 899px) {
  .bg-beam { display: none; }
  .bg-orb { opacity: .38; }
}

/* ============================================================
   Mobile action bar (small screens only)
   ============================================================
   Fixed bottom bar with the two actions that convert: call, or ask for a
   quote. Shown by CSS alone so it does not depend on JS.

   SAFE AREA: the bar sits in the home-indicator region on modern iPhones, so
   its padding adds env(safe-area-inset-bottom). That env() only resolves to a
   non-zero value when the page ships viewport-fit=cover, which every page in
   this site now does (see scripts/sync-chrome.mjs, which enforces it).

   COVERING CONTENT: the bar is fixed, so it is out of flow and WOULD sit on
   top of the end of the page. body gets matching bottom padding at the same
   breakpoint to reserve the space. Any change to the bar's height must change
   that padding too; they are derived from one --bar-h variable so they cannot
   drift apart.
   ============================================================ */
@media (max-width: 899px) {
  :root { --bar-h: 4.25rem; }

  .mobile-bar {
    display: grid;
    grid-template-columns: 1fr 1.25fr;
    gap: .6rem;
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 60; /* above content, below the mobile nav menu */
    padding: .55rem var(--s-3);
    padding-bottom: calc(.55rem + env(safe-area-inset-bottom, 0px));
    background: rgba(8, 13, 26, .92);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-top: 1px solid var(--line);
    transform: translateY(0);
    transition: transform .25s var(--ease), opacity .25s var(--ease);
  }
  /* Reserve the space so the bar never covers the last of the page. */
  body { padding-bottom: calc(var(--bar-h) + env(safe-area-inset-bottom, 0px)); }

  .mobile-bar-call { background: var(--glass); border: 1px solid var(--glass-brd); color: var(--heading); }
  .mobile-bar-call:hover { color: var(--baby); }
  .mobile-bar-quote { background: var(--baby); color: #06101f; }
  .mobile-bar-btn:focus-visible { outline: 2px solid var(--heading); outline-offset: 2px; }

  /* Tucked away while the quote form is actually on screen: pointing at a form
     the visitor is already looking at is noise, and the bar would cover it.
     Added by js/main.js; purely an enhancement. */
  .mobile-bar.mobile-bar-tucked { transform: translateY(120%); opacity: 0; pointer-events: none; }

  /* Pages that opt out entirely (e.g. /contact, where both actions are already
     the whole page). Reclaim the reserved padding too. */
  body[data-no-bar] .mobile-bar { display: none; }
  body[data-no-bar] { padding-bottom: 0; }
}
/* The mobile nav menu overlays the page; the bar must not float over it. */
.mobile-menu.open ~ .mobile-bar,
body.menu-open .mobile-bar { transform: translateY(120%); opacity: 0; pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .mobile-bar { transition: none; }
}

/* ============================================================
   LiquidStory (homepage scroll experience; markup only on index).
   One sticky full-viewport WebGL stage behind five HTML scenes.
   The static WebP fallback is visible by default;
   js/liquid-story/liquid-story.js adds .is-live to the story only
   after WebGL has rendered a first frame, which cross-fades canvas
   in / image out. No-JS, reduced-motion, weak devices, and WebGL
   failure all keep the image and a fully readable page. Scenes are
   viewport-tall ONLY when JS + motion are available; otherwise they
   collapse to normal compact sections.
   ============================================================ */

/* near-black homepage background so the reflective liquid edges read;
   subtle navy stays at the very top edge only */
body.story-dark .bg {
  background:
    radial-gradient(46% 58% at 63% 44%, rgba(28, 120, 200, 0.34) 0%, rgba(10, 30, 60, 0.10) 55%, rgba(7, 12, 24, 0) 75%),
    radial-gradient(70% 90% at 12% 40%, rgba(24, 52, 100, 0.50) 0%, rgba(9, 16, 34, 0.14) 60%, rgba(7, 12, 24, 0) 80%),
    radial-gradient(120% 70% at 50% -12%, rgba(30, 72, 130, 0.38) 0%, rgba(7, 12, 24, 0) 62%),
    linear-gradient(115deg, #0B1730 0%, #081124 46%, #05091A 78%, #040816 100%);
}
/* faint atmospheric haze drifting over the story backdrop (texture, no bands) */
body.story-dark .bg::after {
  content: ""; position: absolute; inset: -20%;
  background:
    radial-gradient(38% 30% at 68% 60%, rgba(90, 160, 230, 0.05), transparent 70%),
    radial-gradient(30% 26% at 30% 25%, rgba(120, 180, 240, 0.04), transparent 70%);
  filter: blur(30px);
  animation: lsHaze 26s var(--ease) infinite alternate;
}
@keyframes lsHaze { from { transform: translate3d(-2%, 1%, 0); } to { transform: translate3d(2%, -1.5%, 0); } }
body.story-dark .bg-grid { opacity: .5; }
body.story-dark .bg-beam, body.story-dark .bg-orb { display: none; }
body.story-dark #fx { display: none; }

.story { position: relative; }
.story-stage {
  position: sticky; top: 0; height: 100vh; margin-bottom: -100vh;
  z-index: 0; overflow: hidden; pointer-events: none;
}
.story-stage canvas {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  opacity: 0; transition: opacity .45s var(--ease);
}
.story.is-live .story-stage canvas { opacity: 1; }
/* The boot placeholder is ALIVE: a rain still tiled vertically and panned
   down by CSS, so rain is falling from the very first paint - the WebGL
   canvas then fades in over identical-looking motion and the handoff is
   imperceptible. The ::before box is exactly 3 tiles tall (aspect-ratio),
   translated by one tile per loop = seamless. */
.story-fallback {
  position: absolute; inset: 0; overflow: hidden;
  opacity: .92; transition: opacity .45s var(--ease), visibility 0s .5s;
}
.story-fallback::before {
  content: ""; position: absolute; left: 0; top: 0;
  width: 100%; aspect-ratio: 1280 / 2400;
  background: url("../assets/liquid-story-still5.webp") 0 0 / 100% 33.3334% repeat-y;
  animation: lsRainPan 7s linear infinite;
  transform: translateY(-33.3333%);
  will-change: transform;
}
@keyframes lsRainPan {
  from { transform: translateY(-33.3333%); }
  to   { transform: translateY(0); }
}
/* small screens: the 3-tile box cannot cover a portrait viewport; keep the
   still static there (the live canvas takes over on first touch anyway) */
@media (max-width: 899px) {
  .story-fallback::before { animation: none; transform: none; inset: 0; width: 100%; height: 100%;
    aspect-ratio: auto; background-size: cover; background-position: center; }
}
@media (prefers-reduced-motion: reduce) {
  .story-fallback::before { animation: none; transform: none; }
}
/* once live, fully REMOVE the animated layer (visibility after the fade):
   an invisible but still-animating fullscreen raster layer contended with
   the 4K WebGL canvas for GPU memory and caused scroll hitches */
.story.is-live .story-fallback { opacity: 0; visibility: hidden; }

/* Scenes: compact readable sections by default (no-JS / reduced motion)... */
.scene { position: relative; z-index: 1; padding: var(--s-12) 0; }
.scene-copy { max-width: 44ch; }
.scene-copy h1 { text-shadow: 0 2px 26px rgba(2, 4, 9, .95); }
.scene-copy h2 { font-size: clamp(1.9rem, 3.6vw, 2.7rem); text-shadow: 0 2px 26px rgba(2, 4, 9, .95); }
.scene-copy .lead, .scene-copy .trust-row { text-shadow: 0 2px 16px rgba(2, 4, 9, .9); }
.scene-copy.right { margin-left: auto; }
.scene-copy.center { margin: 0 auto; text-align: center; }
.scene-copy.center .hero-cta { justify-content: center; }

/* ...and viewport-tall scroll scenes when the animated story can run */
@media (prefers-reduced-motion: no-preference) {
  html.js .scene { display: flex; align-items: center; min-height: 118vh; padding: var(--s-8) 0; }
  html.js .scene-1 { min-height: 106vh; }
  html.js .scene-5 { min-height: 104vh; }
}

@media (max-width: 899px) {
  .scene-copy.right { margin-left: 0; }
}
/* shorter scenes on phones; the story stays but scrolls quicker */
@media (max-width: 899px) and (prefers-reduced-motion: no-preference) {
  html.js .scene { min-height: 104vh; }
}

/* Reduced motion: never run the canvas, keep the still image */
@media (prefers-reduced-motion: reduce) {
  .story-stage canvas { display: none; }
  .story .story-fallback { opacity: .92; }
}

/* ============================================================
   LiquidStory hero visual system (homepage only; body.story-dark).
   One cohesive "cinematic liquid technology" language: near-black
   #02060D base, #23A8FF / #78D7FF cyan-blue accents, white ~10-14%
   borders, soft cyan shadows. Scoped so the other pages keep the
   existing sitewide look until they get their own pass.
   ============================================================ */
body.story-dark { --acc1: #23A8FF; --acc2: #78D7FF; }

body.story-dark .bg {
  background:
    radial-gradient(120% 70% at 50% -10%, rgba(35, 168, 255, 0.10) 0%, rgba(2, 6, 13, 0) 55%),
    linear-gradient(180deg, #02060D 0%, #01040A 100%);
}

/* header: calm, restrained; logo keeps ONE soft cyan glow, not a neon stack */
body.story-dark .site-header {
  background: rgba(2, 6, 13, 0.62);
  border-bottom-color: rgba(255, 255, 255, 0.10);
}
/* Homepage variant. The homepage sits on the lit ribbon hero, so the type
   lockup gets a deeper neutral shadow to hold it off the moving artwork.
   Neutral, never blue: blue light here would fight the gold in the ribbon. */
body.story-dark .brand-word,
body.story-dark .brand-tagline {
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.65);
}
body.story-dark .brand-mark {
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.6);
}
body.story-dark .nav-links a { color: #8FA6C4; }
body.story-dark .nav-links a:hover,
body.story-dark .nav-links a[aria-current="page"] { color: var(--acc2); }

/* headline: white with the droplet's cyan-blue family on the highlight only */
body.story-dark .scene-copy h1 {
  color: #F7FBFF; font-size: clamp(2.6rem, 4.2vw, 3.7rem); font-weight: 800;
  line-height: 1.08; letter-spacing: -0.025em; max-width: 20ch; margin-bottom: 1.1rem;
}
body.story-dark .scene-1 .scene-copy .lead { font-size: 1.19rem; color: #CDDDF0; line-height: 1.7; margin-bottom: 1.4rem; }
body.story-dark .scene-1 .hero-cta { margin-top: .2rem; }
body.story-dark .scene-1 .trust-row { margin-top: 1.3rem; gap: 1.4rem; }
body.story-dark .grad {
  background: linear-gradient(100deg, var(--acc2) 0%, var(--acc1) 85%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* body copy: cleaner blue-gray, more air, controlled width */
body.story-dark .scene-copy { max-width: 50ch; }
body.story-dark .scene-copy .lead { color: #C7D8EC; line-height: 1.75; }
html.js body.story-dark .scene-1 .scene-copy { max-width: 54ch; }
body.story-dark .eyebrow { color: var(--acc2); border-color: rgba(255, 255, 255, 0.12); }
body.story-dark .eyebrow::before { background: var(--acc1); box-shadow: 0 0 8px var(--acc1); }
body.story-dark .trust-row { color: #8FA6C4; }
body.story-dark .trust-row svg { color: var(--acc1); }

/* buttons: liquid glass. Primary = translucent blue glass with inner
   highlight + soft cyan edge; hover = restrained light sweep. */
body.story-dark .btn { position: relative; overflow: hidden; }
body.story-dark .btn-primary {
  background: linear-gradient(180deg, rgba(120, 215, 255, 0.30), rgba(35, 168, 255, 0.20));
  color: #EAF7FF;
  border: 1px solid rgba(120, 215, 255, 0.38);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22), 0 8px 28px -10px rgba(35, 168, 255, 0.55);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
}
body.story-dark .btn-primary::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(105deg, transparent 42%, rgba(255, 255, 255, 0.16) 50%, transparent 58%);
  transform: translateX(-130%); transition: transform .7s var(--ease);
}
body.story-dark .btn-primary:hover {
  transform: translateY(-2px); color: #FFFFFF;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), 0 12px 34px -10px rgba(35, 168, 255, 0.7);
}
body.story-dark .btn-primary:hover::after { transform: translateX(130%); }
body.story-dark .btn-ghost {
  background: rgba(4, 10, 20, 0.45); color: #CFE6FA;
  border: 1px solid rgba(120, 215, 255, 0.22);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
}
body.story-dark .btn-ghost:hover {
  background: rgba(10, 22, 40, 0.60); border-color: rgba(120, 215, 255, 0.40); color: #FFFFFF;
}

/* desktop-only headline break for a balanced two-line lockup */
.hero-br { display: none; }
@media (min-width: 900px) { .hero-br { display: inline; } }
@media (prefers-reduced-motion: reduce) { body.story-dark .btn-primary::after { display: none; } }
