/*
Theme Name: Qubi Advisory Service
Theme URI: https://qubiadvisoryservice.com/
Author: Qubi Advisory Service Ltd
Description: Bespoke single-page theme for Qubi Advisory Service. Scroll-driven hero, ambient background video with a coded fallback, and a post-quantum migration walkthrough. No page builder and no framework.
Version: 2026-09-03T16-33-10
Requires at least: 6.0
Tested up to: 6.7
Requires PHP: 7.4
License: All rights reserved
Text Domain: qubi-advisory
*/

/* ===========================================================================
   Qubi Advisory Service, "Ink & Cyan"
   Crisp white ground, near-black ink for type, the logo's own cyan as the
   single accent. The hero stays the one deliberately dark, cinematic moment;
   everything below it is the light, legible document.
   =========================================================================== */

/* --- Tokens -------------------------------------------------------------- */

:root {
  /* Ground. Three tiers: white page, a tinted recess for fields/tiles/footer,
     white again for cards, which separate from the page via shadow and border,
     not a different fill, since the page is already white. */
  --paper:    #FFFFFF;
  --paper-2:  #F5F7FA;
  --paper-3:  #EEF1F5;

  /* Component-surface aliases. Cards, stat tiles, panels and form fields
     read their fill through these rather than --paper directly, so a
     .section--dark can flip an entire subtree by redefining three names
     instead of touching every component rule. */
  --surface:   var(--paper);
  --surface-2: var(--paper-2);
  --surface-3: var(--paper-3);

  --line:     #E3E7EC;
  --line-2:   #CBD3DB;

  /* Ink. Near-black with a cool undertone, not a flat grey. */
  --ink:      #0A1420;
  --ink-2:    #45505E;   /* secondary body copy, 8.2:1 on white */
  --ink-3:    #647080;   /* tertiary / mono labels, 4.7:1 worst case, on the paper-2 tint */

  /* The one brand colour, used two ways. --cyan is the logo's exact hex: a
     fill, a border, an icon dot, a button ground, never small text on white,
     because it measures 2.3:1 there and fails legibility outright. --cyan-ink
     is the same hue pushed dark enough to read as text (5.0:1). That's what
     carries links, eyebrow labels and small headings on the light page. */
  --cyan:      #13BDCF;
  --cyan-dim:  #0C96A4;
  --cyan-ink:  #0D7B87;

  /* Same rule for the two semantic accents: full-strength for fills/dots,
     a darkened twin for anything that has to be read as text on white. */
  --amber:      #E9A94D;
  --amber-ink:  #9A6313;   /* worst case: 4.7:1 on the paper-2 tint */
  --mint:       #5FD9A8;
  --mint-ink:   #1C7853;   /* worst case: 4.6:1 inside the tinted form-success message */

  /* The hero and its scrim keep working in raw rgb(7,11,20,â¦), a colour that
     never appears in the light page, so it is left as literals there rather
     than pulled into a token nothing else touches. */
  --void:     #070B14;

  --display: "Space Grotesk", "Segoe UI", system-ui, sans-serif;
  --body:    "IBM Plex Sans", "Segoe UI", system-ui, sans-serif;
  --mono:    "IBM Plex Mono", ui-monospace, "Cascadia Code", Consolas, monospace;

  --shell:   1180px;
  --gut:     clamp(1.25rem, 4vw, 2.5rem);
  --section: clamp(4.5rem, 10vw, 9rem);

  --r:       12px;
  --r-lg:    18px;

  --shadow-card: 0 1px 2px rgba(10, 20, 32, 0.04), 0 14px 28px -18px rgba(10, 20, 32, 0.16);
  --shadow-card-hover: 0 2px 4px rgba(10, 20, 32, 0.05), 0 20px 36px -18px rgba(10, 20, 32, 0.22);

  --ease:    cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-io: cubic-bezier(0.65, 0, 0.35, 1);
}

/* --- Reset --------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 5.5rem;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-size: 1rem;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;

  /* clip, NOT hidden. `overflow-x: hidden` makes the other axis compute to
     `auto`, which quietly turns body into a scroll container: that breaks
     momentum scrolling and position:sticky on iOS, and this hero is built on
     sticky. `clip` contains any stray horizontal overflow without creating a
     scroll container at all. */
  overflow-x: clip;
}

img, svg, canvas { display: block; max-width: 100%; }
h1, h2, h3, h4 { margin: 0; font-weight: 600; font-family: var(--display); }
p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--cyan-dim);
  outline-offset: 3px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 300;
  background: var(--ink); color: var(--paper);
  padding: 0.85rem 1.25rem; font-weight: 600;
  border-radius: 0 0 var(--r) 0;
}
.skip:focus { left: 0; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --- Type ---------------------------------------------------------------- */

.d1 {
  font-family: var(--display);
  font-size: clamp(2.4rem, 6.2vw, 4.5rem);
  line-height: 1.02;
  letter-spacing: -0.03em;
  font-weight: 700;
  text-wrap: balance;
}

.d2 {
  font-family: var(--display);
  font-size: clamp(1.9rem, 4.4vw, 3.1rem);
  line-height: 1.08;
  letter-spacing: -0.025em;
  font-weight: 600;
  text-wrap: balance;
}

.d3 {
  font-family: var(--display);
  font-size: clamp(1.35rem, 2.4vw, 1.75rem);
  line-height: 1.18;
  letter-spacing: -0.02em;
}

.d4 {
  font-family: var(--display);
  font-size: 1.15rem;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.lede {
  font-size: clamp(1.05rem, 1.6vw, 1.25rem);
  line-height: 1.6;
  color: var(--ink-2);
  text-wrap: pretty;
}

.prose { color: var(--ink-2); text-wrap: pretty; }
.prose > * + * { margin-top: 1.15rem; }
.prose strong { color: var(--ink); font-weight: 600; }

.label {
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--cyan-ink);
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.label::before {
  content: "";
  width: 7px; height: 7px;
  background: var(--cyan);
  transform: rotate(45deg);
  flex: none;
}

.label--amber { color: var(--amber-ink); }
.label--amber::before { background: var(--amber); }
.label--mint { color: var(--mint-ink); }
.label--mint::before { background: var(--mint); }

.mono { font-family: var(--mono); font-size: 0.85em; letter-spacing: 0.02em; }
.muted { color: var(--ink-3); }
.small { font-size: 0.9rem; }
.xs { font-size: 0.8rem; line-height: 1.6; }

/* --- Layout -------------------------------------------------------------- */

.shell { width: min(100% - (var(--gut) * 2), var(--shell)); margin-inline: auto; }
.shell--narrow { max-width: 760px; }

.section { padding-block: var(--section); position: relative; background: var(--paper); }
.section--tight { padding-block: clamp(3rem, 6vw, 5rem); }

/* The five divider strips between sections sit at <main> level, outside any
   .section, so they need the same opaque ground or the fixed dark ambient
   layer behind the hero would show through the gap. */
main > .shell { background: var(--paper); }

.head { max-width: 46rem; margin-bottom: clamp(2.5rem, 5vw, 4rem); }
.head .d2 { margin-top: 1.25rem; }
.head .lede { margin-top: 1.35rem; }

.grid { display: grid; gap: clamp(1.25rem, 2.5vw, 1.75rem); }
.g2 { grid-template-columns: repeat(2, 1fr); }
.g3 { grid-template-columns: repeat(3, 1fr); }

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}

@media (max-width: 900px) {
  .g3 { grid-template-columns: repeat(2, 1fr); }
  .split { grid-template-columns: 1fr; }
}
@media (max-width: 620px) {
  .g2, .g3 { grid-template-columns: 1fr; }
}

/* Hairline divider carrying the lattice motif */
.divider { position: relative; height: 1px; background: var(--line); }
.divider::after {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  width: 9px; height: 9px;
  background: var(--paper);
  border: 1px solid var(--line-2);
  transform: translate(-50%, -50%) rotate(45deg);
}

/* --- Buttons ------------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.6rem;
  padding: 0.9rem 1.6rem;
  border: 1px solid transparent;
  border-radius: 100px;
  font-family: var(--body);
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition: background-color 0.25s var(--ease), color 0.25s var(--ease),
              border-color 0.25s var(--ease), transform 0.25s var(--ease),
              box-shadow 0.25s var(--ease);
}

.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }

.btn--primary {
  background: var(--ink);
  color: var(--paper);
  box-shadow: 0 0 0 0 rgba(10, 20, 32, 0);
}
.btn--primary:hover { box-shadow: 0 10px 26px -10px rgba(10, 20, 32, 0.45); }

.btn--ghost { border-color: var(--line-2); color: var(--ink); }
.btn--ghost:hover { border-color: var(--cyan-dim); color: var(--cyan-ink); background: rgba(19,189,207,0.06); }

.btn-row { display: flex; flex-wrap: wrap; gap: 0.75rem; }

.link {
  display: inline-flex; align-items: center; gap: 0.45rem;
  font-weight: 600; font-size: 0.92rem; color: var(--cyan-ink);
  transition: gap 0.25s var(--ease), color 0.25s var(--ease);
}
.link:hover { gap: 0.75rem; color: var(--cyan-dim); }

/* --- Ambient background (hero only) --------------------------------------
   A fixed layer behind the whole viewport: video where it can play, a coded
   field of falling data where it cannot, and a scrim over both. It stays dark
   by design. This is the one cinematic surface on an otherwise light page,
   and every .section from here down paints an opaque white ground over it, so
   it is visible only through the hero's own transparent stage. */

.bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.bg__canvas,
.bg__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.bg__canvas { opacity: 0.42; }
.bg__canvas.is-off { display: none; }

.bg__video {
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.4s var(--ease);
}

.bg__video.is-on { opacity: 0.62; }

/* If playback is refused outright, the poster still carries the same world. */
@media (prefers-reduced-motion: reduce) {
  .bg__video { opacity: 0.45; }
}

/* The scrim is what keeps hero copy readable over moving footage. */
.bg__scrim {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(7, 11, 20, 0.34), transparent 72%),
    linear-gradient(180deg,
      rgba(7, 11, 20, 0.76) 0%,
      rgba(7, 11, 20, 0.49) 24%,
      rgba(7, 11, 20, 0.54) 62%,
      rgba(7, 11, 20, 0.82) 100%);
}

/* Content sits above the background layer. Without this the fixed .bg would
   paint over every non-positioned block below it. */
main, .ftr { position: relative; z-index: 1; }

/* Each .section paints its own background, but their padding comes from
   clamp(), which rounds to a fractional pixel at most viewport widths, so two
   adjacent sections rarely tile at a perfectly whole pixel. The sub-pixel
   seam left over used to show the dark video layer bleeding through as a
   thin black line, which is what happened at the ai-governance/sovereignty
   boundary.

   The fix is a forced 1px overlap, not a background on <main> itself: main
   is .hero's own parent, and .hero deliberately has no background of its own
   so the video layer shows through its gaps. A background on main paints
   behind the hero too, in the same stacking context, which quietly cuts the
   hero off from that layer. Pulling each section up into the one before it
   costs one shared pixel row, always won by whichever colour is later in the
   document, and never touches the hero, since :first-child is excluded. */
main > * + * { margin-top: -1px; }

/* --- Header ---------------------------------------------------------------
   Fixed and transparent at rest, floating directly over the dark hero, so its
   idle colours are hardcoded light values rather than the page's ink tokens.
   Once .is-stuck applies, meaning the visitor has scrolled onto the white
   page underneath it, both the ground and the text flip to the light-page
   palette. Two colour states for one element, deliberately. */

.hdr {
  position: fixed;
  inset: 0 0 auto;
  z-index: 100;
  transition: background-color 0.35s var(--ease), border-color 0.35s var(--ease),
              backdrop-filter 0.35s var(--ease);
  border-bottom: 1px solid transparent;
}

.hdr.is-stuck {
  background: rgba(255, 255, 255, 0.86);
  backdrop-filter: saturate(160%) blur(14px);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  border-bottom-color: var(--line);
}

.hdr__in {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem; min-height: 4.6rem;
}

/* The Q is the logo artwork itself; "UBI" is set beside it to finish the
   wordmark, in the logo's own cyan. Tucked in slightly so the orbit's tail
   reads as part of the word rather than a floating mark. */
.brand { display: inline-flex; align-items: center; gap: 0.4rem; flex: none; }

.brand__q { height: 38px; width: auto; flex: none; }

.brand__type { display: grid; line-height: 1; }

/* With the wordmark gone, this line carries the name on its own, so it takes
   a little more weight and presence than a subtitle would. Idle over the
   hero it is near-white; once stuck over the light page it becomes ink. */
.brand__sub {
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.82);
  transition: color 0.3s var(--ease);
}
.hdr.is-stuck .brand__sub { color: var(--ink-2); }

.nav ul { display: flex; align-items: center; gap: 0.25rem; }
.nav a {
  display: block; padding: 0.5rem 0.85rem; border-radius: 100px;
  font-size: 0.92rem; font-weight: 500; color: rgba(255, 255, 255, 0.82);
  transition: color 0.2s var(--ease), background-color 0.2s var(--ease);
}
.nav a:hover { color: #fff; background: rgba(255,255,255,0.1); }
.hdr.is-stuck .nav a { color: var(--ink-2); }
.hdr.is-stuck .nav a:hover { color: var(--ink); background: var(--paper-3); }

.hdr__cta { display: flex; align-items: center; gap: 0.6rem; flex: none; }
.hdr__cta .btn { padding: 0.7rem 1.25rem; font-size: 0.9rem; }

/* The idle (over-hero) primary button needs to read on dark footage, so it
   borrows the cyan-on-ink treatment rather than the page's ink-on-white one;
   once stuck, the ordinary .btn--primary rule already applies correctly. */
.hdr:not(.is-stuck) .hdr__cta .btn--primary {
  background: var(--cyan);
  color: #04222E;
}

.burger {
  display: none;
  width: 44px; height: 44px; padding: 0;
  border: 1px solid rgba(255,255,255,0.3); border-radius: 10px;
  background: transparent; cursor: pointer;
  align-items: center; justify-content: center;
  transition: border-color 0.3s var(--ease);
}
.hdr.is-stuck .burger { border-color: var(--line-2); }

.burger i {
  display: block; position: relative;
  width: 16px; height: 1.5px; background: #fff;
  transition: background-color 0.2s var(--ease);
}
.burger i::before, .burger i::after {
  content: ""; position: absolute; left: 0;
  width: 16px; height: 1.5px; background: #fff;
  transition: transform 0.28s var(--ease);
}
.hdr.is-stuck .burger i,
.hdr.is-stuck .burger i::before,
.hdr.is-stuck .burger i::after { background: var(--ink); }

.burger i::before { top: -5px; }
.burger i::after  { top: 5px; }
.burger[aria-expanded="true"] i { background: transparent; }
.burger[aria-expanded="true"] i::before { transform: translateY(5px) rotate(45deg); }
.burger[aria-expanded="true"] i::after  { transform: translateY(-5px) rotate(-45deg); }

@media (max-width: 900px) {
  .burger { display: inline-flex; }
  .hdr__cta .btn { display: none; }
  .nav {
    /* The mobile dropdown is always light, whatever the header is floating
       over, so its own link colour is fixed to ink rather than inheriting
       the idle/stuck split above. */
    position: fixed; inset: 4.6rem 0 auto;
    background: rgba(255, 255, 255, 0.98);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-bottom: 1px solid var(--line);
    padding: 0.5rem var(--gut) 1.5rem;
    transform: translateY(-10px); opacity: 0; visibility: hidden;
    transition: opacity 0.25s var(--ease), transform 0.25s var(--ease),
                visibility 0.25s var(--ease);
    max-height: calc(100dvh - 4.6rem); overflow-y: auto;
    box-shadow: 0 16px 32px -20px rgba(10,20,32,0.25);
  }
  .nav.is-open { transform: none; opacity: 1; visibility: visible; }
  .nav ul { display: block; }
  .nav li + li { border-top: 1px solid var(--line); }
  .nav a,
  .hdr.is-stuck .nav a {
    padding: 0.95rem 0.25rem; font-size: 1.05rem; border-radius: 0;
    color: var(--ink-2);
  }
  .nav a:hover, .hdr.is-stuck .nav a:hover { color: var(--ink); background: none; }
}

/* --- Hero -------------------------------------------------------------- *
   The one place the site stays dark. Its own internals (vignette, caption
   text-shadow) are unchanged. They already reference a near-black literal
   that matches --ink closely enough that unifying them would be invisible. */

.hero { position: relative; }

/* Scroll distance. Overridden to 100vh when scrub is unavailable. */
.hero__track { height: 100vh; }
.js-scrub .hero__track { height: 420vh; }

/* Phones never get the scrub at all (hero.js switches to ambient mode below
   900px), so the track stays one screen tall and the hero scrolls away like
   any normal section. The Discover / Protect / Monitor story still gets
   told: it is a full section further down the page. */

.hero__stage {
  position: sticky; top: 0;
  height: 100vh; height: 100dvh;
  overflow: hidden;
  display: grid;
  place-items: center;
}

.hero__canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  /* Purely decorative. It must never swallow a touch that was meant to scroll. */
  pointer-events: none;
}

/* Scrim so caption text always has ground to sit on, whatever the crystal is
   doing behind it. Narrow screens get a top-down wash because the crystal sits
   low; wide screens get a left wash because it sits right of centre. */
.hero__stage::after {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(7,11,20,0.88) 0%, rgba(7,11,20,0.72) 40%, rgba(7,11,20,0.2) 72%),
    linear-gradient(0deg, rgba(7,11,20,0.92) 0%, transparent 26%);
}

@media (min-width: 900px) {
  .hero__stage::after {
    background:
      linear-gradient(90deg, rgba(7,11,20,0.94) 0%, rgba(7,11,20,0.78) 32%, transparent 60%),
      radial-gradient(120% 90% at 63% 50%, transparent 42%, rgba(7,11,20,0.5) 100%),
      linear-gradient(180deg, rgba(7,11,20,0.6) 0%, transparent 18%, transparent 74%, rgba(7,11,20,0.88) 100%);
  }
}

/* On small screens the text takes the upper half and the crystal sits below
   it, so the buttons never land on top of the lattice. */
@media (max-width: 899px) {
  .hero__stage { align-items: start; }
  /* The floor keeps the headline clear of the fixed header on short screens
     (landscape phones), where 15vh alone lands underneath it. */
  .hero__content { padding-top: max(15vh, 7rem); }
}

.hero__content {
  position: relative;
  z-index: 2;
  width: min(100% - (var(--gut) * 2), var(--shell));
  margin-inline: auto;
}

/* Caption bands. Each is stacked in the same cell and cross-faded by JS. */
.band {
  grid-area: 1 / 1;
  max-width: 40rem;
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
  will-change: opacity, transform;
}

.band.is-on { opacity: 1; transform: none; }

.js-scrub .hero__content { display: grid; }
.js-scrub .band { pointer-events: none; }
.js-scrub .band.is-on { pointer-events: auto; }

/* Without scrub, only the settle band shows and it is static. */
.hero__content:not(.is-scrub) .band { display: none; }
.hero__content:not(.is-scrub) .band--settle {
  display: block; opacity: 1; transform: none;
}

/* The hero's own type stays light-on-dark regardless of the light page below
   it, so its labels and body copy are pinned to explicit light values rather
   than the ink tokens the rest of the site now uses. */
.band .label { margin-bottom: 1.3rem; color: var(--cyan); }
.band .label::before { background: var(--cyan); }
.band .label--amber { color: var(--amber); }
.band .label--amber::before { background: var(--amber); }
.band .label--mint { color: var(--mint); }
.band .label--mint::before { background: var(--mint); }

.band__t {
  font-family: var(--display);
  font-size: clamp(1.9rem, 5vw, 3.4rem);
  line-height: 1.06;
  letter-spacing: -0.03em;
  font-weight: 700;
  text-wrap: balance;
  color: #F5F7FA;
  text-shadow: 0 2px 40px rgba(7, 11, 20, 0.9);
}

.band__b {
  margin-top: 1.1rem;
  font-size: clamp(1rem, 1.5vw, 1.15rem);
  color: rgba(245, 247, 250, 0.78);
  max-width: 34rem;
  text-wrap: pretty;
  text-shadow: 0 2px 24px rgba(7, 11, 20, 0.95);
}

.band--settle .btn-row { margin-top: 2.25rem; }
.band--settle .band__t { max-width: 18ch; }

/* The hero's own buttons: cyan-on-ink and a light ghost outline, matching the
   header's idle state rather than the page's ink-on-white pattern. */
.band .btn--primary { background: var(--cyan); color: #04222E; }
.band .btn--primary:hover { box-shadow: 0 10px 26px -10px rgba(19,189,207,0.5); }
.band .btn--ghost { border-color: rgba(245,247,250,0.35); color: #F5F7FA; }
.band .btn--ghost:hover { border-color: var(--cyan); color: var(--cyan); background: rgba(19,189,207,0.1); }

/* Scroll cue */
.cue {
  position: absolute;
  bottom: 2rem; left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  display: flex; flex-direction: column; align-items: center; gap: 0.6rem;
  font-family: var(--mono);
  font-size: 0.66rem; letter-spacing: 0.22em; text-transform: uppercase;
  color: rgba(245, 247, 250, 0.6);
  transition: opacity 0.4s var(--ease);
}
.cue__line { width: 1px; height: 34px; background: linear-gradient(var(--cyan), transparent); }
.cue.is-gone { opacity: 0; }
.hero__content:not(.is-scrub) ~ .cue { display: none; }

/* --- Cards ----------------------------------------------------------------
   The page is already white, so a card can't read as a lighter surface. It
   lifts off the ground with a border and a soft shadow instead. */

.card {
  position: relative;
  display: flex; flex-direction: column; gap: 0.8rem;
  padding: clamp(1.5rem, 2.5vw, 2rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  transition: border-color 0.35s var(--ease), transform 0.35s var(--ease),
              box-shadow 0.35s var(--ease);
}

/* The lattice node lights up on hover */
.card::before {
  content: "";
  position: absolute; top: 1.4rem; right: 1.4rem;
  width: 8px; height: 8px;
  background: var(--line-2);
  transform: rotate(45deg);
  transition: background-color 0.35s var(--ease), box-shadow 0.35s var(--ease);
}

.card:hover { border-color: var(--line-2); transform: translateY(-3px); box-shadow: var(--shadow-card-hover); }
.card:hover::before { background: var(--cyan); box-shadow: 0 0 14px rgba(19,189,207,0.55); }

/* Dark boxes on a light section: the inverse of .section--dark. Used where the
   ground should stay white but the cards themselves keep the deep navy fill,
   so the card colour is a property of the card, not borrowed from a dark
   section wrapped around it. */
.card--dark {
  background: #111B2D;
  border-color: rgba(245, 247, 250, 0.14);
  box-shadow: none;
}
.card--dark:hover { border-color: rgba(245, 247, 250, 0.3); box-shadow: none; }
.card--dark::before { background: rgba(245, 247, 250, 0.24); }
.card--dark:hover::before { background: var(--cyan); box-shadow: 0 0 14px rgba(19,189,207,0.55); }
.card--dark .card__n { color: var(--cyan); }
.card--dark .card__t { color: #F5F7FA; }
.card--dark .card__b { color: rgba(245, 247, 250, 0.76); }

/* The seventh capability spans the row rather than sitting as an orphan in a
   three-column grid, which also gives sovereignty the emphasis it earns. */
.card--wide {
  grid-column: 1 / -1;
  flex-direction: row;
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: start;
}

.card--wide > :first-child { flex: 0 0 clamp(9rem, 22%, 14rem); }
.card--wide > :last-child { display: grid; gap: 0.9rem; justify-items: start; }
.card--wide .card__t { margin-top: 0.5rem; }

@media (max-width: 700px) {
  .card--wide { flex-direction: column; gap: 0.8rem; }
  .card--wide > :first-child { flex: none; }
}

.card__n {
  font-family: var(--mono);
  font-size: 0.72rem; letter-spacing: 0.14em; color: var(--cyan-ink);
}
.card__t { font-size: 1.28rem; letter-spacing: -0.02em; line-height: 1.2; color: var(--ink); }
.card__b { font-size: 0.95rem; color: var(--ink-2); text-wrap: pretty; }

/* Big stat block */
.stat {
  padding: clamp(1.5rem, 2.5vw, 2rem);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface-2);
}
.stat__v {
  font-family: var(--display);
  font-size: clamp(2.4rem, 5vw, 3.4rem);
  font-weight: 700; line-height: 1; letter-spacing: -0.03em;
  color: var(--amber-ink);
}
.stat--cyan .stat__v { color: var(--cyan-ink); }
.stat--mint .stat__v { color: var(--mint-ink); }
.stat__k { margin-top: 0.9rem; color: var(--ink-2); font-size: 0.95rem; text-wrap: pretty; }
.stat__src {
  margin-top: 0.9rem; padding-top: 0.9rem;
  border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.05em;
  color: var(--ink-3);
}

/* Numbered steps */
.steps { display: grid; gap: 0; border-top: 1px solid var(--line); }
.step {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr) minmax(0, 1.5fr);
  gap: clamp(1rem, 3vw, 2.5rem);
  padding-block: clamp(1.75rem, 3vw, 2.5rem);
  border-bottom: 1px solid var(--line);
  align-items: start;
}
.step__n {
  font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.12em;
  color: var(--cyan-ink); padding-top: 0.45rem;
}
.step__t { font-size: clamp(1.3rem, 2.2vw, 1.7rem); letter-spacing: -0.02em; color: var(--ink); }
.step__b { color: var(--ink-2); text-wrap: pretty; }

@media (max-width: 820px) {
  .step { grid-template-columns: 3rem minmax(0, 1fr); }
  .step__b { grid-column: 2; }
}

/* Discover / Protect / Monitor: all three are the same dark block within an
   otherwise white section, so the sequence carries the same weight the page
   itself does elsewhere. */
.step--dark {
  background: #0A1420;
  border-radius: var(--r-lg);
  border-bottom-color: transparent;
  padding-inline: clamp(1.25rem, 3vw, 2rem);
  margin-block: 0.4rem;
}
.step--dark .step__n { color: var(--cyan); }
.step--dark .step__t { color: #F5F7FA; }
.step--dark .step__b { color: rgba(245, 247, 250, 0.76); }

@media (max-width: 820px) {
  .step--dark { padding-inline: 1.1rem; }
}

/* Tick lists using the lattice node */
.ticks { display: grid; gap: 0.85rem; }
.ticks li {
  position: relative; padding-left: 1.65rem;
  color: var(--ink-2); text-wrap: pretty;
}
.ticks li::before {
  content: ""; position: absolute; left: 0; top: 0.62em;
  width: 7px; height: 7px; background: var(--cyan);
  transform: rotate(45deg);
}
.ticks strong { color: var(--ink); font-weight: 600; }

/* Panels */
.panel {
  padding: clamp(1.75rem, 3vw, 2.5rem);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}

.panel--glow {
  background:
    radial-gradient(90% 120% at 100% 0%, rgba(19,189,207,0.09), transparent 60%),
    var(--surface-2);
}

.note {
  border-left: 2px solid var(--amber);
  padding-left: 1.1rem;
  color: var(--ink-2);
  text-wrap: pretty;
}

/* --- Migration walkthrough (the interactive moment) ----------------------- */

.mig { display: grid; gap: 1.75rem; }

/* The rail is a real sequence, so the numbers and the connecting line are
   carrying information rather than decorating. */
/* The rail appears only once JS has confirmed the tabs will work. Without it
   the six phases read as a plain stacked sequence, which is also exactly what
   a crawler that does not execute scripts should receive. */
.mig__rail { display: none; }
.mig__panels { display: grid; gap: 1.25rem; }
.mig.is-tabbed .mig__panels { display: block; }

.mig.is-tabbed .mig__rail {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 0;
  position: relative;
}

.mig.is-tabbed .mig__rail::before {
  content: "";
  position: absolute;
  top: 19px;
  left: 8%;
  right: 8%;
  height: 1px;
  background: var(--line-2);
}

.mig__step {
  position: relative;
  z-index: 1;
  display: grid;
  justify-items: center;
  gap: 0.6rem;
  width: 100%;
  padding: 0 0.25rem;
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--ink-3);
  transition: color 0.25s var(--ease);
}

.mig__n {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1px solid var(--line-2);
  background: var(--surface);
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  transition: all 0.3s var(--ease);
}

.mig__t {
  font-family: var(--body);
  font-size: 0.82rem;
  font-weight: 500;
  letter-spacing: -0.005em;
  text-align: center;
}

.mig__step:hover { color: var(--ink-2); }
.mig__step:hover .mig__n { border-color: var(--ink-3); }

.mig__step[aria-selected="true"] { color: var(--ink); }
.mig__step[aria-selected="true"] .mig__n {
  background: var(--cyan);
  border-color: var(--cyan);
  color: #04222E;
  font-weight: 500;
  box-shadow: 0 0 20px -6px rgba(19, 189, 207, 0.7);
}

/* Phases already covered read as done rather than pending. */
.mig__step.is-past .mig__n { border-color: var(--cyan-dim); color: var(--cyan-ink); }

.mig__panel {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface-2);
  padding: clamp(1.25rem, 2.5vw, 1.85rem);
}

.mig__h {
  font-family: var(--display);
  font-size: clamp(1.25rem, 2.2vw, 1.55rem);
  letter-spacing: -0.02em;
  color: var(--cyan-ink);
}

.mig__lead {
  margin-top: 0.7rem;
  color: var(--ink);
  font-size: 1.02rem;
  max-width: 60ch;
  text-wrap: pretty;
}

.mig__facts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2.5vw, 2rem);
  margin-top: 1.6rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}

.mig__k {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 0.55rem;
}

.mig__v { font-size: 0.92rem; color: var(--ink-2); text-wrap: pretty; }

@media (max-width: 820px) {
  .mig__facts { grid-template-columns: 1fr; gap: 1.2rem; }
}

@media (max-width: 680px) {
  /* The rail becomes a swipeable strip rather than six crushed columns. */
  .mig.is-tabbed .mig__rail {
    display: flex;
    overflow-x: auto;
    gap: 0.4rem;
    padding-bottom: 0.5rem;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
  }
  .mig.is-tabbed .mig__rail::before { display: none; }
  .mig__rail li { flex: 0 0 auto; scroll-snap-align: center; }
  .mig__step {
    grid-template-columns: auto auto;
    justify-items: start;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.85rem 0.4rem 0.4rem;
    border: 1px solid var(--line);
    border-radius: 100px;
  }
  .mig__n { width: 30px; height: 30px; font-size: 0.66rem; }
  .mig__t { font-size: 0.85rem; }
  .mig__step[aria-selected="true"] { border-color: var(--cyan); }
}

/* --- FAQ ----------------------------------------------------------------- */

.faq { border-top: 1px solid var(--line); }

.faq details { border-bottom: 1px solid var(--line); }

.faq summary {
  display: flex; align-items: flex-start; gap: 1rem;
  padding-block: 1.4rem;
  cursor: pointer;
  list-style: none;
  font-family: var(--display);
  font-size: clamp(1.05rem, 1.8vw, 1.25rem);
  letter-spacing: -0.015em;
  line-height: 1.35;
  color: var(--ink);
  transition: color 0.25s var(--ease);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--cyan-ink); }

.faq summary::after {
  content: "";
  margin-left: auto; flex: none;
  width: 10px; height: 10px;
  margin-top: 0.45em;
  border-right: 1.5px solid var(--cyan-dim);
  border-bottom: 1.5px solid var(--cyan-dim);
  transform: rotate(45deg);
  transition: transform 0.3s var(--ease);
}
.faq details[open] summary::after { transform: rotate(-135deg); }

.faq__a { padding-bottom: 1.5rem; color: var(--ink-2); max-width: 62ch; text-wrap: pretty; }
.faq__a > * + * { margin-top: 0.9rem; }

/* --- Form ---------------------------------------------------------------- */

.form { display: grid; gap: 1.15rem; }
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 1.15rem; }
@media (max-width: 620px) { .form__row { grid-template-columns: 1fr; } }

.field { display: grid; gap: 0.45rem; }
.field label {
  font-family: var(--mono);
  font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-2);
}
.field .req { color: var(--amber-ink); }

.field input, .field select, .field textarea {
  font: inherit; font-size: 0.97rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--r);
  padding: 0.85rem 0.95rem;
  width: 100%;
  transition: border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.field textarea { resize: vertical; min-height: 8rem; line-height: 1.6; }
.field select { appearance: none; cursor: pointer; }

.field input::placeholder, .field textarea::placeholder { color: var(--ink-3); }

.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--cyan-dim);
  box-shadow: 0 0 0 3px rgba(19, 189, 207, 0.14);
}

.hp {
  position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}

.form__msg {
  padding: 0.9rem 1.1rem;
  border: 1px solid rgba(31, 132, 92, 0.35);
  background: rgba(31, 132, 92, 0.08);
  border-radius: var(--r);
  color: var(--mint-ink);
  font-size: 0.92rem;
}
.form__msg[hidden] { display: none; }

.form__where {
  font-size: 0.85rem;
  color: var(--ink-3);
  text-wrap: pretty;
}

/* --- Contact detail rows ------------------------------------------------- */

.facts { display: grid; }
.fact {
  display: grid;
  grid-template-columns: minmax(7rem, 0.45fr) minmax(0, 1fr);
  gap: 1rem;
  padding-block: 0.95rem;
  border-bottom: 1px solid var(--line);
  align-items: baseline;
}
.fact:first-child { border-top: 1px solid var(--line); }
.fact__k {
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-3);
}
.fact__v { color: var(--ink); text-wrap: pretty; }
.fact__v a {
  color: var(--cyan-ink);
  /* Nudges the tap height past the 24px minimum without shifting the row. */
  display: inline-block;
  padding-block: 0.15rem;
}
.fact__v a:hover { color: var(--cyan-dim); }

@media (max-width: 520px) { .fact { grid-template-columns: 1fr; gap: 0.2rem; } }

/* --- Footer -------------------------------------------------------------- */

.ftr {
  border-top: 1px solid var(--line);
  padding-block: clamp(3rem, 6vw, 4.5rem) 2rem;
  font-size: 0.92rem;
  color: var(--ink-2);
}

/* The footer sits directly under the dark contact band with no divider
   between them, so it carries the same dark ground rather than the page's
   white, closing the page on the same register it opened on. It picks up
   .section--dark for its text tokens (borders, links, secondary copy) and
   only needs this one explicit override, because .ftr's own background
   above would otherwise win: two same-specificity rules on one element
   resolve by source order, and leaving that implicit is asking for the
   footer to silently go light again the next time either rule moves. */
.ftr.section--dark { background: #0A1420; border-top-color: var(--line); }

.ftr__top {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(2, minmax(0, 1fr));
  gap: clamp(2rem, 4vw, 3rem);
  padding-bottom: clamp(2.5rem, 5vw, 3.5rem);
}
@media (max-width: 780px) { .ftr__top { grid-template-columns: 1fr 1fr; } }
@media (max-width: 500px) { .ftr__top { grid-template-columns: 1fr; } }

.ftr__blurb { margin-top: 1.1rem; max-width: 28rem; color: var(--ink-3); font-size: 0.9rem; }
.ftr__h {
  font-family: var(--mono);
  font-size: 0.68rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-3); margin-bottom: 1.1rem;
}
.ftr ul { display: grid; gap: 0.65rem; }
.ftr a:hover { color: var(--cyan-ink); }

/* On touch screens the footer links are the smallest targets on the page.
   Text at this size is only ~19px tall, so padding brings each one up past the
   44px minimum without changing how the list looks. */
@media (max-width: 780px) {
  .ftr ul { gap: 0; }
  .ftr ul li a {
    display: block;
    padding-block: 0.8rem;
  }
  .ftr ul li:not(:has(a)) { padding-block: 0.35rem; }
}

.ftr__btm {
  border-top: 1px solid var(--line);
  padding-top: 1.75rem;
  display: flex; flex-wrap: wrap; gap: 0.75rem 2rem;
  justify-content: space-between;
  font-size: 0.8rem; color: var(--ink-3);
}
.ftr__legal { max-width: 64ch; text-wrap: pretty; }

/* --- Reveal -------------------------------------------------------------- */

/* Content is visible by default and is only hidden once JS has confirmed it
   can put it back. If the script is blocked, errors, or never arrives, the
   page still reads in full rather than going blank below the hero. */
.js-rv .rv {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}

.js-rv .rv.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .js-rv .rv { opacity: 1; transform: none; }
}

/* --- Ambient section glow ------------------------------------------------ */

.glow-top { position: relative; }
.glow-top::before {
  content: "";
  position: absolute; top: 0; left: 50%;
  width: min(900px, 90vw); height: 500px;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(19,189,207,0.12), transparent 65%);
  pointer-events: none;
  z-index: -1;
}

/* --- Dark section variant -------------------------------------------------
   The hero is not the only place the brand gets to be dark. A handful of
   sections carry it further down the page for rhythm: the three deadlines,
   the AI governance band, and the closing call to action. Everything inside
   them retheme automatically, because every card, stat, panel, form field
   and label already reads its colour through a token rather than a literal.
   Redefine eleven names here and the whole subtree follows. */

.section--dark {
  /* A literal, not var(--ink): --ink is one of the names this rule redefines
     below, and CSS resolves var(--ink) against the value it has on THIS
     element, not the value it had before this rule ran. Referencing it here
     would pick up its own new light value and paint the section white. */
  background: #0A1420;
  color: #F5F7FA;

  --surface:   #111B2D;
  --surface-2: #16233A;
  --surface-3: #1C2C46;

  --ink:    #F5F7FA;
  --ink-2:  rgba(245, 247, 250, 0.76);
  --ink-3:  rgba(245, 247, 250, 0.56);

  --line:   rgba(245, 247, 250, 0.14);
  --line-2: rgba(245, 247, 250, 0.26);

  /* On white these three exist because the full-strength brand colours fail
     small text there. On dark that problem never arises, so the "text-safe"
     name resolves back to the vivid colour itself. */
  --cyan-ink:  var(--cyan);
  --amber-ink: var(--amber);
  --mint-ink:  var(--mint);

  /* A dark drop-shadow under a dark card is invisible. Cards on dark ground
     separate by a lightened border and a glow on hover instead, the same way
     they did before this palette existed. */
  --shadow-card: none;
  --shadow-card-hover: 0 0 0 1px rgba(245, 247, 250, 0.1);
}

/* Buttons are the one component with no colour token to redefine, since
   .btn--primary is deliberately ink-on-white so it reads on every light
   section. On dark ground it borrows the hero's own treatment instead. */
.section--dark .btn--primary { background: var(--cyan); color: #04222E; }
.section--dark .btn--primary:hover { box-shadow: 0 10px 26px -10px rgba(19,189,207,0.5); }
.section--dark .btn--ghost { border-color: rgba(245,247,250,0.3); color: #F5F7FA; }
.section--dark .btn--ghost:hover { border-color: var(--cyan); color: var(--cyan); background: rgba(19,189,207,0.1); }

/* The ambient cyan wash reads differently on dark: worth a touch more so it
   still registers as the same soft highlight rather than vanishing. */
.section--dark.glow-top::before { background: radial-gradient(circle, rgba(19,189,207,0.16), transparent 65%); }

/* .mig__step, the migration rail's numbered circles, are never used inside a
   dark section today, so no override is written for them; if that changes,
   they inherit --surface / --ink-3 like everything else and need nothing
   extra. */

@media print {
  .hdr, .cue, .hero__canvas, .burger { display: none !important; }
  body { background: #fff; color: #000; }
  .hero__track { height: auto !important; }
  .hero__stage { position: static; height: auto; }
}
