/* ============================================================
   Xterion — credibility site
   Single fixed screen. Selecting a nav item transitions a panel
   into view (no scrolling). Echoes the live brand:
   bg #0A0F1E · cyan #00bcd4 · Sora + Inter · glowing logo.
   ============================================================ */

:root {
  --bg:        #0A0F1E;
  --line:      #1e2a3a;
  --line-2:    #16202f;
  --accent:    #00bcd4;
  --accent-2:  #4dd6e8;
  /* Violet from the overview deck — the far end of the logo's cyan-to-magenta
     gradient. Reserved for the problem statement, never for Xterion's own
     capabilities, which stay cyan. */
  --accent-alt: #a78bfa;
  --text:      #c8d6e5;
  --text-soft: #93a4ba;
  --text-faint:#5a6b80;

  --maxw: 1080px;
  --pad: clamp(20px, 5vw, 48px);
  --header-h: 76px;
  --local-nav-h: 56px;
  --footer-h: 56px;

  --display: 'Sora', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

* { box-sizing: border-box; }

html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--body);
  color: var(--text);
  background: var(--bg);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow: hidden;                 /* no page scroll — views swap in place */
}

.container {
  width: 100%; max-width: var(--maxw); margin: 0 auto;
  padding-left: var(--pad); padding-right: var(--pad);
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-2); }

.skip-link {
  position: absolute; left: -9999px; top: 0;
  background: var(--accent); color: #04222a; padding: 10px 16px;
  z-index: 300; font-weight: 600;
}
.skip-link:focus { left: 12px; top: 12px; }

/* ---- Persistent ambient background ---- */
.bg { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.bg-glow { position: absolute; border-radius: 50%; transition: opacity 0.8s ease; }
.bg-glow-core {
  top: 42%; left: 50%; transform: translate(-50%, -50%);
  width: 820px; height: 820px;
  background: radial-gradient(circle, rgba(0,188,212,0.15) 0%, rgba(0,188,212,0.045) 38%, transparent 68%);
  filter: blur(10px);
}
.bg-glow-b {
  bottom: -240px; right: -140px; width: 600px; height: 600px;
  background: radial-gradient(circle, rgba(45,106,163,0.16) 0%, transparent 68%);
  filter: blur(18px);
}
.bg-grid {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(to right, rgba(255,255,255,0.022) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255,255,255,0.022) 1px, transparent 1px);
  background-size: 62px 62px;
  mask-image: radial-gradient(ellipse 78% 70% at 50% 45%, #000 30%, transparent 80%);
  -webkit-mask-image: radial-gradient(ellipse 78% 70% at 50% 45%, #000 30%, transparent 80%);
}

/* ---- Header ---- */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100; height: var(--header-h);
  display: flex; align-items: center;
  /* Opaque, not a fade to transparent. The gradient was designed when no panel
     ever scrolled, so nothing passed behind the chrome. Panels do scroll now
     (a phone cannot fit the hero), and a bar that fades to nothing let the
     copy slide visibly through it. Blur covers the decorative glows behind. */
  /* Fully opaque, and deliberately no backdrop-filter. At 97% the blur was
     contributing about 3% of anything, but it forced the header into a
     composited layer — and inside one, a child whose visibility flips via an
     ancestor attribute change can fail to repaint on iOS Safari. That is what
     left the brand logo on screen after navigating home from a section: a
     fresh load painted correctly, the dynamic change did not invalidate. */
  background: var(--bg);
}
.header-inner { display: flex; align-items: center; justify-content: space-between; width: 100%; }
.brand { display: inline-flex; }
.brand-logo { height: 40px; width: auto; display: block; }
/* The header used to hide entirely on home, since the hero carried the logo and
   the two CTAs covered Platform/Contact. The section nav is global now and the
   hero is down to one CTA, so the chrome has to stay — but the logo would be a
   second, smaller copy of the hero lockup, so that alone still hides. */
.brand { transition: opacity 0.4s ease; }
html[data-view="home"] .brand,
html[data-view="home"] .brand-logo { opacity: 0; visibility: hidden; pointer-events: none; }

.nav { display: flex; align-items: center; gap: clamp(16px, 3vw, 34px); }
.nav a {
  font-size: 0.95rem; font-weight: 500; color: var(--text-soft);
  transition: color 0.2s ease; position: relative;
}
.nav a:hover { color: var(--text); }
.nav a[aria-current="true"] { color: var(--accent); }
.nav-cta {
  border: 1px solid var(--line); border-radius: 7px; padding: 9px 20px;
  color: var(--text) !important;
  transition: border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
}
.nav-cta:hover { border-color: var(--accent); color: var(--accent) !important; box-shadow: 0 0 24px rgba(0,188,212,0.18); }
.nav-cta[aria-current="true"] { border-color: var(--accent); color: var(--accent) !important; }
@media (max-width: 560px) { .nav a:not(.nav-cta) { display: none; } }

/* ---- Stage + views (the swap mechanism) ---- */
.stage { position: fixed; inset: 0; z-index: 10; }

.view {
  position: absolute; inset: 0;
  display: flex; align-items: safe center; justify-content: center;
  padding: calc(var(--header-h) + var(--local-nav-h) + 16px) 0 calc(var(--footer-h) + 16px);
  opacity: 0; visibility: hidden;
  transform: translateY(18px) scale(0.992);
  transition: opacity 0.5s var(--ease), transform 0.55s var(--ease), visibility 0s linear 0.55s;
  pointer-events: none;
  overflow-y: auto;                 /* graceful fallback if a panel is taller than the screen */
}
.view.is-active {
  opacity: 1; visibility: visible; transform: none; pointer-events: auto;
  transition: opacity 0.55s var(--ease), transform 0.6s var(--ease), visibility 0s;
}
.view[hidden] { display: flex; }    /* keep flex layout; visibility handles hide */

.view-inner { width: 100%; text-align: center; }

/* staggered child entrance, re-fired each time a view activates */
.v-item { opacity: 0; transform: translateY(20px); }
.view.is-active .v-item {
  opacity: 1; transform: none;
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
  transition-delay: calc(0.08s + var(--i, 0) * 0.07s);
}

@media (prefers-reduced-motion: reduce) {
  .view, .view.is-active, .v-item, .view.is-active .v-item { transition: none !important; }
  .v-item { opacity: 1; transform: none; }
}

/* ---- Typographic primitives ---- */
.kicker, .eyebrow {
  font-size: 0.8rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--accent); font-weight: 600; margin: 0 0 18px;
}
.kicker { margin-bottom: clamp(8px, 1.5vh, 18px); }
/* Narrow screens break the kicker mid-phrase — "PENSION RIS / TRANSFER" — so
   below the width where it fits on one line the two halves stack instead, and
   the separating dot goes with the single line it belonged to. */
@media (max-width: 480px) {
  .kicker span { display: block; }
  .kicker .kicker-sep { display: none; }
}
.display-title {
  font-family: var(--display); font-weight: 700;
  font-size: clamp(2rem, 4.6vw, 3.4rem);
  line-height: 1.12; letter-spacing: -0.02em;
  color: #eaf2fb; margin: 0 auto 22px; max-width: 20ch;
  /* Evens the two lines rather than filling the first and orphaning the
     rest — "Not the / bottleneck." split awkwardly without this. */
  text-wrap: balance;
}
.display-title.sm { font-size: clamp(1.7rem, 3.4vw, 2.5rem); margin-bottom: 16px; }
/* Home hero: two full statements rather than a short tagline. At the section
   titles' scale the first statement alone overruns the 880px hero column, so
   this takes a smaller cap and drops the 20ch measure, with each statement
   set on its own line. */
.hero-statement { max-width: none; font-size: clamp(1.4rem, 2.95vw, 2.2rem); }
/* The two statements are separate sentences, not one heading. They used to be
   two block spans inside a single h1, which gave that h1 an accessible name of
   both sentences run together — the reading crawlers and screen readers got.
   They are now an h1 and a paragraph; this closes the gap between them so the
   rendering is unchanged. */
.display-title.hero-statement--lead { margin-bottom: 0; }
/* The hero paragraph now runs ~9 lines. Centred, every line starts at a
   different x and the eye has to hunt for each one — fine for the three-line
   paragraph this replaced, a real cost at this length. Set flush left at a
   measure wide enough that its left edge lands on the headline's, while the
   composition around it stays centred. */
.home-inner .lead { max-width: 62ch; margin-bottom: clamp(14px, 2.4vh, 30px); }
.grad {
  background: linear-gradient(100deg, var(--accent) 0%, #6fe3f0 50%, #5aa2d6 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.lead {
  font-size: clamp(1.04rem, 1.7vw, 1.22rem);
  color: var(--text-soft); max-width: 60ch; margin: 0 auto 34px;
  /* Stops the paragraph ending on a stranded word or two. Ignored by
     browsers that don't support it, which just get the default wrap. */
  text-wrap: pretty;
}
.lead.center { margin-left: auto; margin-right: auto; }
/* The Capabilities lead is a single sentence that reads best unbroken. The
   60ch measure that keeps longer paragraphs readable was splitting it in two,
   with room to spare in the container — so this one lead takes the container's
   width and still wraps on its own once the screen is genuinely too narrow. */
.view-capabilities .lead { max-width: none; }
/* The problem statement that sets up the headline. Deliberately stays INSIDE
   the lead paragraph and in the body face: on its own line in the display face
   it mirrored the headline's structure (short pair, second half in a
   contrasting colour) and read as a second tagline competing with the first,
   rather than as the substance behind it. Colour and weight carry the emphasis
   instead. The violet is the deck's, and the only non-cyan accent on the site,
   so the constraint reads as distinct from everything Xterion offers in cyan. */
.lead-open { color: #eaf2fb; font-weight: 600; }
.lead-open-alt { color: var(--accent-alt); font-weight: 600; }

/* ---- Home view ---- */
/* Was 880px for a hero that was only type, and --maxw (1080) is still too narrow
   for five columns: at 984px of content a column holds 169px and "Onboard with
   precision" needs 188px, so the label wrapped and its description fell out of
   line with its neighbours. 1240px gives each column 201px. Home is the only
   view that runs wider than --maxw, and the pillar row is why. */
.home-inner { max-width: 1240px; }
.home-logo {
  width: clamp(230px, min(30vw, 33vh), 400px); height: auto; margin: 0; display: block;
  filter: drop-shadow(0 0 50px rgba(0,188,212,0.28));
}

/* ---- Trademark symbol ----
   On the hero lockup only. The header logo is 40px tall, which leaves the
   wordmark a cap height of ~11px and the symbol about 4px to render in — below
   what it can resolve as anything but a blob. Marking the primary lockup is
   the convention, and satisfies notice without repeating on every instance.

   Text rather than baked into the PNG so it scales with the hero's clamp.
   Offsets are measured from the artwork, not guessed — in the 546x148 image
   the wordmark cap band runs y 54..94 (36.5% to 63.5% of height) and the N's
   right edge sits at x 531 (97.25% of width). */
.lockup { position: relative; display: inline-block; line-height: 0; }
.lockup--hero { display: block; width: fit-content; margin: 0 auto clamp(12px, 2.4vh, 30px); }

.tm {
  position: absolute;
  left: 97.25%;          /* right edge of the N */
  top: 36.5%;            /* cap top of the wordmark */
  line-height: 1;
  font-family: var(--body); font-weight: 500;
  color: #dbe7f3;
  user-select: none; pointer-events: none;
  white-space: nowrap;
}
/* Sized so the glyph lands near 35-40% of the wordmark's cap height, which is
   27% of the logo box. At the hero's 430px max that cap is ~31px, so ~12px of
   glyph — and the TM character renders at roughly half its font-size. */
.lockup--hero .tm { font-size: clamp(15px, 2vw, 26px); margin-left: 5px; }
.triad {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center;
  gap: 8px 22px; margin: 0 auto 34px; max-width: 720px;
}
.triad span {
  font-family: var(--display); font-weight: 600;
  font-size: clamp(0.92rem, 1.5vw, 1.06rem); color: #dbe7f3; letter-spacing: -0.005em;
  position: relative;
}
.triad span:not(:last-child)::after {
  content: ''; position: absolute; right: -12px; top: 50%; transform: translateY(-50%);
  width: 5px; height: 5px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 10px rgba(0,188,212,0.7);
}
@media (max-width: 560px) { .triad span:not(:last-child)::after { display: none; } }

/* Top margin so the CTA is not flush against the veterans panel above it. */
.actions {
  display: flex; flex-wrap: wrap; gap: 14px; justify-content: center;
  margin: clamp(14px, 2.4vh, 30px) 0 0;
}
.micro {
  font-size: 0.78rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--text-faint); margin: 0;
}
.btn {
  display: inline-block; font-family: var(--body);
  font-size: 1rem; font-weight: 600; padding: 13px 30px;
  border-radius: 8px; border: 1px solid transparent;
  transition: transform 0.18s var(--ease), background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}
.btn-primary { background: var(--accent); color: #04222a; }
.btn-primary:hover { background: var(--accent-2); color: #04222a; transform: translateY(-2px); box-shadow: 0 10px 34px rgba(0,188,212,0.3); }
/* The border was on --line (#1e2a3a), the hairline used for dividers, which
   sits at 1.32:1 against the background and effectively disappears. A control
   boundary needs 3:1 under WCAG 1.4.11; #4f6a8e gives 3.44:1. With a faint
   fill it reads as a button while staying subordinate to the filled primary. */
.btn-ghost {
  border-color: #4f6a8e; color: var(--text);
  background: rgba(255,255,255,0.03);
}
.btn-ghost:hover {
  border-color: var(--accent); color: var(--accent);
  background: rgba(0,188,212,0.06);
  transform: translateY(-2px);
}

/* ---- Capabilities view ---- */
.cards {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(16px, 2vw, 24px);
  margin-top: 8px; text-align: left;
}
@media (max-width: 820px) { .cards { grid-template-columns: 1fr; max-width: 460px; margin-inline: auto; } }
.card {
  background: linear-gradient(180deg, rgba(255,255,255,0.03), rgba(255,255,255,0.01));
  border: 1px solid var(--line); border-radius: 14px; padding: clamp(22px, 2.6vw, 30px);
}
/* Hover thickens the type and moves nothing else. The box is deliberately
   untouched: it was the outline shifting that made a static card feel
   clickable, since a bordered tile changing its edge is button vocabulary.
   Type weight is not — it reads as emphasis, not as a target.

   Faux weight via text-shadow rather than font-weight. A real weight change
   re-measures the glyphs: at 820, 1060 and 1140px it rewraps the paragraph and
   grows the card 25px — a whole line — under the cursor, jolting the grid row.
   text-shadow cannot affect layout, so the effect is identical at every width. */
.card-num, .card h3, .card p { transition: text-shadow 0.2s ease; }
.card:hover .card-num, .card:hover h3, .card:hover p { text-shadow: 0 0 0.45px currentColor; }
.card-num { font-family: var(--display); font-size: 0.9rem; font-weight: 700; color: var(--accent); letter-spacing: 0.1em; margin-bottom: 16px; }
.card h3 { font-family: var(--display); font-weight: 600; font-size: 1.18rem; margin: 0 0 10px; color: #eaf2fb; letter-spacing: -0.01em; }
.card p { margin: 0; color: var(--text-soft); font-size: 0.97rem; line-height: 1.6; }

/* ---- Lifecycle flow (Capabilities) ----
   Four stages: icon, title, then what happens in it. Monochrome cyan — the
   palette reserves violet for the problem statement and keeps capabilities in
   cyan, so the stages are distinguished by their icons, not by colour. Reading
   order carries the sequence; the numbers it used to carry were redundant with
   that and with the titles. */
.flow {
  list-style: none; margin: clamp(20px, 2.6vw, 30px) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 0; text-align: left;
}
/* Hairlines between columns rather than boxes around them: four bordered cards
   would read as tiles and compete with the panels on other views. */
.flow-stage { padding: 0 clamp(12px, 1.4vw, 20px); }
.flow-stage + .flow-stage { border-left: 1px solid var(--line-2); }
.flow-icon {
  display: block; width: 46px; height: 46px; margin: 0 auto 12px;
  fill: none; stroke: url(#icon-grad); stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round;
}
.flow-title {
  margin: 0 0 12px; text-align: center;
  font-family: var(--display); font-weight: 600; font-size: 1.02rem;
  color: #eaf2fb; letter-spacing: -0.01em;
}
.flow-items { list-style: none; margin: 0; padding: 0; }
.flow-items li {
  position: relative; padding: 0 0 9px 17px; margin-bottom: 9px;
  border-bottom: 1px solid var(--line-2);
  font-size: 0.87rem; line-height: 1.5; color: var(--text-soft);
}
.flow-items li:last-child { border-bottom: 0; margin-bottom: 0; padding-bottom: 0; }
.flow-items li::before {
  content: ''; position: absolute; left: 0; top: 8px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
}

/* The assurance bar: what holds true across every stage above. */
.flow-assurance {
  display: grid; grid-template-columns: repeat(4, 1fr);
  margin: clamp(18px, 2.2vw, 26px) 0 0;
  border: 1px solid var(--line); border-radius: 12px;
  background: rgba(255,255,255,0.015); text-align: left;
}
.assurance-item {
  display: flex; align-items: center; gap: 12px; margin: 0;
  padding: 14px clamp(12px, 1.4vw, 18px);
  font-size: 0.86rem; line-height: 1.4; color: var(--text-soft);
}
.assurance-item + .assurance-item { border-left: 1px solid var(--line-2); }
.assurance-icon {
  flex: none; width: 30px; height: 30px;
  fill: none; stroke: url(#icon-grad); stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round;
}

/* Four columns need the container at its full 1080px: "Operate and understand"
   wants 201px and a quarter column gives 206px there, but only 196px once the
   container starts shrinking. Below that the title wraps and its list drops out
   of line with the other three, so two wide columns instead. */
@media (max-width: 1099px) {
  .flow { grid-template-columns: repeat(2, 1fr); gap: 26px 0; }
  .flow-stage:nth-child(odd) { border-left: 0; }
  .flow-assurance { grid-template-columns: repeat(2, 1fr); }
  .assurance-item:nth-child(odd) { border-left: 0; }
  .assurance-item:nth-child(n + 3) { border-top: 1px solid var(--line-2); }
}
@media (max-width: 620px) {
  .flow { grid-template-columns: 1fr; gap: 24px; }
  .flow-stage, .flow-stage:nth-child(n) { border-left: 0; padding: 0; }
  .flow-assurance { grid-template-columns: 1fr; }
  .assurance-item, .assurance-item:nth-child(n) { border-left: 0; }
  .assurance-item + .assurance-item { border-top: 1px solid var(--line-2); }
}

/* ---- Home: rule, pillars, veterans ---- */
/* The sprite only carries <defs> and <symbol>; nothing should render from it. */
.icon-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.hero-rule {
  display: block; width: 150px; height: 1px; margin: clamp(2px, 0.4vh, 4px) auto clamp(10px, 1.8vh, 20px);
  background: linear-gradient(90deg, rgba(0,188,212,0), var(--accent), rgba(0,188,212,0));
}

.pillars {
  list-style: none; margin: clamp(16px, 2.8vh, 34px) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(5, 1fr);
}
/* Hairlines between columns rather than around them — a border box per pillar
   would read as five cards and compete with the panels elsewhere. */
.pillar { padding: 0 clamp(8px, 1vw, 14px); }
.pillar + .pillar { border-left: 1px solid var(--line-2); }
.pillar-icon { display: block; width: 42px; height: 42px; margin: 0 auto 14px; }
.pillar-icon, .veterans-icon {
  fill: none; stroke: url(#icon-grad); stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round;
}
.pillar-name {
  margin: 0 0 6px; font-family: var(--display); font-weight: 600;
  font-size: 0.98rem; color: #eaf2fb; letter-spacing: -0.01em;
}
.pillar-desc { margin: 0; font-size: 0.86rem; line-height: 1.5; color: var(--text-soft); }

.veterans {
  display: flex; align-items: center; gap: clamp(14px, 2vw, 24px);
  margin: clamp(14px, 2.2vh, 28px) auto 0; padding: clamp(11px, 1.6vh, 16px) clamp(18px, 2.2vw, 26px);
  border: 1px solid var(--line); border-radius: 12px;
  background: rgba(255,255,255,0.015); text-align: left;
}
.veterans-icon { flex: none; width: 44px; height: 44px; }
.veterans-copy { border-left: 1px solid var(--line-2); padding-left: clamp(14px, 2vw, 22px); }
.veterans-title {
  margin: 0 0 4px; font-family: var(--display); font-weight: 600;
  font-size: 1rem; color: #eaf2fb;
}
.veterans-desc { margin: 0; font-size: 0.9rem; line-height: 1.55; color: var(--text-soft); }

/* Five columns need 1200px to hold "Onboard with precision" on one line; below
   that the label wraps and its description drops out of line with its
   neighbours. Three wide columns beat five cramped ones. */
@media (max-width: 1199px) {
  .pillars { grid-template-columns: repeat(3, 1fr); gap: 26px 0; }
  /* With rows, a left border on every item but the first draws a line at the
     start of row two. Reset per row instead. */
  .pillar + .pillar { border-left: 1px solid var(--line-2); }
  .pillar:nth-child(3n + 1) { border-left: 0; }
}
@media (max-width: 700px) {
  .pillars { grid-template-columns: repeat(2, 1fr); gap: 24px 0; }
  .pillar:nth-child(3n + 1) { border-left: 1px solid var(--line-2); }
  .pillar:nth-child(odd) { border-left: 0; }
}
@media (max-width: 460px) {
  .pillars { grid-template-columns: 1fr; gap: 20px; }
  .pillar, .pillar:nth-child(n) { border-left: 0; padding: 0; }
  .veterans { flex-direction: column; align-items: flex-start; gap: 12px; }
  .veterans-copy { border-left: 0; padding-left: 0; }
}

/* Laptop-height step. The vh clamps above carry most of it, but a 768px screen
   is ~90px short once the pillar row is in, so the icons, the display type and
   the supporting copy all come down a notch rather than any one of them
   collapsing. */
@media (max-height: 880px) {
  .home-logo { width: clamp(200px, min(26vw, 27vh), 330px); }
  .hero-statement { font-size: clamp(1.28rem, 2.4vw, 1.92rem); }
  .home-inner .lead { font-size: 0.98rem; }
  .pillar-icon { width: 34px; height: 34px; margin-bottom: 9px; }
  .pillar-name { font-size: 0.93rem; margin-bottom: 4px; }
  .pillar-desc { font-size: 0.82rem; line-height: 1.42; }
  .veterans-icon { width: 36px; height: 36px; }
  .veterans-title { font-size: 0.95rem; }
  .veterans-desc { font-size: 0.86rem; }
  .veterans { padding-top: 11px; padding-bottom: 11px; }
  .pillars { margin-top: clamp(14px, 2.2vh, 28px); }
  .actions { margin-top: clamp(12px, 2vh, 26px); }
}

/* 768px laptops need one more notch; below this the phone rules take over. */
@media (max-height: 790px) {
  .home-logo { width: clamp(190px, min(24vw, 25vh), 300px); }
  .hero-statement { font-size: clamp(1.2rem, 2.2vw, 1.8rem); }
  .pillar-icon { width: 30px; height: 30px; margin-bottom: 8px; }
  .pillar-desc { font-size: 0.8rem; }
  .kicker { margin-bottom: clamp(6px, 1.1vh, 12px); }
  .veterans-icon { width: 32px; height: 32px; }
}

/* ---- Platform-family local nav ----
   Section navigation shared by Overview, In Action, Integration and Operating
   Model. Deliberately quieter than the global nav — smaller, tracked, muted —
   so it reads as "parts of this section" rather than a second main nav. */
.local-nav {
  position: fixed; top: var(--header-h); left: 0; right: 0; z-index: 90;
  display: flex; align-items: center;
  height: var(--local-nav-h);
  border-bottom: 1px solid var(--line-2);
  background: var(--bg);
}
.local-nav-inner {
  display: flex; flex-wrap: wrap; justify-content: center;
  align-items: center; gap: 2px clamp(4px, 1.2vw, 12px);
}
/* Shown, and the panel padded to clear it, only on the four family views.
   data-view is stamped on <html> by the router. */
.local-nav a {
  position: relative;
  font-size: 0.75rem; font-weight: 500;
  letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--text-soft);
  padding: 6px 10px; border-radius: 6px;
  transition: color 0.2s ease, background 0.2s ease;
  white-space: nowrap;
}
.local-nav a:hover { color: var(--text-soft); background: rgba(255,255,255,0.035); }
/* Underline rather than a filled pill: the pill read as a button in a row of
   plain text links, and this is a state, not a control. */
.local-nav a[aria-current="page"] { color: var(--accent); }
.local-nav a[aria-current="page"]::after {
  content: ''; position: absolute; left: 8px; right: 8px; bottom: -7px;
  height: 2px; border-radius: 2px; background: var(--accent);
}
.local-nav a:focus-visible { outline: 1px solid var(--accent); outline-offset: 1px; }

/* Hairline separators between items, suppressed at the ends and when wrapped
   onto a new line would leave one dangling. */
.local-nav a + a::before {
  content: ''; position: absolute; left: calc(-1 * clamp(6px, 1.4vw, 14px) / 2);
  top: 50%; transform: translateY(-50%);
  width: 1px; height: 10px; background: var(--line);
}
@media (max-width: 560px) {
  .local-nav-inner { gap: 2px 4px; }
  .local-nav a { font-size: 0.66rem; letter-spacing: 0.1em; padding: 5px 7px; }
  .local-nav a + a::before { display: none; }
}

/* ---- Mobile menu ---- */
/* Hidden above the breakpoint: the two desktop navs cover everything there. */
.nav-toggle {
  display: none; align-items: center; justify-content: center;
  width: 40px; height: 40px; padding: 0;
  background: none; border: 1px solid var(--line); border-radius: 8px;
  color: var(--text-soft); cursor: pointer;
}
.nav-toggle:hover { border-color: var(--accent); color: var(--accent); }
.nav-toggle:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }
.nav-toggle-box { display: block; width: 18px; height: 12px; position: relative; }
.nav-toggle-box span {
  position: absolute; left: 0; width: 100%; height: 1.5px; border-radius: 2px;
  background: currentColor;
  transition: transform 0.25s var(--ease), opacity 0.2s ease;
}
.nav-toggle-box span:nth-child(1) { top: 0; }
.nav-toggle-box span:nth-child(2) { top: 50%; transform: translateY(-50%); }
.nav-toggle-box span:nth-child(3) { bottom: 0; }
/* Bars fold into an X while the panel is open. */
[aria-expanded="true"] .nav-toggle-box span:nth-child(1) { top: 50%; transform: translateY(-50%) rotate(45deg); }
[aria-expanded="true"] .nav-toggle-box span:nth-child(2) { opacity: 0; }
[aria-expanded="true"] .nav-toggle-box span:nth-child(3) { bottom: 50%; transform: translateY(50%) rotate(-45deg); }

/* Drops from under the header. Fixed like the rest of the chrome, so it never
   scrolls with a panel underneath it. */
.mobile-nav {
  position: fixed; top: var(--header-h); left: 0; right: 0; z-index: 95;
  background: var(--bg);
  border-bottom: 1px solid var(--line-2);
}
.mobile-nav[hidden] { display: none; }
.mobile-nav-inner { display: flex; flex-direction: column; padding-top: 8px; padding-bottom: 14px; }
.mobile-nav a {
  padding: 13px 4px;
  font-family: var(--display); font-weight: 600; font-size: 0.95rem;
  color: var(--text-soft);
}
.mobile-nav a:hover { color: #eaf2fb; }
.mobile-nav a[aria-current="page"] { color: var(--accent); }
.mobile-nav a:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }
/* Separates the four sections from the two company links. */
.mobile-nav-rule { height: 1px; background: var(--line-2); margin: 8px 0; }

/* Below this width the two desktop navs would crowd each other, so both give
   way to the menu. Zeroing --local-nav-h also reclaims the padding every view
   was reserving for the section strip. */
@media (max-width: 760px) {
  :root { --local-nav-h: 0px; }
  .nav, .local-nav { display: none; }
  .nav-toggle { display: inline-flex; }
}

/* ---- Product view ----
   The screenshot is the section; the copy exists to frame it. Border and radius
   match .card so the frame reads as part of the existing system rather than a
   pasted-on image. Native 1433x877 (ratio 1.634) — width/height attributes plus
   aspect-ratio reserve the box so activating the view causes no layout shift. */
.shot { margin: clamp(22px, 3vw, 32px) auto 0; max-width: 900px; width: 100%; }
.shot img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 1433 / 877;
  border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 24px 60px rgba(0,0,0,0.55);
}
/* The inline render is ~63% of native, so the benefit-form table reads as shape
   rather than text. Full size opens in an overlay rather than a new tab: a bare
   image file loses the site frame entirely, which reads as unfinished. */
.shot-zoom { display: block; cursor: zoom-in; }
.shot figcaption {
  margin-top: 10px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--text-faint);
}
.shot figcaption a {
  color: var(--text-faint); letter-spacing: 0.14em;
  transition: color 0.2s ease;
}
.shot figcaption a:hover { color: var(--accent); }
@media (max-width: 560px) {
  .shot figcaption { flex-direction: column; gap: 6px; }
}
/* Shorter viewports: pull the image in so the framing copy stays on screen with
   it, rather than letting the panel scroll on a section that is one glance. */
@media (max-height: 900px) { .shot { max-width: 740px; margin-top: 18px; } }
@media (max-height: 780px) { .shot { max-width: 620px; margin-top: 14px; } }

/* ---- Full-size viewer ----
   Keeps the reader inside the site rather than dropping them on a bare image
   file. Sits above the header and footer (z 300 vs 100). body already carries
   overflow:hidden, so no scroll lock is needed. */
.lightbox {
  position: fixed; inset: 0; z-index: 300;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(46px, 6vw, 72px) clamp(16px, 4vw, 56px);
  background: rgba(6, 10, 20, 0.93);
  backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 0.25s var(--ease);
}
.lightbox.is-open { opacity: 1; }
/* Needed because .lightbox sets display:flex, which would otherwise defeat the
   hidden attribute. */
.lightbox[hidden] { display: none; }

.lightbox-img {
  max-width: 100%; max-height: 100%;
  width: auto; height: auto;
  border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 30px 90px rgba(0, 0, 0, 0.65);
}

.lightbox-close {
  position: absolute; top: clamp(12px, 2vw, 26px); right: clamp(12px, 2vw, 26px);
  width: 38px; height: 38px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--line); border-radius: 8px;
  color: var(--text); font-size: 1.5rem; line-height: 1; font-family: var(--body);
  cursor: pointer;
  transition: border-color 0.2s ease, color 0.2s ease, background 0.2s ease;
}
.lightbox-close:hover { border-color: var(--accent); color: var(--accent); background: rgba(0,188,212,0.07); }
.lightbox-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }


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

/* ---- Integration view ----
   Three positions relative to the carrier's system of record — upstream,
   parallel, downstream — then the event-driven note. */
.wrap-grid .card { padding: clamp(18px, 2vw, 24px); }
.wrap-grid .card-num { margin-bottom: 10px; font-size: 0.78rem; }
.wrap-grid .card h3 { font-size: 1.05rem; margin-bottom: 8px; }
.wrap-grid .card p { font-size: 0.9rem; line-height: 1.55; }



/* ---- Operating model view ----
   Four cards in 2x2 (mirrors the overview deck), then a single substrate
   line naming the cloud the platform runs on. The hosting detail is one
   line, not the subject of the view. */
.ops-grid { grid-template-columns: repeat(2, 1fr); }
.ops-grid .card { padding: clamp(18px, 2vw, 24px); }
.ops-grid .card-num { margin-bottom: 12px; font-size: 0.82rem; }
.ops-grid .card h3 { font-size: 1.08rem; margin-bottom: 8px; }
.ops-grid .card p { font-size: 0.92rem; line-height: 1.55; }
@media (max-width: 820px) { .ops-grid { grid-template-columns: 1fr; } }

.substrate {
  margin: clamp(18px, 2.4vw, 26px) 0 0;
  padding: 13px clamp(16px, 2vw, 20px);
  border: 1px solid var(--line); border-radius: 10px;
  background: rgba(255,255,255,0.015);
  color: var(--text-soft); font-size: 0.87rem; line-height: 1.55;
  text-align: left;
}
.substrate-row { display: flex; align-items: flex-start; gap: 11px; margin: 0; }
.substrate-row + .substrate-row {
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line-2);
}
.substrate strong { color: #eaf2fb; font-weight: 600; }
.substrate-dot {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  margin-top: 7px;
  background: #34d399; box-shadow: 0 0 10px rgba(52,211,153,0.6);
}
/* Hollow ring, not a filled dot: the filled green reads as "live", and this
   one is deliberately not claiming a completed state. */
.substrate-dot--pending {
  background: transparent; box-shadow: none;
  border: 1px solid var(--accent);
}

/* Short viewports: compress the denser views so they stay on one screen. */
@media (max-height: 820px) {
  .ops-grid .card { padding: 15px 18px; }
  .ops-grid .card-num { margin-bottom: 8px; font-size: 0.76rem; }
  .ops-grid .card h3 { font-size: 1rem; margin-bottom: 6px; }
  .ops-grid .card p { font-size: 0.86rem; line-height: 1.45; }
  .substrate { font-size: 0.8rem; padding: 11px 16px; margin-top: 16px; }

  .wrap-grid .card { padding: 15px 18px; }
  .wrap-grid .card h3 { font-size: 1rem; margin-bottom: 6px; }
  .wrap-grid .card p { font-size: 0.86rem; line-height: 1.45; }
}

/* ---- Contact view ---- */
.contact-link {
  display: inline-block; font-family: var(--display); font-weight: 600;
  font-size: clamp(1.5rem, 3.4vw, 2.3rem); color: var(--accent);
  padding-bottom: 6px; border-bottom: 1px solid rgba(0,188,212,0.3);
  transition: color 0.2s ease, border-color 0.2s ease, text-shadow 0.2s ease;
}
.contact-link:hover { color: var(--accent-2); border-color: var(--accent-2); text-shadow: 0 0 30px rgba(0,188,212,0.45); }

/* ---- Contact form ---- */
/* Left-aligned inside the centred panel, for the same reason the leadership
   bios are: labels and fields read badly when every row starts at a different
   x. The block itself stays centred. */
.contact-form {
  width: 100%; max-width: 520px; margin: 0 auto;
  display: flex; flex-direction: column; gap: 16px; text-align: left;
}
.field { display: flex; flex-direction: column; gap: 6px; }
.field label {
  font-size: 0.78rem; font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-soft);
}
.field input, .field textarea {
  width: 100%; font-family: var(--body); font-size: 0.98rem; color: var(--text);
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--line); border-radius: 8px;
  padding: 11px 13px;
  transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}
.field textarea { resize: vertical; min-height: 96px; }
.field input::placeholder, .field textarea::placeholder { color: var(--text-faint); }
.field input:hover, .field textarea:hover { border-color: #2b3b50; }
.field input:focus, .field textarea:focus {
  outline: none; border-color: var(--accent);
  background: rgba(0,188,212,0.05);
  box-shadow: 0 0 0 3px rgba(0,188,212,0.12);
}
/* Invalid state is driven by aria-invalid, which the script sets only after a
   field has actually been validated — never on an untouched empty field. */
.field input[aria-invalid="true"], .field textarea[aria-invalid="true"] {
  border-color: #e2725b;
}
.field-err { margin: 0; font-size: 0.78rem; color: #f0917c; }
.field-err[hidden] { display: none; }
/* Honeypot. Off-canvas rather than display:none, which some bots skip. */
.field-trap {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden; opacity: 0; pointer-events: none;
}
.contact-submit { align-self: flex-start; margin-top: 2px; }
.contact-submit[disabled] { opacity: 0.6; cursor: not-allowed; transform: none; box-shadow: none; }
.form-status { margin: 2px 0 0; font-size: 0.9rem; }
.form-status[hidden] { display: none; }
.form-status.is-ok { color: var(--accent-2); }
.form-status.is-err { color: #f0917c; }
/* The address is a fallback beside the form now, not the page's main event, so
   it drops from display size to body size. */
/* Label, address, phone stacked rather than run into a sentence — three lines
   read faster than one, and the phone stays tappable on its own row. */
.contact-alt {
  margin: 22px 0 0; font-size: 0.92rem; color: var(--text-faint);
  display: flex; flex-direction: column; align-items: center; gap: 5px;
}
.contact-alt-label { color: var(--text-faint); }
.contact-alt .contact-link {
  font-size: inherit; font-family: var(--body); font-weight: 500;
  padding-bottom: 1px;
}
/* The About heading is twelve words, where the other panel titles are six or
   eight. At the shared 20ch measure it broke into four lines and read as a
   paragraph rather than a title, so it takes the full container and a slightly
   smaller cap: two lines at 1440, and the clamp keeps it there as the viewport
   narrows. */
.view-about .display-title.sm {
  max-width: none;
  font-size: clamp(1.5rem, 3vw, 2.3rem);
}

/* About runs to real prose now, not a one-line lead. Body size rather than
   lead size, a reading measure, and flush left — six centred paragraphs would
   make the reader hunt for the start of every line. */
.about-prose {
  /* 84ch rather than the 66ch a shorter read would take. Six paragraphs at the
     narrower measure ran the panel 392px past a 1440x900 laptop; this cuts that
     to 262px by turning 20 lines into 16. Wider than the classic 45-75, but the
     type is small and the alternative is a third of the page below the fold.
     Past ~90ch the line count stops falling, so there is nothing to buy. */
  max-width: 84ch; margin: 0 auto; text-align: left;
  color: var(--text-soft); font-size: 0.98rem; line-height: 1.72;
}
/* The opening sentence is the thesis; the rest of that paragraph is the evidence
   for it. Set larger and brighter, inside the same box so its left edge matches
   the prose exactly. Not italic — the font request carries weights only, so
   font-style would synthesise a slant from the roman and read as a fault. */
.about-lede { font-size: 1.14rem; line-height: 1.55; color: var(--text); margin-bottom: 18px; }
.about-prose p { margin: 0 0 15px; }
.about-prose p:last-child { margin-bottom: 0; }
.about-prose strong { color: #eaf2fb; font-weight: 600; }
/* Sits above the hairline the leaders grid already draws. */
.leaders-head { margin: clamp(26px, 3.5vw, 38px) 0 0; }
.leaders-head + .leaders { margin-top: 12px; }
@media (max-width: 560px) {
  .about-prose { font-size: 0.9rem; line-height: 1.6; }
  .about-prose p { margin-bottom: 12px; }
}

/* Leadership block. Left-aligned inside a centred container: names and roles
   centre well, but a sentence of background reads badly ragged on both sides. */
.leaders {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: clamp(20px, 3vw, 40px);
  margin: clamp(26px, 3.5vw, 40px) auto 0;
  padding-top: clamp(20px, 2.6vw, 28px);
  border-top: 1px solid var(--line-2);
  max-width: 880px; text-align: left;
}
.leader-name {
  font-family: var(--display); font-weight: 600; font-size: 1.02rem;
  color: #eaf2fb; letter-spacing: -0.01em;
}
.leader-role {
  font-size: 0.75rem; color: var(--accent);
  letter-spacing: 0.14em; text-transform: uppercase; font-weight: 600;
  margin-top: 3px;
}
.leader-bio {
  margin: 10px 0 0; font-size: 0.87rem; line-height: 1.6;
  color: var(--text-soft); text-wrap: pretty;
}
@media (max-width: 640px) { .leaders { grid-template-columns: 1fr; } }
@media (max-height: 760px) {
  .leaders { margin-top: 20px; padding-top: 18px; }
  .leader-bio { font-size: 0.82rem; line-height: 1.5; margin-top: 8px; }
}

/* Sits directly above the footer bar, under the fixed chrome but over the
   panel, so a scrollable view fades out rather than being cut off mid-sentence.
   Driven by data-scrollcue on <html>; see app.js. */
.scroll-cue {
  position: fixed; left: 0; right: 0; bottom: var(--footer-h);
  height: 72px; z-index: 50; pointer-events: none;
  background: linear-gradient(to top, var(--bg), rgba(10,15,30,0));
  opacity: 0; transition: opacity 0.3s ease;
}
html[data-scrollcue="on"] .scroll-cue { opacity: 1; }

/* ---- Footer ---- */
.site-footer {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 100; height: var(--footer-h);
  display: flex; align-items: center;
  /* Opaque for the same reason as the header: content scrolls under it. No
     backdrop-filter, to keep the chrome out of composited layers. */
  background: var(--bg);
}
/* Was space-between, for the copyright/tagline pair. With the tagline retired
   the survivor sat pinned left, which read as leftover rather than chosen — and
   on home the header logo is hidden, so nothing shared that edge. Right instead:
   the footer and the header are the same .container, so the copyright lands on
   the exact right edge as the nav above it, on every view. */
.footer-inner {
  display: flex; align-items: center; justify-content: flex-end; width: 100%;
  /* The privacy link joins the copyright at the right edge rather than taking
     the vacant left one: two items at opposite ends re-created the stranded
     look that retiring the tagline fixed. Paired, they read as one line of
     fine print. */
  gap: clamp(14px, 2.5vw, 24px);
}
.footer-meta { color: var(--text-faint); font-size: 0.82rem; letter-spacing: 0.04em; }

/* Sized and coloured to match .footer-meta, not the cyan links in the panels:
   this is fine print that has to be findable, not an invitation. */
.footer-link {
  color: var(--text-faint); font-size: 0.82rem; letter-spacing: 0.04em;
  transition: color 0.2s ease;
}
.footer-link:hover, .footer-link:focus-visible { color: var(--accent-2); }
.footer-link:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }
.footer-link[aria-current] { color: var(--text-soft); }

@media (max-width: 560px) {
  .footer-meta, .footer-link { font-size: 0.72rem; }
}

/* ---- Privacy / legal prose ---- */
/* Narrower than .about-prose's 84ch: that measure exists to hold a six-
   paragraph story to as few lines as possible, whereas this is a reference
   document nobody reads end to end. Subheads do the wayfinding, so the
   comfortable measure wins and the panel is simply allowed to scroll. */
.legal-prose {
  max-width: 74ch; margin: 0 auto; text-align: left;
  color: var(--text-soft); font-size: 0.95rem; line-height: 1.7;
}
.legal-prose p { margin: 0 0 14px; }
.legal-prose p:last-child { margin-bottom: 0; }
.legal-prose strong { color: #eaf2fb; font-weight: 600; }
.legal-prose h3 {
  font-family: var(--display); font-size: 0.98rem; font-weight: 600;
  color: var(--text); margin: 26px 0 8px;
}
.legal-meta {
  color: var(--text-faint); font-size: 0.82rem; letter-spacing: 0.04em;
  text-transform: uppercase;
  padding-bottom: 16px; border-bottom: 1px solid var(--line-2);
}
.legal-link {
  color: var(--accent); border-bottom: 1px solid rgba(0,188,212,0.3);
  transition: color 0.2s ease, border-color 0.2s ease;
}
.legal-link:hover, .legal-link:focus-visible { color: var(--accent-2); border-color: var(--accent-2); }

@media (max-width: 560px) {
  .legal-prose { font-size: 0.88rem; line-height: 1.62; }
  .legal-prose h3 { margin-top: 22px; }
}

/* ---- Small / short phones: tighten the home view so the CTA buttons
   stay above the fold even on a 667px-tall screen (iPhone SE). ---- */
/* The hero paragraph is long, and on a phone it pushed the CTA down behind the
   fixed footer — 23px under it at 390px wide, 76px at 360px. The panel scrolls,
   so nothing was unreachable, but the button arrived half-hidden. Tightening
   the type and the gaps brings it back above the footer at rest.
   .triad is gone from the markup; its rule went with it. */
@media (max-width: 560px) {
  .home-logo { width: 190px; }
  .lockup--hero { margin-bottom: 16px; }
  .kicker { font-size: 0.7rem; letter-spacing: 0.14em; margin-bottom: 10px; }
  .hero-statement { font-size: 1.32rem; }
  .display-title { margin-bottom: 14px; }
  .lead { font-size: 0.9rem; line-height: 1.5; margin-bottom: 18px; }
  .actions { margin-bottom: 0; }
}

/* Short viewports (iPhone SE height, landscape phones): compress the home
   view harder so the CTA buttons stay visible without scrolling. */
/* This block used to keep the CTA above the fold on a 667px-tall phone. That
   was reachable when the hero paragraph ran three lines; at ~590 characters it
   is not, and shrinking type far enough to manage it would cost legibility for
   a fit that still would not arrive. So it compresses what it reasonably can
   and lets the shortest screens scroll — which is now clean, because the
   footer is opaque and the button no longer surfaces from behind it.
   .triad rules removed with the element. */
@media (max-height: 720px) {
  /* A shorter footer buys back clearance without touching type size: it moves
     the bar down and shrinks the padding each view reserves for it. */
  :root { --footer-h: 46px; }
  .home-logo { width: 168px; }
  .lockup--hero { margin-bottom: 10px; }
  .kicker { font-size: 0.68rem; margin-bottom: 8px; }
  .display-title { font-size: 1.85rem; margin-bottom: 12px; }
  .hero-statement { font-size: 1.22rem; }
  .lead { font-size: 0.86rem; line-height: 1.45; margin-bottom: 12px; }
}
