@charset "UTF-8";
/* ==========================================================================
   ElectroMech CloudTech — Bedrock · Kiro · Amazon Quick Suite micro-website
   --------------------------------------------------------------------------
   Tokens are lifted from the live theme on electromech.cloud (WordPress
   "gutenify-agency" global styles) so this page is visually continuous with
   the main domain when it is linked in or folded into it.

     --wp--preset--color--primary              #fb1f40
     --wp--preset--color--secondary            #031435
     --wp--preset--color--tertiary             #c3d9e7
     --wp--preset--color--body-text            #717171
     --wp--preset--color--background-secondary #f9faff
     --wp--preset--color--border               #f2f2f2
     --wp--preset--font-family--body           "Inter", sans-serif
     core button: radius 0 · padding 10px 40px · primary fill · navy hover

   Accessibility: white on #fb1f40 measures 3.91:1, which clears WCAG AA for
   large text but not for body copy or control labels. #fb1f40 is therefore
   kept as the visible brand accent (rules, marks, borders, underlines) and
   --red-ink (#d3102f, 5.41:1 on white) is used wherever red carries text.
   On the navy sections red is replaced by --red-soft (#ff8b9d, 8.17:1).
   ========================================================================== */

/* Inter is self-hosted in assets/css/fonts.css, generated by
   tools/fetch_fonts.py and linked from layouts/base.html.

   It used to be an @import of fonts.googleapis.com. That was a third-party,
   render-blocking request on every page, it disclosed every visitor to Google,
   and an @import inside CSS is invisible to any check that only inspects HTML
   attributes. Note also that the Google URL contains a semicolon inside its
   query string, which once truncated this very declaration and took the whole
   stylesheet down with it. */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Brand — inherited from electromech.cloud */
  --red: #fb1f40;
  --red-ink: #d3102f;      /* AA-safe red on white */
  --red-soft: #ff8b9d;     /* AA-safe red on navy  */
  --navy: #031435;
  --navy-700: #14315f;
  --navy-600: #1f4478;

  /* Neutrals */
  --ink: #0b1220;
  --body: #717171;   /* 4.88:1 on white, 4.68:1 on --paper-alt */
  /* Was #8a8f98, which measured 3.25:1 and failed WCAG AA everywhere it was
     used for small text (mono labels, table notes, form notes, .muted).
     #6b7280 holds 4.83:1 on white and 4.64:1 on --paper-alt. */
  --muted: #6b7280;
  --line: #e7e9ef;
  --line-soft: #f2f2f2;
  --paper: #ffffff;
  --paper-alt: #f9faff;

  /* AWS accent — service chips only */
  --aws-orange: #ec7211;

  /* Type */
  --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --font-mono: "SFMono-Regular", ui-monospace, Menlo, Consolas,
    "Liberation Mono", monospace;

  --fs-h1: clamp(2rem, 1.35rem + 2.6vw, 3.25rem);
  --fs-h2: clamp(1.625rem, 1.28rem + 1.4vw, 2.25rem);
  --fs-h3: clamp(1.1875rem, 1.09rem + 0.42vw, 1.4375rem);
  --fs-h4: clamp(1.0625rem, 1.02rem + 0.21vw, 1.1875rem);
  --fs-body: clamp(0.9688rem, 0.95rem + 0.1vw, 1.0313rem);
  --fs-sm: 0.875rem;
  --fs-xs: 0.8125rem;
  --fs-eyebrow: 0.75rem;

  --lh-tight: 1.16;
  --lh-head: 1.28;
  --lh-body: 1.75;

  /* Space */
  --gap: 1.5rem;
  --section-y: clamp(3.5rem, 2rem + 6vw, 6.5rem);
  --container: 1200px;

  /* Effects */
  --radius: 0px;           /* theme buttons are square */
  --radius-card: 2px;
  --shadow: 0 2px 4px rgba(3, 20, 53, 0.05), 0 12px 28px -14px rgba(3, 20, 53, 0.16);
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  --header-h: 84px;

  /* Entrance motion (section 18b). These four set the feel of the whole site.
     --motion-ease is flatter at the end than --ease, so things settle rather
     than arrive; it is the only entrance curve on the site. */
  --motion-dur: 520ms;
  --motion-step: 70ms;
  --motion-rise: 14px;
  --motion-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 16px);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--body);
  font-family: var(--font);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  font-feature-settings: "kern" 1, "liga" 1, "cv11" 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}
body.is-locked { overflow: hidden; }

img, svg { max-width: 100%; display: block; height: auto; }

h1, h2, h3, h4 {
  margin: 0 0 0.625rem;
  color: var(--ink);
  font-weight: 700;
  line-height: var(--lh-head);
  letter-spacing: -0.018em;
  text-wrap: balance;
}
h1 { font-size: var(--fs-h1); line-height: var(--lh-tight); letter-spacing: -0.026em; }
h2 { font-size: var(--fs-h2); letter-spacing: -0.022em; }
h3 { font-size: var(--fs-h3); }
h4 { font-size: var(--fs-h4); }

p { margin: 0 0 1.125rem; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: var(--navy); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--red-ink); }

strong, b { color: var(--ink); font-weight: 600; }

ul, ol { margin: 0 0 1.125rem; padding-left: 1.15rem; }
li { margin-bottom: 0.4rem; }
li:last-child { margin-bottom: 0; }

::selection { background: rgba(251, 31, 64, 0.16); color: var(--ink); }

:focus-visible { outline: 2px solid var(--red-ink); outline-offset: 3px; }

.skip-link {
  position: absolute; left: 0; top: 0;
  transform: translateY(-120%);
  z-index: 200;
  background: var(--navy); color: #fff;
  padding: 0.75rem 1.25rem;
  font-size: var(--fs-sm); font-weight: 600;
  text-decoration: none;
  transition: transform 0.18s var(--ease);
}
.skip-link:focus { transform: translateY(0); color: #fff; }

/* Off-screen but available to assistive tech */
.sr-only {
  position: absolute !important;
  width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}

/* Spam honeypot — never shown, never announced */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; }

/* --------------------------------------------------------------------------
   3. Layout
   -------------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: clamp(1.125rem, 0.5rem + 2.4vw, 2.5rem);
}
/* The header bar carries a logo, eight top-level nav items and a CTA. That does
   not fit inside the 1200px content measure, so the topbar and header get their
   own wider, less-padded container. Body content stays at --container so the
   reading measure is unchanged. */
.container--wide {
  max-width: 1520px;
  padding-inline: clamp(1.125rem, 0.5rem + 1.6vw, 2rem);
}

.section { padding-block: var(--section-y); position: relative; }
.section--alt { background: var(--paper-alt); }

.grid { display: grid; gap: var(--gap); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--sidebar {
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: clamp(2rem, 1rem + 4vw, 4.5rem);
}
.grid--split {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2rem, 1rem + 4vw, 4.5rem);
  align-items: start;
}
@media (max-width: 1000px) {
  .grid--sidebar, .grid--split { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 820px) {
  .grid--3 { grid-template-columns: minmax(0, 1fr); }
}

/* --------------------------------------------------------------------------
   4. Section headings
   -------------------------------------------------------------------------- */
.eyebrow,
.testimonial__label {
  display: inline-flex; align-items: center; gap: 0.6rem;
  margin: 0 0 0.9rem;
  color: var(--red-ink);
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  line-height: 1.4;
}
.eyebrow::before,
.testimonial__label::before {
  content: ""; width: 26px; height: 2px; flex: none;
  background: var(--red);
}
/* On navy the AA-safe red is lighter */
.hero .eyebrow, .ctaband .eyebrow { color: var(--red-soft); }
.hero .eyebrow::before, .ctaband .eyebrow::before { background: var(--red-soft); }

.section-head { max-width: 62ch; margin-bottom: clamp(2rem, 1.2rem + 2.4vw, 3.25rem); }
.section-head > p { font-size: 1.0625rem; margin-bottom: 0; }

.lede {
  font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.1875rem);
  line-height: 1.68;
  color: #5b6270;
}
.ctaband .lede { color: rgba(255, 255, 255, 0.8); }

/* Service subtitle under each of the three service headings */
.svc-sub {
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--navy);
  margin-bottom: 0.75rem;
}

/* --------------------------------------------------------------------------
   5. Buttons — mirrors theme core-button (square, red fill, navy hover)
   -------------------------------------------------------------------------- */
.btn {
  --btn-bg: var(--red-ink);
  --btn-fg: #ffffff;
  --btn-bd: var(--red-ink);
  display: inline-flex; align-items: center; justify-content: center; gap: 0.55rem;
  padding: 0.8125rem 2.25rem;
  border: 1px solid var(--btn-bd);
  border-radius: var(--radius);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1.4;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease),
    color 0.2s var(--ease), transform 0.2s var(--ease);
}
.btn:hover {
  --btn-bg: var(--navy);
  --btn-bd: var(--navy);
  color: #fff;
  transform: translateY(-1px);
}
.btn:active { transform: translateY(0); }

.btn--onnavy { --btn-bg: transparent; --btn-fg: #fff; --btn-bd: rgba(255,255,255,0.42); }
.btn--onnavy:hover { --btn-bg: #fff; --btn-bd: #fff; color: var(--navy); }

.btn--sm { padding: 0.5625rem 1.25rem; font-size: var(--fs-xs); }
.btn--lg { padding: 1rem 2.5rem; font-size: 0.9375rem; }
.btn--block { width: 100%; }
.btn[disabled] { opacity: 0.5; pointer-events: none; }

.btn-row { display: flex; flex-wrap: wrap; gap: 0.875rem; align-items: center; }

.textlink {
  display: inline-flex; align-items: center; gap: 0.45rem;
  color: var(--navy);
  font-size: var(--fs-sm); font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid rgba(3, 20, 53, 0.22);
  padding-bottom: 2px;
  transition: color 0.18s var(--ease), border-color 0.18s var(--ease), gap 0.18s var(--ease);
}
.textlink:hover { color: var(--red-ink); border-color: var(--red); gap: 0.7rem; }
.textlink .arw { transition: transform 0.18s var(--ease); }
.textlink:hover .arw { transform: translateX(2px); }

/* --------------------------------------------------------------------------
   6. Top bar
   -------------------------------------------------------------------------- */
.topbar {
  background: var(--navy);
  color: rgba(255, 255, 255, 0.72);
  font-size: var(--fs-xs);
  line-height: 1.5;
}
.topbar__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.25rem; min-height: 40px; flex-wrap: wrap;
}
.topbar__group { display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap; }
.topbar a {
  color: rgba(255, 255, 255, 0.82); text-decoration: none;
  display: inline-flex; align-items: center; gap: 0.45rem;
}
.topbar a:hover { color: #fff; }
.topbar svg { flex: none; opacity: 0.7; }
.topbar__tag {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.2rem 0.6rem;
  border: 1px solid rgba(255, 255, 255, 0.22);
  color: rgba(255, 255, 255, 0.88);
  font-weight: 500; letter-spacing: 0.04em;
}
.topbar__dot { width: 6px; height: 6px; background: #35d07f; border-radius: 50%; flex: none; }
@media (max-width: 900px) { .topbar { display: none; } }

/* --------------------------------------------------------------------------
   7. Header + navigation
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: rgba(255, 255, 255, 0.94);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line);
  transition: box-shadow 0.24s var(--ease);
}
.site-header.is-stuck { box-shadow: 0 1px 0 var(--line), 0 12px 28px -20px rgba(3, 20, 53, 0.4); }
.site-header__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem; min-height: var(--header-h);
}

.brand { display: inline-flex; align-items: center; gap: 0.875rem; text-decoration: none; flex: none; }
.brand img { width: 208px; height: auto; }
.brand__rule { width: 1px; height: 34px; background: var(--line); }
.brand__kicker {
  font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--navy); line-height: 1.35; max-width: 8.5rem;
}
.brand__kicker span { display: block; color: var(--red-ink); }
@media (max-width: 1080px) { .brand__rule, .brand__kicker { display: none; } }
@media (max-width: 560px) { .brand img { width: 172px; } }

.nav { display: flex; align-items: center; gap: 1.75rem; flex-wrap: nowrap; }
.nav__list {
  display: flex; align-items: center; flex-wrap: nowrap;
  gap: 1.5rem; margin: 0; padding: 0; list-style: none;
}
.nav__list li { margin: 0; }
.nav__link {
  position: relative;
  /* inline-flex, not inline-block: keeps the chevron on the label's own line
     instead of letting it drop to a second line when space gets tight. */
  display: inline-flex; align-items: center; padding: 0.4rem 0;
  color: var(--ink);
  font-size: var(--fs-sm); font-weight: 500;
  text-decoration: none; white-space: nowrap;
  transition: color 0.18s var(--ease);
}
.nav__link::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px;
  height: 2px; background: var(--red);
  transform: scaleX(0); transform-origin: left;
  transition: transform 0.22s var(--ease);
}
.nav__link:hover { color: var(--red-ink); }
.nav__link:hover::after { transform: scaleX(1); }
/* Three-step degradation, measured against the widest label set in site.json:
   > 1440  logo + 8 items + Let's Meet + CTA
   1361-1440  Let's Meet dropped (measured: it overflows the bar up to ~1400px;
              it stays in the mobile menu and the footer)
   1281-1360  CTA dropped too (Contact stays in the topbar, footer and page CTA band)
   <= 1280  hamburger */
@media (max-width: 1440px) { .nav__list { gap: 1.25rem; } .nav { gap: 1.5rem; } .nav .nav__meet { display: none; } }
@media (max-width: 1360px) { .nav .btn { display: none; } }
@media (max-width: 1280px) { .nav__list { display: none; } }

.nav-toggle {
  display: none;
  width: 44px; height: 44px;
  align-items: center; justify-content: center;
  background: transparent; border: 1px solid var(--line);
  cursor: pointer; padding: 0;
}
.nav-toggle span {
  position: relative; display: block; width: 18px; height: 1.5px;
  background: var(--ink);
  transition: background 0.2s var(--ease);
}
.nav-toggle span::before,
.nav-toggle span::after {
  content: ""; position: absolute; left: 0; width: 18px; height: 1.5px;
  background: var(--ink);
  transition: transform 0.24s var(--ease), top 0.24s var(--ease);
}
.nav-toggle span::before { top: -6px; }
.nav-toggle span::after { top: 6px; }
.nav-toggle[aria-expanded="true"] span { background: transparent; }
.nav-toggle[aria-expanded="true"] span::before { top: 0; transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] span::after { top: 0; transform: rotate(-45deg); }
@media (max-width: 1280px) { .nav-toggle { display: inline-flex; } }

/* Closed state uses visibility rather than display: it keeps the slide
   transition, stays out of the accessibility tree, and cannot trap clicks. */
.mobile-nav {
  position: fixed; inset: 0 0 0 auto;
  width: min(400px, 88vw);
  z-index: 130;
  background: #fff;
  border-left: 1px solid var(--line);
  padding: 1.75rem clamp(1.25rem, 4vw, 2rem) 2.5rem;
  overflow-y: auto;
  transform: translateX(100%);
  visibility: hidden;
  transition: transform 0.3s var(--ease), visibility 0.3s var(--ease);
}
.mobile-nav.is-open { transform: translateX(0); visibility: visible; }
.mobile-nav__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.75rem; }
.mobile-nav__list { list-style: none; margin: 0 0 1.75rem; padding: 0; }
.mobile-nav__list li { margin: 0; border-bottom: 1px solid var(--line-soft); }
.mobile-nav__list a {
  display: block; padding: 0.9375rem 0;
  color: var(--ink); font-size: 1rem; font-weight: 500; text-decoration: none;
}
.mobile-nav__list a:hover { color: var(--red-ink); }
.mobile-nav__meta {
  font-size: var(--fs-sm);
  border-top: 1px solid var(--line);
  padding-top: 1.25rem; margin-top: 1.5rem;
}
.mobile-nav__meta a { color: var(--navy); font-weight: 500; display: block; margin-bottom: 0.4rem; }

.nav-close {
  width: 40px; height: 40px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid var(--line); cursor: pointer;
  font-size: 1.25rem; line-height: 1; color: var(--ink);
}

/* pointer-events and visibility are both required. An opacity-0 overlay with
   inset:0 still intercepts every click underneath it, which silently makes the
   whole page unclickable. */
.scrim {
  position: fixed; inset: 0; z-index: 120;
  background: rgba(3, 20, 53, 0.5);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.28s var(--ease), visibility 0.28s var(--ease);
}
.scrim.is-open { opacity: 1; visibility: visible; pointer-events: auto; }

.progress {
  position: fixed; top: 0; left: 0; z-index: 140;
  height: 2px; width: 100%;
  transform: scaleX(0); transform-origin: left;
  background: var(--red);
  pointer-events: none; /* never let a 2px bar eat clicks on the top bar */
}

/* --------------------------------------------------------------------------
   8. Hero
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  background: var(--navy);
  color: rgba(255, 255, 255, 0.78);
  overflow: hidden;
  isolation: isolate;
}
.hero::before {
  content: ""; position: absolute; inset: 0; z-index: -2;
  background:
    radial-gradient(900px 460px at 88% -10%, rgba(31, 68, 120, 0.85), transparent 68%),
    radial-gradient(700px 420px at 6% 108%, rgba(168, 13, 37, 0.4), transparent 66%);
}
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 72px 72px;
  mask-image: linear-gradient(to bottom, rgba(0,0,0,0.85), transparent 78%);
  -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,0.85), transparent 78%);
}
.hero__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
  gap: clamp(2.5rem, 1rem + 5vw, 5rem);
  align-items: center;
  padding-block: clamp(3.25rem, 2rem + 6vw, 6rem);
}
@media (max-width: 1000px) { .hero__inner { grid-template-columns: minmax(0, 1fr); } }

.hero h1 { color: #fff; margin-bottom: 1.25rem; }
/* Marker highlight. The stop sits low and the fill is light so the bar reads
   as an underline rather than a redaction block, and box-decoration-break
   makes it render correctly when the phrase wraps across lines. */
.hero h1 em {
  font-style: normal;
  color: #fff;
  background: linear-gradient(transparent 76%, rgba(251, 31, 64, 0.45) 76%);
  padding-inline: 0.06em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.hero__lede {
  font-size: clamp(1.0313rem, 0.97rem + 0.42vw, 1.1875rem);
  line-height: 1.7;
  color: rgba(255, 255, 255, 0.8);
  max-width: 58ch;
  margin-bottom: 1.875rem;
}
.hero__badges { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem; }

.chip {
  display: inline-flex; align-items: center; gap: 0.45rem;
  padding: 0.3125rem 0.6875rem;
  border: 1px solid rgba(255, 255, 255, 0.2);
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.88);
  font-size: 0.75rem; font-weight: 500; letter-spacing: 0.03em;
  line-height: 1.5; white-space: nowrap;
}
.chip svg { flex: none; }

/* Hero capability-stack panel */
.console {
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: linear-gradient(180deg, rgba(10, 33, 73, 0.92), rgba(3, 20, 53, 0.92));
  box-shadow: 0 40px 80px -40px rgba(0, 0, 0, 0.7);
}
.console__bar {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.03);
}
.console__dots { display: flex; gap: 0.3125rem; }
.console__dots i { width: 8px; height: 8px; border-radius: 50%; background: rgba(255,255,255,0.2); }
.console__dots i:first-child { background: rgba(251, 31, 64, 0.7); }
.console__title {
  margin-left: 0.5rem;
  font-family: var(--font-mono); font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.6); letter-spacing: 0.02em;
}
.console__body { padding: 1.375rem 1.25rem 1.5rem; }
.console__row {
  display: flex; align-items: flex-start; gap: 0.75rem;
  padding: 0.8125rem 0;
  border-bottom: 1px dashed rgba(255, 255, 255, 0.1);
  font-size: var(--fs-sm); line-height: 1.55;
}
.console__row:last-child { border-bottom: 0; padding-bottom: 0; }
.console__step {
  flex: none; width: 24px; height: 24px; margin-top: 1px;
  display: grid; place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.24);
  font-family: var(--font-mono); font-size: 0.6875rem;
  color: rgba(255, 255, 255, 0.72);
}
.console__row b { display: block; color: #fff; font-weight: 600; font-size: 0.9375rem; }
.console__row span { color: rgba(255, 255, 255, 0.62); font-size: var(--fs-xs); }
.console__row.is-done .console__step {
  border-color: rgba(53, 208, 127, 0.6);
  background: rgba(53, 208, 127, 0.14);
  color: #7ff0b4;
}
.console__foot {
  margin-top: 1.25rem; padding-top: 1rem;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  font-family: var(--font-mono); font-size: 0.75rem; color: rgba(255,255,255,0.55);
}
.console__foot b { color: #7ff0b4; font-weight: 500; }

/* --------------------------------------------------------------------------
   9. Stat strip
   -------------------------------------------------------------------------- */
.statstrip { border-block: 1px solid var(--line); background: #fff; }
.statstrip__grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
.statstrip__item {
  padding: clamp(1.5rem, 1rem + 1.6vw, 2.25rem) clamp(1rem, 0.5rem + 1.4vw, 2rem);
  border-left: 1px solid var(--line);
}
.statstrip__item:first-child { border-left: 0; }
.statstrip__n {
  display: block;
  color: var(--navy);
  font-size: clamp(1.75rem, 1.4rem + 1.6vw, 2.5rem);
  font-weight: 700; letter-spacing: -0.03em; line-height: 1.05;
  margin-bottom: 0.375rem;
  font-variant-numeric: tabular-nums;
}
.statstrip__n sup { color: var(--red); font-size: 0.5em; top: -0.7em; }
.statstrip__l { font-size: var(--fs-xs); color: var(--body); line-height: 1.5; letter-spacing: 0.01em; }
.statstrip__l b { display: block; color: var(--ink); font-weight: 600; font-size: var(--fs-sm); margin-bottom: 0.1rem; }
@media (max-width: 900px) {
  .statstrip__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .statstrip__item:nth-child(3) { border-left: 0; }
  .statstrip__item:nth-child(n+3) { border-top: 1px solid var(--line); }
}
@media (max-width: 520px) {
  .statstrip__grid { grid-template-columns: minmax(0, 1fr); }
  .statstrip__item { border-left: 0; }
  .statstrip__item + .statstrip__item { border-top: 1px solid var(--line); }
}

/* --------------------------------------------------------------------------
   10. Cards
   -------------------------------------------------------------------------- */
.card {
  display: flex; flex-direction: column;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  padding: clamp(1.375rem, 1rem + 1.2vw, 2rem);
}
.card--alt { background: var(--paper-alt); }
.card h3, .card h4 { margin-bottom: 0.5rem; }
.card p { font-size: var(--fs-sm); line-height: 1.72; }
.card__foot { margin-top: auto; padding-top: 1.25rem; }

/* Small mono label used above card content */
.cs__k {
  font-family: var(--font-mono); font-size: 0.6875rem;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted);
  font-weight: 500; margin-bottom: 0.5rem;
}

/* Pillar card — service and proof cards */
.pillar {
  position: relative;
  display: flex; flex-direction: column;
  background: #fff;
  border: 1px solid var(--line);
  border-top: 3px solid var(--navy);
  padding: clamp(1.5rem, 1.1rem + 1.4vw, 2.125rem);
  transition: border-color 0.22s var(--ease), box-shadow 0.22s var(--ease), transform 0.22s var(--ease);
}
.pillar:hover { box-shadow: var(--shadow); transform: translateY(-3px); border-top-color: var(--red); }
.pillar__svc {
  display: flex; align-items: center; gap: 0.625rem;
  font-family: var(--font-mono); font-size: 0.6875rem;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.875rem;
}
.pillar__svc i { width: 7px; height: 7px; background: var(--red); flex: none; }
.pillar h3 { margin-bottom: 0.625rem; }
.pillar__role { font-size: var(--fs-sm); font-weight: 600; color: var(--navy); margin-bottom: 0.75rem; }
.pillar ul {
  list-style: none; padding: 0; margin: 1.125rem 0 0;
  border-top: 1px solid var(--line-soft); padding-top: 1.125rem;
}
.pillar ul li {
  position: relative; padding-left: 1.375rem;
  font-size: var(--fs-sm); line-height: 1.6; margin-bottom: 0.625rem;
}
.pillar ul li::before {
  content: ""; position: absolute; left: 0; top: 0.6em;
  width: 8px; height: 1.5px; background: var(--red);
}
.pillar__foot { margin-top: auto; padding-top: 1.375rem; }

/* --------------------------------------------------------------------------
   11. Lists
   -------------------------------------------------------------------------- */
.checklist { list-style: none; padding: 0; margin: 0; }
.checklist li {
  position: relative;
  padding-left: 2rem; margin-bottom: 0.875rem;
  font-size: var(--fs-sm); line-height: 1.68;
}
.checklist li::before {
  content: ""; position: absolute; left: 0; top: 0.28em;
  width: 18px; height: 18px;
  border: 1px solid rgba(211, 16, 47, 0.35);
  background: rgba(251, 31, 64, 0.08);
}
.checklist li::after {
  content: ""; position: absolute; left: 5px; top: 0.62em;
  width: 8px; height: 4px;
  border-left: 1.5px solid var(--red-ink);
  border-bottom: 1.5px solid var(--red-ink);
  transform: rotate(-45deg);
}
.checklist li b { display: block; color: var(--ink); font-weight: 600; }
/* Navy variant */
.ctaband .checklist li { color: rgba(255, 255, 255, 0.78); }
.ctaband .checklist li b { color: #fff; }
.ctaband .checklist li::before { border-color: rgba(255,255,255,0.3); background: rgba(255,255,255,0.08); }
.ctaband .checklist li::after { border-color: var(--red-soft); }

.deflist { margin: 0; }
.deflist > div {
  display: grid; grid-template-columns: 168px minmax(0, 1fr);
  gap: 1.25rem;
  padding: 1rem 0;
  border-top: 1px solid var(--line);
  font-size: var(--fs-sm);
}
.deflist > div:last-child { border-bottom: 1px solid var(--line); }
.deflist dt { color: var(--ink); font-weight: 600; margin: 0; }
.deflist dd { margin: 0; }
@media (max-width: 640px) {
  .deflist > div { grid-template-columns: minmax(0, 1fr); gap: 0.25rem; }
}

/* Numbered delivery-loop list */
.steps { list-style: none; margin: 0; padding: 0; counter-reset: s; }
.steps li {
  display: flex; align-items: flex-start; gap: 0.75rem;
  padding: 0.8125rem 0;
  border-bottom: 1px dashed var(--line);
  font-size: var(--fs-xs); line-height: 1.6;
  margin: 0;
}
.steps li:last-child { border-bottom: 0; padding-bottom: 0; }
.steps li:first-child { padding-top: 0; }
.steps__n {
  flex: none; width: 24px; height: 24px; margin-top: 1px;
  display: grid; place-items: center;
  border: 1px solid #cfd4dd;
  font-family: var(--font-mono); font-size: 0.6875rem; color: #5b6270;
}
.steps li b { display: block; color: var(--ink); font-weight: 600; font-size: var(--fs-sm); }

/* --------------------------------------------------------------------------
   12. Phases
   -------------------------------------------------------------------------- */
.phase-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; }
.phase {
  position: relative;
  padding: 1.75rem clamp(1rem, 0.6rem + 1.2vw, 1.75rem) 1.75rem 0;
  border-top: 2px solid var(--line);
}
.phase::before {
  content: ""; position: absolute; top: -6px; left: 0;
  width: 10px; height: 10px; background: var(--red);
}
.phase__k {
  font-family: var(--font-mono); font-size: 0.6875rem;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--red-ink); font-weight: 600;
  margin-bottom: 0.625rem;
}
.phase h3 { font-size: var(--fs-h4); margin-bottom: 0.5rem; }
.phase p { font-size: var(--fs-sm); line-height: 1.68; margin: 0; }
.phase ul { margin: 0.75rem 0 0; padding-left: 1.05rem; font-size: var(--fs-xs); line-height: 1.62; }
@media (max-width: 940px) { .phase-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .phase-grid { grid-template-columns: minmax(0, 1fr); } }

/* --------------------------------------------------------------------------
   13. AWS service chips
   -------------------------------------------------------------------------- */
.svc-chips { display: flex; flex-wrap: wrap; gap: 0.375rem; }
.svc-chip {
  display: inline-flex; align-items: center; gap: 0.375rem;
  padding: 0.25rem 0.5625rem;
  border: 1px solid var(--line);
  background: #fff;
  font-family: var(--font-mono);
  font-size: 0.6875rem; color: #4a515e; letter-spacing: 0.01em;
  white-space: nowrap;
}
.svc-chip::before { content: ""; width: 5px; height: 5px; background: var(--aws-orange); flex: none; }

/* --------------------------------------------------------------------------
   13a. Problem-first cards
   -------------------------------------------------------------------------- */
.prob {
  display: flex; flex-direction: column;
  background: #fff;
  border: 1px solid var(--line);
  border-left: 3px solid var(--red);
  padding: clamp(1.25rem, 1rem + 1vw, 1.625rem);
  transition: box-shadow 0.22s var(--ease), transform 0.22s var(--ease);
}
.prob:hover { box-shadow: var(--shadow); transform: translateY(-3px); }
.prob h4 {
  margin-bottom: 0.5rem;
  font-size: 1.0625rem;
  letter-spacing: -0.016em;
  line-height: 1.4;
}
.prob > p {
  font-size: var(--fs-xs);
  line-height: 1.65;
  margin-bottom: 1rem;
}
.prob .svc-chips { margin-bottom: 1rem; }
.prob__ev {
  display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
  margin: auto 0 0;
  padding-top: 0.875rem;
  border-top: 1px solid var(--line-soft);
  font-size: var(--fs-xs);
  color: var(--muted);
}

/* --------------------------------------------------------------------------
   13b. Capability matrix
   -------------------------------------------------------------------------- */
.matrix-wrap { background: #fff; border: 1px solid var(--line); }

.matrix {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
  text-align: left;
}
.matrix caption { text-align: left; }
.matrix thead th {
  padding: 0.875rem 1.125rem;
  border-bottom: 1px solid var(--line);
  background: var(--paper-alt);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.6875rem; font-weight: 500;
  letter-spacing: 0.1em; text-transform: uppercase;
  white-space: nowrap;
}
.matrix tbody tr + tr > * { border-top: 1px solid var(--line-soft); }
.matrix tbody th,
.matrix tbody td {
  padding: 1rem 1.125rem;
  vertical-align: top;
}
.matrix tbody th {
  color: var(--ink);
  font-size: var(--fs-sm); font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.45;
  width: 20%;
  min-width: 9rem;
}
.matrix tbody tr:hover > * { background: rgba(3, 20, 53, 0.015); }
.matrix__note {
  display: block;
  margin-top: 0.375rem;
  color: var(--muted);
  font-size: var(--fs-xs); font-weight: 400;
  line-height: 1.5;
  letter-spacing: 0;
}
.matrix td:last-child { width: 24%; min-width: 11rem; }
.matrix--eol tbody th { width: 52%; }
.matrix--eol td:last-child { width: 48%; color: var(--navy); font-weight: 500; }

/* Status pills */
.tag {
  display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.2rem 0.5rem;
  border: 1px solid transparent;
  font-family: var(--font-mono);
  font-size: 0.625rem; font-weight: 500;
  letter-spacing: 0.06em; text-transform: uppercase;
  white-space: nowrap; line-height: 1.5;
}
.tag--live { color: #1d6b46; border-color: rgba(53, 160, 107, 0.4); background: rgba(53, 160, 107, 0.1); }
.tag--cap  { color: #525966; border-color: var(--line); background: var(--paper-alt); }

/* Stack into labelled blocks once three columns stop fitting */
@media (max-width: 860px) {
  .matrix-wrap { border: 0; background: transparent; }
  .matrix, .matrix thead, .matrix tbody, .matrix tr, .matrix th, .matrix td { display: block; width: auto; }
  .matrix thead { display: none; }
  .matrix tbody tr {
    background: #fff;
    border: 1px solid var(--line);
    padding: 0.375rem 0;
  }
  .matrix tbody tr + tr { margin-top: 0.75rem; }
  .matrix tbody tr + tr > * { border-top: 0; }
  .matrix tbody th, .matrix tbody td { padding: 0.625rem 1.125rem; min-width: 0; }
  .matrix tbody th { padding-top: 1rem; font-size: 1rem; }
  .matrix tbody td[data-label]::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 0.4375rem;
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: 0.625rem; font-weight: 500;
    letter-spacing: 0.1em; text-transform: uppercase;
  }
  .matrix tbody td:last-child { padding-bottom: 1rem; }
  .matrix--eol tbody th { font-size: var(--fs-sm); }
}

/* --------------------------------------------------------------------------
   14. Quote + credentials
   -------------------------------------------------------------------------- */
.quote {
  border-left: 3px solid var(--red);
  padding: 0.25rem 0 0.25rem 1.75rem;
  margin: 0;
}
.quote p {
  font-size: clamp(1.0625rem, 1rem + 0.5vw, 1.25rem);
  line-height: 1.62; color: var(--ink); font-weight: 500;
  letter-spacing: -0.012em;
}
.quote footer { font-size: var(--fs-xs); color: var(--muted); margin-top: 0.875rem; }
.quote footer b { display: block; color: var(--ink); font-size: var(--fs-sm); }

.creds {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 1px; background: var(--line); border: 1px solid var(--line);
}
.creds__i { background: #fff; padding: 1.25rem 1.375rem; }
.creds__i b { display: block; color: var(--navy); font-size: var(--fs-sm); font-weight: 600; margin-bottom: 0.25rem; }
.creds__i span { font-size: var(--fs-xs); color: var(--body); line-height: 1.55; }

/* Official AWS Partner badge.
   The asset has an opaque white background and AWS brand guidance requires
   clear space around it, so it sits on a white tile rather than on the navy. */
/* A horizontal row of partner badges. Each sits on its own white tile because
   the marks are drawn for a light ground and need clear space around them; a
   single shared tile would crowd them together and let the eye read the three
   as one graphic. Sized by height so they align optically despite one being
   portrait and two square. */
.apn {
  --apn-h: 84px;
  display: flex;
  flex-wrap: wrap;
  /* Both of these are load-bearing. The footer column stretches this list
     taller than its contents, and with the defaults a wrapped flex container
     stretches its line to match and the tiles inherit an inconsistent cross
     size — one tile ends up ~6px taller than the other and the row of white
     plates reads as misaligned. Pinning both axes to the start sizes every
     tile from its own content instead. */
  align-items: flex-start;
  align-content: flex-start;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.apn__i {
  display: grid;
  place-items: center;
  padding: 0.5rem 0.625rem;
  background: #fff;
  border-radius: var(--radius-card);
  line-height: 0;
}
.apn__i img {
  height: var(--apn-h);
  width: auto;
  max-width: 100%;
}

@media (max-width: 560px) {
  .apn { --apn-h: 72px; gap: 0.375rem; }
  .apn__i { padding: 0.4375rem 0.5rem; }
}

/* --------------------------------------------------------------------------
   15. CTA band + contact
   -------------------------------------------------------------------------- */
.ctaband {
  background: var(--navy);
  color: rgba(255,255,255,0.76);
  position: relative; overflow: hidden; isolation: isolate;
}
.ctaband::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(760px 400px at 82% 120%, rgba(168, 13, 37, 0.42), transparent 66%);
}
.ctaband__inner {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: clamp(2rem, 1rem + 3vw, 3.5rem); align-items: start;
}
@media (max-width: 860px) { .ctaband__inner { grid-template-columns: minmax(0, 1fr); } }
.ctaband h2 { color: #fff; }
.ctaband__meta {
  border-left: 1px solid rgba(255,255,255,0.16);
  padding-left: clamp(1.5rem, 1rem + 2vw, 2.5rem);
}
@media (max-width: 860px) {
  .ctaband__meta {
    border-left: 0; border-top: 1px solid rgba(255,255,255,0.16);
    padding-left: 0; padding-top: 1.75rem;
  }
}
.ctaband__meta dl { margin: 1.75rem 0 0; }
.ctaband__meta dt {
  font-size: 0.6875rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: rgba(255,255,255,0.5); margin-bottom: 0.25rem;
}
.ctaband__meta dd { margin: 0 0 1.125rem; color: #fff; font-size: var(--fs-sm); font-weight: 500; }
.ctaband__meta dd:last-child { margin-bottom: 0; }
.ctaband__meta a { color: #fff; text-decoration: none; border-bottom: 1px solid rgba(255,255,255,0.3); }
.ctaband__meta a:hover { color: var(--red-soft); border-color: var(--red-soft); }

/* --------------------------------------------------------------------------
   16. Forms
   -------------------------------------------------------------------------- */
.field { margin-bottom: 1.125rem; }
.field label { display: block; margin-bottom: 0.4375rem; color: var(--ink); font-size: var(--fs-sm); font-weight: 600; }
.req { color: var(--red-ink); }

.input, .select, .textarea {
  width: 100%;
  padding: 0.75rem 0.875rem;
  border: 1px solid #d9dde6;
  border-radius: var(--radius);
  background: #fff;
  color: var(--ink);
  font: inherit; font-size: var(--fs-sm);
  line-height: 1.5;
  transition: border-color 0.18s var(--ease), box-shadow 0.18s var(--ease);
  -webkit-appearance: none; appearance: none;
}
.input::placeholder, .textarea::placeholder { color: #a8adb8; }
.input:focus, .select:focus, .textarea:focus {
  outline: 0; border-color: var(--navy);
  box-shadow: 0 0 0 3px rgba(3, 20, 53, 0.1);
}
.input[aria-invalid="true"], .select[aria-invalid="true"], .textarea[aria-invalid="true"] {
  border-color: var(--red-ink);
  box-shadow: 0 0 0 3px rgba(211, 16, 47, 0.12);
}
.textarea { min-height: 96px; resize: vertical; }
.select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%23717171' stroke-width='1.6' d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.875rem center;
  padding-right: 2.25rem;
}
.err { display: none; margin-top: 0.375rem; color: var(--red-ink); font-size: var(--fs-xs); font-weight: 500; }
.err.is-shown { display: block; }

.consent { display: flex; align-items: flex-start; gap: 0.625rem; font-size: var(--fs-xs); line-height: 1.6; }
.consent input { margin-top: 0.2rem; flex: none; width: 16px; height: 16px; accent-color: var(--red-ink); }
.consent label { font-size: var(--fs-xs); font-weight: 400; color: var(--body); margin: 0; }

.form-note {
  margin-top: 1rem; padding-top: 1rem;
  border-top: 1px solid var(--line-soft);
  font-size: var(--fs-xs); color: var(--muted); line-height: 1.6;
}
.form-status {
  display: none;
  margin-bottom: 1.25rem; padding: 0.875rem 1rem;
  border-left: 3px solid #35a06b;
  background: rgba(53, 160, 107, 0.12);
  font-size: var(--fs-sm); color: #d6ffe8;
}
.form-status.is-shown { display: block; }
.form-status.is-error {
  border-color: var(--red-soft);
  background: rgba(251, 31, 64, 0.14);
  color: #ffd5dc;
}
.form-status a { color: #fff; }

/* Contact form sits on navy */
.ctaband .field label { color: #fff; }
.ctaband .consent label { color: rgba(255, 255, 255, 0.72); }
.ctaband .form-note { color: rgba(255, 255, 255, 0.5); border-top-color: rgba(255, 255, 255, 0.14); }
.ctaband .err { color: var(--red-soft); }
.ctaband .req { color: var(--red-soft); }
/* background-color, NOT the background shorthand. The shorthand resets
   background-repeat to `repeat` and background-position to `0 0`, which made
   the select's chevron tile across the whole control. */
.ctaband .input, .ctaband .select, .ctaband .textarea {
  background-color: rgba(255, 255, 255, 0.07);
  border-color: rgba(255, 255, 255, 0.22);
  color: #fff;
}
.ctaband .input::placeholder, .ctaband .textarea::placeholder { color: rgba(255, 255, 255, 0.42); }
.ctaband .input:focus, .ctaband .select:focus, .ctaband .textarea:focus {
  border-color: #fff; box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.14);
}
.ctaband .select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%23ffffff' stroke-opacity='.65' stroke-width='1.6' d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.875rem center;
  background-size: 12px 8px;
}
/* The dropdown list itself is painted by the OS, so it needs explicit
   light-on-dark reversal or the options render white on white. */
.ctaband .select option { color: var(--ink); background-color: #fff; }
.ctaband .select option[value=""] { color: var(--muted); }
/* Grouped options: the OS paints this list, so it needs its own light styling
   or the group labels vanish against the dark control. */
.ctaband .select optgroup {
  color: var(--navy);
  background-color: #fff;
  font-weight: 700;
  font-style: normal;
}

/* --------------------------------------------------------------------------
   17. Footer
   -------------------------------------------------------------------------- */
.site-footer { background: var(--navy); color: rgba(255,255,255,0.62); font-size: var(--fs-sm); }
.site-footer a { color: rgba(255,255,255,0.72); text-decoration: none; }
.site-footer a:hover { color: #fff; }
.footer__top {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr));
  gap: clamp(1.75rem, 1rem + 3vw, 3.25rem);
  padding-block: clamp(2.75rem, 2rem + 3vw, 4.25rem);
}
@media (max-width: 1000px) { .footer__top { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) { .footer__top { grid-template-columns: minmax(0, 1fr); } }
/* The supplied logo PNG has no alpha channel, so brightness(0) invert(1)
   rendered it as a solid white block on the navy footer. A typeset wordmark
   is cleaner here, and the real logo still carries the header on white. */
.footer__wordmark {
  margin: 0 0 1.125rem;
  color: #fff;
  font-size: 1.5rem; font-weight: 700;
  letter-spacing: -0.035em; line-height: 1.1;
}
.footer__wordmark span { color: var(--red-soft); }
.footer__wordmark small {
  display: block; margin-top: 0.375rem;
  font-size: 0.6875rem; font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.5);
}
.footer__brand p { font-size: var(--fs-xs); line-height: 1.75; max-width: 40ch; margin-bottom: 1.25rem; }
.footer__h {
  color: #fff; font-size: 0.6875rem; font-weight: 600;
  letter-spacing: 0.13em; text-transform: uppercase;
  margin-bottom: 1.125rem; padding-bottom: 0.625rem;
  border-bottom: 1px solid rgba(255,255,255,0.14);
}
.footer__list { list-style: none; margin: 0; padding: 0; }
.footer__list li { margin-bottom: 0.625rem; font-size: var(--fs-xs); line-height: 1.6; }
.footer__contact { list-style: none; margin: 0 0 1.25rem; padding: 0; }
.footer__contact li { display: flex; gap: 0.75rem; margin-bottom: 1rem; font-size: var(--fs-xs); line-height: 1.65; }
.footer__contact svg { flex: none; margin-top: 0.2rem; opacity: 0.55; }
.footer__social {
  list-style: none; margin: 0 0 1.25rem; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem;
  font-size: var(--fs-xs); line-height: 1.6;
}
.footer__social li { margin: 0; }
.footer__legal {
  max-width: 74ch; font-size: 0.6875rem; line-height: 1.7;
  color: rgba(255,255,255,0.38); padding-bottom: 1.5rem;
}
.footer__bottom {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  padding-block: 1.375rem;
  border-top: 1px solid rgba(255,255,255,0.12);
  font-size: 0.75rem; color: rgba(255,255,255,0.45);
}
.footer__bottom nav { display: flex; gap: 1.375rem; flex-wrap: wrap; }

/* --------------------------------------------------------------------------
   18. Entrance motion
   Spec: docs/superpowers/specs/2026-09-23-site-motion-system-design.md

   A section names its motion once, with data-motion="…" in its partial. The
   inline script in <head> adds html.js-motion when motion is allowed, and
   site.js adds .is-in to a section once it is on screen. Everything visual is
   here, and the whole feel is tuned by the four --motion-* tokens in :root.

   Two rules hold throughout:
   - Content is hidden only under .js-motion, only until .is-in, and only when
     the visitor has not asked for reduced motion. If site.js never starts, the
     head script's safety net removes .js-motion and everything shows.
   - Entrances are keyframe animations with backwards fill, not transitions to
     an end state. When one finishes, no rule is left holding the element, so a
     card's own :hover lift works again. The old reveal rule this replaced held
     `transform: none` on the element for good, and silently disabled the hover
     lift on every card it touched.
   -------------------------------------------------------------------------- */
[data-motion] { --motion-kf: motion-rise; }
[data-motion="sequence"] { --motion-kf: motion-slide; }   /* a process: left to right */
[data-motion="tick"],
[data-motion="fade"] { --motion-kf: motion-fade; }         /* arrives, does not travel */
[data-motion="fade"],
[data-motion="settle"] { --motion-step: 0ms; }             /* a set, not a sequence */
[data-motion="settle"] { --motion-rise: 4px; }

/* Child index for the stagger. Capped at 9, so a long list tops out at 630ms of
   delay: past the tenth item nobody is watching the order any more. */
[data-motion] > * { --i: 0; }
[data-motion] > :nth-child(2) { --i: 1; }
[data-motion] > :nth-child(3) { --i: 2; }
[data-motion] > :nth-child(4) { --i: 3; }
[data-motion] > :nth-child(5) { --i: 4; }
[data-motion] > :nth-child(6) { --i: 5; }
[data-motion] > :nth-child(7) { --i: 6; }
[data-motion] > :nth-child(8) { --i: 7; }
[data-motion] > :nth-child(9) { --i: 8; }
[data-motion] > :nth-child(n+10) { --i: 9; }

/* Only the starting frame is defined, so each animation ends on the element's
   own styles instead of imposing a final value. */
@keyframes motion-rise  { from { opacity: 0; transform: translate3d(0, var(--motion-rise), 0); } }
@keyframes motion-slide { from { opacity: 0; transform: translate3d(calc(var(--motion-rise) * -1), 0, 0); } }
@keyframes motion-fade  { from { opacity: 0; } }
@keyframes motion-settle { from { transform: scale(1.03); } }

@media (prefers-reduced-motion: no-preference) {
  /* Waiting to arrive. Opacity only: layout is untouched, so nothing shifts. */
  .js-motion [data-motion]:not([data-motion="open"]):not(.is-in) > * { opacity: 0; }

  /* Sections animate when they arrive. Page openings need no script at all:
     they play from first paint, so the headline is never held back waiting
     for site.js, and they still play with JavaScript off. */
  .js-motion [data-motion].is-in > *,
  [data-motion="open"] > * {
    animation-name: var(--motion-kf);
    animation-duration: var(--motion-dur);
    animation-timing-function: var(--motion-ease);
    animation-delay: calc(var(--i) * var(--motion-step));
    animation-fill-mode: backwards;
  }

  /* Hero images and hero art settle alongside the headline: 1.03x to 1x over
     700ms. Transform only, never opacity, so they paint at once and cannot
     delay the page's largest paint. The column image's wrapper, and the art's
     own layer for full-width art, clip the zoom. */
  .hero__media img,
  .hero__backdrop img {
    animation: motion-settle 700ms var(--motion-ease) backwards;
  }
}

@media print {
  [data-motion] > * { opacity: 1 !important; animation: none !important; }
}

/* Page transitions. Following a link to another page of the site cross-fades
   in 180ms, in browsers with cross-document view transitions; the rest cut,
   as they always have. Short on purpose: a slow transition reads as latency.

   Opted into under no-preference, rather than switched on for everyone and
   off again under reduce. That would work only while the reduce rule stayed
   later in the file, and a reorder would quietly bring transitions back for
   visitors who asked for less motion. verify.py refuses @view-transition
   anywhere else.

   The group is set as well as the two snapshots: its default is 250ms, and a
   transition lasts as long as its longest animation. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }

  ::view-transition-group(root),
  ::view-transition-old(root),
  ::view-transition-new(root) { animation-duration: 180ms; }
}

/* --------------------------------------------------------------------------
   19. Utilities
   -------------------------------------------------------------------------- */
.mb-0 { margin-bottom: 0 !important; }
.mb-3 { margin-bottom: 1.5rem; }
.mt-3 { margin-top: 1.5rem; }
.mt-4 { margin-top: 2rem; }
.mt-5 { margin-top: 2.75rem; }
.text-sm { font-size: var(--fs-sm); }
.text-xs { font-size: var(--fs-xs); }
.muted { color: var(--muted); }
.maxw-70 { max-width: 70ch; }

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

@media print {
  .topbar, .site-header, .progress, .mobile-nav, .scrim,
  .btn, .nav-toggle, .btn-row { display: none !important; }
  body { color: #000; font-size: 11pt; }
  .hero, .ctaband, .site-footer, .console {
    background: #fff !important; color: #000 !important;
  }
  .hero h1, .ctaband h2 { color: #000 !important; }
  .hero h1 em { background: none; }
  .hero::before, .hero::after, .ctaband::before { display: none; }
  /* Dark art behind black text is unreadable on paper. */
  .hero__video, .hero__backdrop { display: none !important; }
  .console__row b, .console__row span, .console__foot,
  .ctaband .checklist li, .ctaband .checklist li b, .ctaband .lede { color: #000 !important; }
  .section { padding-block: 1.25rem; }
  .card, .pillar, .creds, .console { break-inside: avoid; border-color: #bbb; }
  a { text-decoration: underline; }
}

/* ==========================================================================
   MAIN SITE ADDITIONS
   Components the full electromech.cloud site needs on top of the micro-site
   design system above: page headers, breadcrumbs, dropdown navigation,
   long-form article typography, and a light-background form status.
   Everything above this line is shared verbatim with genai-microsite and
   webinar-microsite, so the three stay visually identical.
   ========================================================================== */

/* --------------------------------------------------------------------------
   M1. Layout additions
   -------------------------------------------------------------------------- */
.container--tight { max-width: 860px; }
.section--tight { padding-block: clamp(2.5rem, 1.5rem + 4vw, 4rem); }
.mt-2 { margin-top: 1rem; }

/* Secondary button: outlined, for the lower-priority action in a pair. */
.btn--ghost { --btn-bg: transparent; --btn-fg: var(--navy); --btn-bd: #c9ced9; }
.btn--ghost:hover { --btn-bg: var(--navy); --btn-bd: var(--navy); color: #fff; }
.section--navy { background: var(--navy); color: rgba(255, 255, 255, 0.76); }
.section--navy h2, .section--navy h3, .section--navy h4 { color: #fff; }
.section--navy strong { color: #fff; }
.section--navy .lede { color: rgba(255, 255, 255, 0.8); }
.section--navy .eyebrow { color: var(--red-soft); }
.section--navy .eyebrow::before { background: var(--red-soft); }

.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1000px) { .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px) { .grid--2, .grid--4 { grid-template-columns: minmax(0, 1fr); } }

/* --------------------------------------------------------------------------
   M2. Page header
   -------------------------------------------------------------------------- */
.pagehead {
  position: relative;
  background: var(--navy);
  color: rgba(255, 255, 255, 0.78);
  overflow: hidden;
  isolation: isolate;
}
.pagehead::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(820px 420px at 88% -25%, rgba(31, 68, 120, 0.9), transparent 68%),
    radial-gradient(600px 340px at 2% 115%, rgba(168, 13, 37, 0.32), transparent 66%);
}
.pagehead__inner { padding-block: clamp(2.5rem, 1.9rem + 3.4vw, 4.5rem); }
.pagehead h1 { color: #fff; max-width: 30ch; }
.pagehead__intro {
  max-width: 64ch;
  margin-top: 1rem;
  color: rgba(255, 255, 255, 0.8);
  font-size: clamp(1.0313rem, 0.97rem + 0.4vw, 1.1875rem);
  line-height: 1.68;
}
.pagehead--article h1 { max-width: 38ch; }
.pagehead .factbar__v { color: #fff; }

.postmeta {
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem;
  margin: 1.25rem 0 0;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: rgba(255, 255, 255, 0.6);
}
.postmeta span + span { position: relative; padding-left: 1.25rem; }
.postmeta span + span::before {
  content: ""; position: absolute; left: 0; top: 50%;
  width: 4px; height: 4px; margin-top: -2px;
  background: var(--red); border-radius: 50%;
}

/* Editorial flag on auto-migrated pages. Deliberately loud so it cannot ship
   unnoticed; remove the needs_review front-matter key to clear it. */
.reviewflag {
  display: block;
  margin: 1.5rem 0 0;
  padding: 0.75rem 1rem;
  border-left: 3px solid var(--aws-orange);
  background: rgba(236, 114, 17, 0.14);
  color: #ffd9b8;
  font-size: var(--fs-xs);
  line-height: 1.6;
}
.reviewflag code {
  background: rgba(0, 0, 0, 0.25);
  border-color: rgba(255, 255, 255, 0.2);
  color: #fff;
}

/* --------------------------------------------------------------------------
   M3. Breadcrumbs
   -------------------------------------------------------------------------- */
.crumbs-wrap {
  background: var(--paper-alt);
  border-bottom: 1px solid var(--line);
}
.crumbs {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 0.4rem 0.6rem;
  list-style: none; margin: 0; padding: 0.75rem 0;
  font-size: var(--fs-xs);
}
.crumbs li { display: inline-flex; align-items: center; gap: 0.6rem; margin: 0; }
.crumbs li::after { content: "/"; color: #b9c0cd; }
.crumbs li:last-child::after { content: none; }
.crumbs a { color: var(--body); text-decoration: none; }
.crumbs a:hover { color: var(--red-ink); }
.crumbs [aria-current="page"] { color: var(--ink); font-weight: 600; }

/* --------------------------------------------------------------------------
   M4. Dropdown navigation
   -------------------------------------------------------------------------- */
.nav__item { position: relative; }
.nav__chev { margin-left: 0.3rem; opacity: 0.55; transition: transform 0.18s var(--ease); }
.nav__item--has-sub:hover .nav__chev,
.nav__item--has-sub:focus-within .nav__chev { transform: rotate(180deg); opacity: 1; }
.nav__link.is-active { color: var(--red-ink); }
.nav__link.is-active::after { transform: scaleX(1); }

.subnav-pop {
  position: absolute; top: 100%; left: 50%;
  transform: translateX(-50%) translateY(6px);
  z-index: 110;
  min-width: 270px;
  padding: 0.5rem;
  background: #fff;
  border: 1px solid var(--line);
  box-shadow: 0 18px 44px -18px rgba(3, 20, 53, 0.34);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity 0.18s var(--ease), transform 0.18s var(--ease),
    visibility 0.18s var(--ease);
}
/* Opens on hover and on keyboard focus, so it is reachable by tab. */
.nav__item--has-sub:hover .subnav-pop,
.nav__item--has-sub:focus-within .subnav-pop {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translateX(-50%) translateY(0);
}
/* The last item's panel is centred on a narrow link at the right-hand end of
   the bar, so a 270px panel opens past the edge of the screen. It is worst
   between 1281px and 1360px, where the header CTA is hidden and the last item
   sits flush against the container edge. Anchor that one to its own right edge
   instead of centring it. */
.nav__item:last-child .subnav-pop {
  left: auto; right: 0;
  transform: translateX(0) translateY(6px);
}
.nav__item:last-child:hover .subnav-pop,
.nav__item:last-child:focus-within .subnav-pop {
  transform: translateX(0) translateY(0);
}
.subnav-pop ul { list-style: none; margin: 0; padding: 0; }
.subnav-pop li { margin: 0; }
.subnav-pop a {
  display: block;
  padding: 0.5rem 0.75rem;
  color: var(--ink);
  font-size: var(--fs-xs);
  line-height: 1.45;
  text-decoration: none;
  border-left: 2px solid transparent;
}
.subnav-pop a:hover,
.subnav-pop a:focus-visible {
  background: var(--paper-alt);
  border-left-color: var(--red);
  color: var(--red-ink);
}
.subnav-pop a[aria-current="page"] { color: var(--red-ink); font-weight: 600; border-left-color: var(--red); }
@media (max-width: 1280px) { .subnav-pop { display: none; } }

.mobile-nav__sub { list-style: none; margin: 0 0 0.5rem; padding: 0 0 0.375rem 0.875rem; }
.mobile-nav__sub li { border-bottom: 0; }
.mobile-nav__sub a {
  padding: 0.4375rem 0;
  font-size: var(--fs-xs);
  font-weight: 400;
  color: var(--body);
}
.mobile-nav__sub a:hover { color: var(--red-ink); }

/* --------------------------------------------------------------------------
   M5. Event / detail fact bar  (shared with webinar-microsite)
   -------------------------------------------------------------------------- */
.factbar {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-left: 3px solid var(--red);
  background: rgba(255, 255, 255, 0.04);
}
.factbar__i {
  padding: 0.9375rem 1.125rem;
  border-left: 1px solid rgba(255, 255, 255, 0.12);
}
.factbar__i:first-child { border-left: 0; }
.factbar__k {
  margin-bottom: 0.3125rem;
  color: rgba(255, 255, 255, 0.55);
  font-family: var(--font-mono);
  font-size: 0.625rem; font-weight: 500;
  letter-spacing: 0.1em; text-transform: uppercase;
}
.factbar__v {
  margin: 0;
  color: #fff;
  font-size: var(--fs-sm); font-weight: 600;
  line-height: 1.4;
}
@media (max-width: 720px) {
  .factbar { grid-template-columns: minmax(0, 1fr); }
  .factbar__i { border-left: 0; border-top: 1px solid rgba(255, 255, 255, 0.12); }
  .factbar__i:first-child { border-top: 0; }
}

/* --------------------------------------------------------------------------
   M6. Cards
   -------------------------------------------------------------------------- */
.card--hover { transition: border-color 0.22s var(--ease), box-shadow 0.22s var(--ease), transform 0.22s var(--ease); }
.card--hover:hover { border-color: #d5dae4; box-shadow: var(--shadow); transform: translateY(-3px); }
.card h3 a, .pillar h3 a { color: inherit; text-decoration: none; }
.card h3 a:hover, .pillar h3 a:hover { color: var(--red-ink); }

.logowall { display: flex; flex-wrap: wrap; gap: 0.5rem 0.75rem; align-items: center; }
.logowall__item {
  display: inline-flex; align-items: center;
  padding: 0.5rem 0.9375rem;
  border: 1px solid var(--line);
  background: #fff;
  font-size: var(--fs-sm); font-weight: 600; color: var(--navy);
  letter-spacing: -0.01em;
}
.logowall__item span { font-weight: 400; color: var(--muted); font-size: var(--fs-xs); margin-left: 0.5rem; }

/* --------------------------------------------------------------------------
   M7. Long-form article typography
   -------------------------------------------------------------------------- */
.prose { font-size: 1.0313rem; line-height: 1.78; }
.prose > * + * { margin-top: 1.125rem; }
.prose h2 {
  margin-top: 2.75rem; margin-bottom: 0.75rem;
  font-size: clamp(1.375rem, 1.2rem + 0.9vw, 1.75rem);
  scroll-margin-top: calc(var(--header-h) + 20px);
}
.prose h3 {
  margin-top: 2rem; margin-bottom: 0.5rem;
  font-size: clamp(1.125rem, 1.05rem + 0.4vw, 1.3125rem);
  scroll-margin-top: calc(var(--header-h) + 20px);
}
.prose h2:first-child, .prose h3:first-child { margin-top: 0; }
.prose ul, .prose ol { padding-left: 1.35rem; }
.prose li { margin-bottom: 0.5rem; }
.prose li > ul, .prose li > ol { margin-top: 0.5rem; }
.prose a { color: var(--navy); text-decoration: underline; text-decoration-color: rgba(3, 20, 53, 0.3); }
.prose a:hover { color: var(--red-ink); text-decoration-color: var(--red); }
.prose img { margin-block: 1.75rem; border: 1px solid var(--line); }
.prose figure { margin: 1.75rem 0; }
.prose figcaption {
  margin-top: 0.625rem;
  color: var(--muted);
  font-size: var(--fs-xs);
  line-height: 1.6;
}
.prose blockquote {
  margin: 1.75rem 0;
  padding: 0.25rem 0 0.25rem 1.5rem;
  border-left: 3px solid var(--red);
  color: var(--ink);
  font-size: 1.0625rem;
  font-weight: 500;
}
.prose blockquote p:last-child { margin-bottom: 0; }
.prose pre {
  margin: 1.75rem 0;
  padding: 1.125rem 1.25rem;
  overflow-x: auto;
  background: var(--navy);
  color: #e7ecf5;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  line-height: 1.7;
}
.prose pre code { background: none; border: 0; padding: 0; color: inherit; font-size: inherit; }
.prose table { margin: 0; font-size: var(--fs-sm); border-collapse: collapse; }
.prose th, .prose td {
  padding: 0.75rem 0.875rem;
  border: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}
.prose th { background: var(--paper-alt); color: var(--ink); font-weight: 600; }
.prose hr { margin-block: 2.5rem; }

/* Comparison tables migrated from the old blog posts are five and six columns
   wide and cannot shrink to a phone. build.py wraps every table in this
   scroller so the table scrolls instead of the whole page. site.js adds
   tabindex and a role only when it actually overflows, so keyboard users get a
   stop where there is something to scroll and nowhere else. */
.table-scroll {
  margin: 1.75rem 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.table-scroll:focus-visible {
  outline: 2px solid var(--red-ink);
  outline-offset: 3px;
}
/* A scroller with no visible edge looks like a truncated table. The fade on the
   right tells the reader there is more, and the note gives the same information
   to anyone who cannot see the fade. site.js adds .is-scrollable only while the
   table actually overflows. */
.table-scroll.is-scrollable {
  position: relative;
  background:
    linear-gradient(to left, rgba(255, 255, 255, 0), #fff 60%) left / 2rem 100% no-repeat,
    linear-gradient(to right, rgba(255, 255, 255, 0), #fff 60%) right / 2rem 100% no-repeat;
  background-attachment: local, local;
}
.table-scroll.is-scrollable::after {
  content: "Scroll the table sideways to see every column";
  display: block;
  position: sticky; left: 0;
  margin-top: 0.5rem;
  color: var(--muted);
  font-size: var(--fs-xs);
}

/* Bare URLs used as link text, and inline code, are the other thing that will
   not wrap. Without this a single GitHub URL pushes a phone layout 200px wide.
   `anywhere` rather than `break-word` because only `anywhere` reduces the
   element's min-content width, which is what actually drives the overflow.

   Deliberately not applied to td/th: it lets a five-column table crush itself
   into 318px with words broken mid-syllable, which reads far worse than
   scrolling the table. Cells keep their natural width and .table-scroll
   handles it. */
.prose a, .prose code { overflow-wrap: anywhere; }
.prose p, .prose li, .prose dd { overflow-wrap: break-word; }
/* Headings break mid-word badly; allow normal breaking plus hyphen-free wrap. */
.prose h2, .prose h3, .prose h4 { overflow-wrap: break-word; }

/* --------------------------------------------------------------------------
   M8. Form status on light backgrounds
   Overrides the navy-tuned rule above. The main site's forms sit on white
   cards, where pale-on-pale text is unreadable.
   -------------------------------------------------------------------------- */
.form-status {
  border-left: 3px solid #1d8a57;
  background: #e7f4ed;
  color: #14543a;
  font-weight: 500;
  line-height: 1.6;
}
.form-status.is-error {
  border-left-color: var(--red-ink);
  background: #fde8eb;
  color: #9c0b22;
}
.form-status a { color: inherit; font-weight: 600; }
.form-status__t {
  display: flex; align-items: center; gap: 0.5rem;
  margin-bottom: 0.375rem;
  color: #0f4530;
  font-size: 1.0625rem; font-weight: 700;
  letter-spacing: -0.015em;
}
.form-status.is-error .form-status__t { color: #8a0a1e; }
.form-status__t svg { flex: none; }

.form-card {
  background: #fff;
  border: 1px solid var(--line);
  border-top: 3px solid var(--red);
  padding: clamp(1.5rem, 1.1rem + 1.4vw, 2.25rem);
}

/* --------------------------------------------------------------------------
   M9. Print additions
   -------------------------------------------------------------------------- */
@media print {
  .crumbs-wrap, .subnav-pop, .reviewflag { display: none !important; }
  .pagehead { background: #fff !important; color: #000 !important; }
  .pagehead h1, .pagehead__intro, .postmeta { color: #000 !important; }
  .pagehead::before { display: none; }
  .prose pre { background: #f4f4f4; color: #000; border: 1px solid #bbb; }
}

/* --------------------------------------------------------------------------
   M9. Block library additions
   The declarative blocks in partials/blocks/ reuse the components above almost
   entirely. These are the few pieces they needed that did not already exist.
   -------------------------------------------------------------------------- */

/* Hero image, as an alternative to the console panel in the second column.
   The frame is on the wrapper, which also clips, so the image can settle from
   a slight zoom as the page opens (section 18) without the border moving. */
.hero__media {
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.14);
}
.hero__media img {
  display: block;
  width: 100%; height: auto;
}

/* Full-width hero media (spec
   docs/superpowers/specs/2026-09-28-site-media-upgrade-design.md): a background
   loop (home, Gen AI) or generated hero art (every service page). Both fill the
   hero edge to edge, under its own glow and grid layers and under a navy wash
   that is darkest behind the headline, so white text keeps its contrast on
   every frame. The art keeps its subject on the right, where the wash is light.
   A <video> shows its poster until site.js starts it. */
.hero__video,
.hero__backdrop {
  position: absolute; inset: 0; z-index: -3;
  overflow: hidden;
  pointer-events: none;
}
.hero__video video,
.hero__backdrop img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
}
/* When a narrow screen crops the sides, keep the art's subject in view. */
.hero__backdrop img { object-position: 82% 50%; }
.hero__video::after,
.hero__backdrop::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg,
    rgba(3, 20, 53, 0.9) 0%, rgba(3, 20, 53, 0.8) 42%,
    rgba(3, 20, 53, 0.38) 78%, rgba(3, 20, 53, 0.28) 100%);
}
/* A hero with art gets room to show it, not just the height of its text. It
   is never wider than 3.5:1, so on a very wide screen the cover crop stays in
   the plain top and bottom fifth that the art keeps, clear of the subject. */
.hero--backdrop .hero__inner {
  min-height: max(clamp(27rem, 20rem + 12vw, 36rem), 100vw / 3.5);
}
/* Stacked (1000px and below) the text runs the full width. A video keeps its
   poster behind it, under a flat wash. Hero art would have to be washed out of
   sight to sit behind that much text, so it becomes a full-width band below
   the text instead: at the 21:9 it was composed at, so nothing is cropped, and
   its top edge fades into the hero. It stays under the glow and grid layers. */
@media (max-width: 1000px) {
  .hero__video::after { background: rgba(3, 20, 53, 0.8); }
  .hero--backdrop .hero__inner { min-height: 0; padding-bottom: 0; }
  .hero__backdrop {
    position: relative; inset: auto;
    aspect-ratio: 21 / 9;
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 25%);
            mask-image: linear-gradient(to bottom, transparent, #000 25%);
  }
  .hero__backdrop img { object-position: 50% 50%; }
  .hero__backdrop::after { background: rgba(3, 20, 53, 0.3); }
}

/* Numbered delivery phases. .phase already exists; the number did not. */
.phase__n {
  display: block;
  margin-bottom: 0.625rem;
  font-family: var(--font-mono); font-size: 0.6875rem; font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--red-ink);
}

/* Card thumbnail. Cropped to a consistent ratio so a grid of cards lines up
   even though the source images are all different shapes. */
.card__media {
  display: block;
  margin: -1.375rem -1.375rem 1.125rem;
  border-bottom: 1px solid var(--line);
}
.card__media img {
  display: block;
  width: 100%; height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  margin: 0; border: 0;
}
.card__meta {
  margin-bottom: 0.375rem;
  font-family: var(--font-mono); font-size: 0.6875rem;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted);
}

/* Standalone figure in a composed page. */
.figure { margin: 0; }
.figure img { display: block; width: 100%; height: auto; border: 1px solid var(--line); }
.figure figcaption {
  margin-top: 0.625rem;
  color: var(--muted); font-size: var(--fs-xs); line-height: 1.6;
}

/* Inline "read more" link with the arrow affordance. */
.link {
  display: inline-flex; align-items: center; gap: 0.4rem;
  color: var(--navy);
  font-size: var(--fs-sm); font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid rgba(3, 20, 53, 0.22);
  transition: color 0.18s var(--ease), border-color 0.18s var(--ease);
}
.link::after { content: "\2192"; transition: transform 0.18s var(--ease); }
.link:hover { color: var(--red-ink); border-bottom-color: var(--red); }
.link:hover::after { transform: translateX(3px); }

/* A table caption inside .matrix, which previously had no styling. */
.matrix caption {
  caption-side: top;
  padding-bottom: 0.75rem;
  color: var(--muted); font-size: var(--fs-xs); text-align: left;
}

/* Reading measure that stays left-aligned with the wide container.
   .container--tight centres itself, so a narrow section sitting between two full
   -width ones makes the left edge of the page zig-zag. Nesting .measure inside a
   normal .container keeps every section starting on the same vertical line while
   still holding text to a comfortable line length. */
.measure { max-width: 62ch; }
.measure--wide { max-width: 78ch; }

/* --------------------------------------------------------------------------
   M10. Light-background variants
   .factbar and .reviewflag were written when both only ever appeared inside the
   navy .pagehead, so their borders and text are white-on-transparent. The
   casestudy layout now places the factbar below the hero on white, and the
   review banner sits on white on every composed page, where white text on a
   white background is invisible and a pale orange note on a pale orange panel
   measures about 1.3:1.

   So: light is the default, and the dark treatment is scoped to the dark
   sections that actually need it.
   -------------------------------------------------------------------------- */
.factbar {
  border: 1px solid var(--line);
  border-left: 3px solid var(--red);
  background: var(--paper-alt);
}
.factbar__k { color: var(--muted); }
.factbar__v { color: var(--ink); }

/* Inside the navy hero or pagehead, revert to the light-on-dark treatment. */
.hero .factbar,
.pagehead .factbar {
  border-color: rgba(255, 255, 255, 0.16);
  border-left-color: var(--red);
  background: rgba(255, 255, 255, 0.04);
}
.hero .factbar__k,
.pagehead .factbar__k { color: rgba(255, 255, 255, 0.55); }
.hero .factbar__v,
.pagehead .factbar__v { color: #fff; }

/* 7.3:1 on the pale amber panel, against #ffd9b8's 1.3:1. */
.reviewflag {
  background: #fff5e8;
  color: #7a3d00;
}
.reviewflag code {
  background: rgba(0, 0, 0, 0.06);
  border-color: rgba(122, 61, 0, 0.25);
  color: #5c2d00;
}
.hero .reviewflag,
.pagehead .reviewflag {
  background: rgba(236, 114, 17, 0.14);
  color: #ffd9b8;
}
.hero .reviewflag code,
.pagehead .reviewflag code {
  background: rgba(0, 0, 0, 0.25);
  border-color: rgba(255, 255, 255, 0.2);
  color: #fff;
}

@media (max-width: 720px) {
  .factbar { grid-template-columns: minmax(0, 1fr); }
}

/* Single-card grid. build.py sizes a card grid to its item count, so a section
   with one card no longer sits in a three-column grid with two empty columns.
   Capped rather than full-width, because a lone card stretched across 1160px
   reads as a mistake too. */
.grid--1 { grid-template-columns: minmax(0, 1fr); max-width: 44rem; }

/* ==========================================================================
   JOURNEY — the company timeline band
   --------------------------------------------------------------------------
   A dark section with a central rail on wide screens, alternating milestone
   cards, and a single-sided left rail below 900px.

   Two rules govern the whole block:

   1. The default state is the FINISHED state. Nothing is hidden until
      site.js adds .is-armed, so with JavaScript off, or if the script fails,
      every milestone is fully legible. Animation is the enhancement, never
      the thing content depends on.
   2. Only transform, opacity and filter are animated. The rail fill scales,
      it does not grow in height; the travelling spark translates, it does
      not change `top`. Both stay on the compositor.

   Numbering comes from a CSS counter, so inserting a milestone cannot leave
   the circles out of step with the list.
   ========================================================================== */
.journey {
  /* Geometry */
  --j-node: 3.25rem;          /* 52px, within the 48-56px the design calls for */
  --j-line: 2px;
  --j-connector: clamp(1.25rem, 2.4vw, 2.75rem);
  --j-col-gap: clamp(1.5rem, 3vw, 3.25rem);
  --j-row-gap: clamp(1.75rem, 2.4vw, 2.5rem);
  /* The year is each milestone's anchor, so the node, the connector and the
     rail all align to the centre of the year's line box rather than to the
     centre of the card. Deriving that from the year's own font-size and
     line-height keeps one source of truth: change the type scale and the
     geometry follows, instead of drifting against a hard-coded offset. */
  --j-year-fs: clamp(1.375rem, 1.1rem + 0.9vw, 1.875rem);
  --j-year-lh: 1.2;
  --j-anchor: calc(var(--j-year-fs) * var(--j-year-lh) / 2);
  --j-rail-inset: var(--j-anchor);

  /* Motion. The design brief asked for cubic-bezier(0.22, 1, 0.36, 1), which
     is the site-wide entrance curve, so it is taken from there rather than
     repeated: one curve for every entrance on the site. */
  --j-ease: var(--motion-ease);
  --j-dur: 620ms;
  --j-dur-slow: 780ms;
  --j-pop: 520ms;

  /* Driven by site.js */
  --j-progress: 0;            /* 0 → 1 along the rail */

  /* Surface */
  --j-bg: #03052b;
  --j-ink: #eef3fb;
  --j-ink-dim: #9aa8c4;

  position: relative;
  isolation: isolate;
  overflow: hidden;           /* contains the ambient glows; also the reason no
                                 child can cause horizontal overflow */
  padding-block: var(--section-y);
  background: var(--j-bg);
  color: var(--j-ink);
}

/* ---------------------------------------------------------------- ambient */
.journey__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

.journey__glow {
  position: absolute;
  width: 46rem;
  height: 46rem;
  border-radius: 50%;
  filter: blur(80px);
  opacity: 0.5;
  will-change: transform;
}

.journey__glow--blue {
  top: -14rem;
  left: -10rem;
  background: radial-gradient(circle, rgba(58, 116, 214, 0.28), transparent 68%);
  animation: journeyDriftA 46s var(--j-ease) infinite;
}

.journey__glow--violet {
  right: -12rem;
  bottom: -16rem;
  background: radial-gradient(circle, rgba(124, 92, 214, 0.24), transparent 68%);
  animation: journeyDriftB 58s var(--j-ease) infinite;
}

/* Deliberately tiny movements. The brief asks for a background that feels
   alive but is almost imperceptible, so these travel a couple of percent. */
@keyframes journeyDriftA {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(3%, 2%, 0) scale(1.04); }
}

@keyframes journeyDriftB {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1.03); }
  50%      { transform: translate3d(-3%, -2%, 0) scale(1); }
}

/* When the journey completes, the ambience lifts very slightly. */
.journey.is-done .journey__glow { opacity: 0.68; }

/* The background loop (J01, spec
   docs/superpowers/specs/2026-09-28-site-media-upgrade-design.md) replaces the
   glows on wide screens. It is shown at 60%, so the ambience stays quiet and
   the timeline keeps its contrast on every frame, and it lifts like the glows
   when the journey completes. Its poster is a background declared only here,
   at the width the loop plays at, so a phone downloads neither and keeps the
   glows. The poster is the loop's first frame, so nothing jumps when site.js
   starts it. */
.journey__loop { display: none; }
@media (min-width: 1001px) {
  .journey__loop {
    display: block;
    position: absolute;
    inset: 0;
    opacity: 0.6;
    background: var(--loop-poster) 50% 50% / cover no-repeat;
    transition: opacity var(--j-dur) var(--j-ease);
  }
  .journey__loop video {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  .journey__loop ~ .journey__glow { display: none; }
  .journey.is-done .journey__loop { opacity: 0.7; }
}

/* ------------------------------------------------------------------ head */
.journey__inner { position: relative; }

.journey__head {
  max-width: 44rem;
  margin: 0 auto clamp(2.5rem, 4vw, 4rem);
  text-align: center;
}

.journey__eyebrow { color: var(--red-soft); }   /* AA on navy, unlike --red-ink */

.journey__title {
  margin: 0;
  font-size: clamp(2rem, 1.3rem + 2.6vw, 4rem);
  line-height: var(--lh-tight);
  letter-spacing: -0.02em;
  color: #fff;
}

.journey__title em {
  font-style: normal;
  color: var(--red-soft);
}

.journey__lede {
  margin: 1rem auto 0;
  max-width: 38rem;
  color: var(--j-ink-dim);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

/* -------------------------------------------------------------- timeline */
.journey__timeline { position: relative; }

.journey__rail {
  position: absolute;
  /* JS measures first-node centre to last-node centre and sets --j-rail-top
     and --j-rail-h, so the rail terminates exactly on the end nodes rather
     than overhanging. The rem fallbacks cover the no-JS case, where rows are
     taller than a node and the overhang is a few pixels. */
  top: var(--j-rail-top, var(--j-rail-inset));
  left: 50%;
  width: var(--j-line);
  height: var(--j-rail-h, calc(100% - (var(--j-rail-inset) * 2)));
  transform: translateX(-50%);
  background: rgba(195, 217, 231, 0.13);
  z-index: 0;
}

.journey__rail-fill {
  position: absolute;
  inset: 0;
  transform-origin: top center;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.5),
    rgba(147, 178, 232, 0.42)
  );
}

.journey__spark {
  position: absolute;
  top: 0;
  left: 50%;
  width: 0.5rem;
  height: 0.5rem;
  margin-left: -0.25rem;
  margin-top: -0.25rem;
  border-radius: 50%;
  background: #fff;
  box-shadow:
    0 0 8px 2px rgba(255, 255, 255, 0.55),
    0 0 20px 6px rgba(120, 165, 240, 0.4);
  opacity: 0;
}

/* ------------------------------------------------------------ milestones */
.journey__list {
  counter-reset: journey;
  position: relative;
  z-index: 1;
  display: grid;
  row-gap: var(--j-row-gap);
  margin: 0;
  padding: 0;
  list-style: none;
}

.journey__item {
  counter-increment: journey;
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--j-node) minmax(0, 1fr);
  column-gap: var(--j-col-gap);
  align-items: start;
}

/* 1996 left, 2014 right, 2016 left … as the design specifies.

   grid-row is explicit on both the card and the node, and that is load-bearing.
   Grid auto-placement is sparse: the node claims column 2 first (it precedes
   the card in the DOM), so a card then asking for column 1 cannot place behind
   the cursor and silently drops to row 2. The result is a row as tall as the
   node plus the card, with the node floating above the year instead of beside
   it — about 60px out on every left-hand milestone. */
.journey__item:nth-child(odd) .journey__card {
  grid-column: 1;
  grid-row: 1;
  text-align: right;
  justify-items: end;
}

.journey__item:nth-child(even) .journey__card {
  grid-column: 3;
  grid-row: 1;
  text-align: left;
}

/* ------------------------------------------------------------------ node */
.journey__node {
  grid-column: 2;
  grid-row: 1;
  /* Pull the node up so its centre lands on the year's centre. Negative
     whenever the node is taller than one line of the year, which it is. */
  margin-top: calc(var(--j-anchor) - (var(--j-node) / 2));
  position: relative;
  z-index: 2;
  display: grid;
  place-items: center;
  width: var(--j-node);
  height: var(--j-node);
  border-radius: 50%;
  /* Lifted off the section background so the rail does not show through. */
  background: #071231;
  border: 1px solid rgba(var(--j-rgb), 0.32);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--j-ink-dim);
  transition:
    border-color var(--j-dur) var(--j-ease),
    box-shadow var(--j-dur) var(--j-ease),
    color var(--j-dur) var(--j-ease);
}

.journey__node::before { content: counter(journey); }

.journey__connector {
  position: absolute;
  top: var(--j-anchor);
  width: var(--j-connector);
  height: var(--j-line);
  background: rgba(195, 217, 231, 0.16);
  transition: background-color var(--j-dur) var(--j-ease),
              box-shadow var(--j-dur) var(--j-ease);
}

.journey__item:nth-child(odd) .journey__connector {
  right: 50%;
  margin-right: calc(var(--j-node) / 2);
}

.journey__item:nth-child(even) .journey__connector {
  left: 50%;
  margin-left: calc(var(--j-node) / 2);
}

/* ------------------------------------------------------------------ card */
.journey__card { display: grid; gap: 0.3rem; }

.journey__year {
  font-size: var(--j-year-fs);
  line-height: var(--j-year-lh);
  font-weight: 700;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  color: var(--j-ink-dim);
  transition: color var(--j-dur) var(--j-ease);
}

.journey__what {
  margin: 0;
  max-width: 24rem;
  color: var(--j-ink-dim);
  font-size: var(--fs-body);
  line-height: 1.5;
  transition: color var(--j-dur) var(--j-ease);
}

.journey__item:nth-child(odd) .journey__what { margin-left: auto; }

.journey__flag {
  justify-self: start;
  margin-top: 0.15rem;
  padding: 0.15rem 0.5rem;
  border: 1px solid rgba(var(--j-rgb), 0.4);
  color: rgb(var(--j-rgb));
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.journey__item:nth-child(odd) .journey__flag { justify-self: end; }

/* --------------------------------------------------------------- accents */
/* Held as RGB triplets so one value drives the border, the glow and the flag
   at different alphas. Muted on purpose: the brief asks for restraint. */
.journey__item { --j-rgb: 195, 217, 231; }
.journey__item[data-accent="gold"]        { --j-rgb: 214, 168,  86; }
.journey__item[data-accent="rose"]        { --j-rgb: 255, 139, 157; }
.journey__item[data-accent="amber"]       { --j-rgb: 224, 144,  79; }
.journey__item[data-accent="azure"]       { --j-rgb:  95, 168, 216; }
.journey__item[data-accent="teal"]        { --j-rgb:  79, 168, 155; }
.journey__item[data-accent="green"]       { --j-rgb: 123, 171,  92; }
.journey__item[data-accent="gold-bright"] { --j-rgb: 232, 193, 104; }

/* ======================================================= ANIMATED STATES
   Everything above renders the finished timeline. The rules below only bite
   once site.js has added .is-armed, which it does not do when the visitor
   asks for reduced motion or when IntersectionObserver is missing.
   ====================================================================== */
.journey.is-armed .journey__head {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--j-dur-slow) var(--j-ease),
              transform var(--j-dur-slow) var(--j-ease);
}

.journey.is-armed.is-in .journey__head {
  opacity: 1;
  transform: none;
}

/* The "coming into focus" pass: 0.94 → 1, 0.75 → 1 opacity, 2px → 0 blur.
   A 6% scale change, which is deliberately small. */
.journey.is-armed .journey__timeline {
  opacity: 0.75;
  transform: scale(0.94);
  filter: blur(2px);
  transition: opacity var(--j-dur-slow) var(--j-ease),
              transform var(--j-dur-slow) var(--j-ease),
              filter var(--j-dur-slow) var(--j-ease);
}

.journey.is-armed.is-in .journey__timeline {
  opacity: 1;
  transform: scale(1);
  filter: blur(0);
}

/* Rail reveals top to bottom by scaling, not by changing height. */
.journey.is-armed .journey__rail-fill {
  transform: scaleY(var(--j-progress));
}

.journey.is-armed.is-in .journey__spark {
  opacity: 1;
  /* --j-rail-h is the measured rail height in px, so the spark tracks progress
     in the same coordinate space as the fill. */
  transform: translateY(calc(var(--j-rail-h, 0px) * var(--j-progress)));
}

/* The spark is only meaningful while travelling; it fades at the end. */
.journey.is-armed.is-done .journey__spark {
  opacity: 0;
  transition: opacity var(--j-dur) var(--j-ease);
}

.journey.is-armed .journey__card {
  opacity: 0.4;
  transform: translateY(14px);
  transition: opacity var(--j-dur) var(--j-ease),
              transform var(--j-dur) var(--j-ease);
}

.journey.is-armed .journey__item.is-on .journey__card {
  opacity: 1;
  transform: none;
}

/* ------------------------------------------------- active milestone look */
.journey__item.is-on .journey__node,
.journey__item:hover .journey__node {
  border-color: rgba(var(--j-rgb), 0.92);
  color: #fff;
  box-shadow:
    0 0 0 1px rgba(var(--j-rgb), 0.22),
    0 0 20px rgba(var(--j-rgb), 0.3);
}

.journey__item.is-on .journey__connector,
.journey__item:hover .journey__connector {
  background: rgba(var(--j-rgb), 0.6);
  box-shadow: 0 0 10px rgba(var(--j-rgb), 0.28);
}

.journey__item.is-on .journey__year,
.journey__item:hover .journey__year { color: #fff; }

.journey__item.is-on .journey__what { color: #cdd8ec; }
.journey__item:hover .journey__what { color: var(--j-ink); }

/* The one-shot 1 → 1.08 → 1 pulse as a milestone lights up. */
.journey.is-armed .journey__item.is-on .journey__node {
  animation: journeyPop var(--j-pop) var(--j-ease) both;
}

@keyframes journeyPop {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.08); }
  100% { transform: scale(1); }
}

/* Hover must not disturb layout, so it scales the node only. */
@media (hover: hover) and (pointer: fine) {
  .journey__item:hover .journey__node { transform: scale(1.06); }
  .journey__node { transition: border-color var(--j-dur) var(--j-ease),
                               box-shadow var(--j-dur) var(--j-ease),
                               color var(--j-dur) var(--j-ease),
                               transform var(--j-pop) var(--j-ease); }
}

/* 2027: the closing state is a slightly stronger glow, not a celebration. */
.journey__item[data-status="planned"].is-on .journey__node {
  box-shadow:
    0 0 0 1px rgba(var(--j-rgb), 0.3),
    0 0 26px rgba(var(--j-rgb), 0.42),
    0 0 56px rgba(var(--j-rgb), 0.2);
}

.journey.is-done .journey__rail { background: rgba(195, 217, 231, 0.2); }

/* ====================================================== TABLET / MOBILE
   Below 900px the alternating layout stops fitting two readable columns
   either side of the rail, so it becomes a single-sided timeline with the
   rail on the left and all content to its right. This is a different
   layout, not a scaled-down copy of the desktop one.
   ====================================================================== */
@media (max-width: 900px) {
  .journey {
    --j-node: 2.75rem;        /* 44px */
    --j-rail-inset: 1.375rem;
    --j-connector: 0.875rem;
    --j-row-gap: clamp(1.5rem, 4vw, 2rem);
  }

  .journey__head { text-align: left; margin-inline: 0; }

  .journey__rail { left: calc(var(--j-node) / 2); transform: none; }

  .journey__item {
    grid-template-columns: var(--j-node) minmax(0, 1fr);
    column-gap: calc(var(--j-connector) + 0.5rem);
  }

  /* Both parities collapse to the same single-sided arrangement. */
  /* The node moves to column 1 so it sits ON the rail. Without this it keeps
     the desktop `grid-column: 2`, lands in the same column as the card, and
     the rail runs down the left with the numbered circles floating beside it. */
  .journey__node { grid-column: 1; grid-row: 1; }

  .journey__item:nth-child(odd) .journey__card,
  .journey__item:nth-child(even) .journey__card {
    grid-column: 2;
    grid-row: 1;
    text-align: left;
    justify-items: start;
  }

  .journey__item:nth-child(odd) .journey__what { margin-left: 0; }
  .journey__item:nth-child(odd) .journey__flag { justify-self: start; }
  .journey__what { max-width: none; }

  /* Connector points inward from the rail for every item. Vertical position
     still comes from --j-anchor, so it stays level with the node and year. */
  .journey__item:nth-child(odd) .journey__connector,
  .journey__item:nth-child(even) .journey__connector {
    right: auto;
    left: calc(var(--j-node) / 2);
    margin-left: calc(var(--j-node) / 2);
    margin-right: 0;
  }
}

@media (max-width: 560px) {
  /* Only the two source values change; --j-anchor and the rail inset follow. */
  .journey { --j-node: 2.5rem; --j-year-fs: 1.25rem; }
}

/* ==================================================== REDUCED MOTION
   site.js already declines to arm the section when this is set. These rules
   are the second line of defence: if .is-armed is ever present anyway, the
   content still resolves to its finished, readable state.
   ================================================================== */
@media (prefers-reduced-motion: reduce) {
  .journey__glow { animation: none; }

  .journey.is-armed .journey__head,
  .journey.is-armed .journey__timeline,
  .journey.is-armed .journey__card {
    opacity: 1;
    transform: none;
    filter: none;
    transition: none;
  }

  .journey.is-armed .journey__item.is-on .journey__node { animation: none; }
  .journey.is-armed .journey__rail-fill { transform: none; }
  .journey__spark { display: none; }

  .journey__node,
  .journey__connector,
  .journey__year,
  .journey__what { transition: none; }
}

@media print {
  .journey { background: #fff; color: #000; padding-block: 1.5rem; }
  .journey__bg, .journey__spark, .journey__rail { display: none; }
  .journey__title, .journey__year { color: #000; }
  .journey__what, .journey__lede { color: #333; }
}

/* ==========================================================================
   19. Clients, testimonials, pager
   --------------------------------------------------------------------------
   Blocks restored from the old site. Tokens only, no new colours, no
   transitions.
   ========================================================================== */
/* Clients: the OUR CLIENTS logo wall on the home page
   (partials/blocks/clients.html). A static grid, no motion; the old site's
   autoplay carousel is gone. The logos are white-ground PNGs, so each sits on
   a --paper tile. At 390px the grid falls to two columns. */
.clients__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 1rem;
  list-style: none; margin-bottom: 0; padding: 0;
}
.clients__item {
  margin: 0;
  background: var(--paper);
  border: 1px solid var(--line);
  display: grid; place-items: center;
  min-height: 96px; padding: 1rem;
}
.clients__item a { display: inline-block; }
.clients a:focus-visible { outline: 2px solid var(--navy); outline-offset: 4px; }
.clients__item img {
  display: block;
  height: 56px; width: auto; max-width: 100%;
  object-fit: contain;
}
/* Testimonials: verbatim quotes from data/testimonials.json
   (partials/blocks/testimonials.html), each a figure in a list item. The
   caption uses --muted, 4.83:1 on --paper. The label (an old caption such as
   "Corporate Success") takes the eyebrow style, set in section 4. */
.testimonials { list-style: none; margin-bottom: 0; padding: 0; }
.testimonials > li { margin: 0; }
.testimonial {
  margin: 0; height: 100%;
  border: 1px solid var(--line);
  background: var(--paper);
  padding: 1.5rem;
}
.testimonial blockquote { margin: 0; color: var(--ink); }
.testimonial blockquote p:last-child { margin-bottom: 0; }
.testimonial figcaption {
  margin-top: 0.875rem;
  font-size: var(--fs-xs); color: var(--muted);
}
.testimonial figcaption b { display: block; color: var(--ink); font-size: var(--fs-sm); }
.testimonial figcaption span { display: block; }
/* Pager: numbered pagination under a generated archive's card grid
   (partials/blocks/pager.html). It follows the cards section, so it is pulled
   up into that section's bottom padding, and is positioned so the section's
   box does not sit on top of its links. */
.pager {
  position: relative;
  margin-top: calc(2rem - var(--section-y));
  padding-bottom: var(--section-y);
}
.pager ul {
  display: flex; flex-wrap: wrap; gap: 0.5rem;
  list-style: none; margin: 0; padding: 0;
}
.pager li { margin: 0; }
.pager a,
.pager [aria-current="page"] {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px; padding: 0 0.875rem;
  border: 1px solid var(--line);
  font-size: var(--fs-sm); font-weight: 600;
  text-decoration: none;
}
.pager a { color: var(--navy); background: var(--paper); }
.pager a:hover { color: var(--red-ink); border-color: var(--red); }
.pager [aria-current="page"] { color: var(--ink); background: var(--line-soft); }
/* "Filed under" on a post: its categories and tags as rel=tag links to the
   archives (layouts/post.html). */
.filed { margin-top: 2.5rem; padding-top: 1.25rem; border-top: 1px solid var(--line-soft); }
.filed__label {
  margin: 0 0 0.625rem;
  font-size: var(--fs-xs); font-weight: 600; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.08em;
}
.filed__list {
  display: flex; flex-wrap: wrap; gap: 0.5rem;
  list-style: none; margin: 0; padding: 0;
}
.filed__list li { margin: 0; }
.filed__list a {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 0.75rem;
  border: 1px solid var(--line); background: var(--paper);
  color: var(--navy); font-size: var(--fs-sm); text-decoration: none;
}
.filed__list a:hover { color: var(--red-ink); border-color: var(--red); }
/* The byline links to the author archive; on the dark article hero it keeps
   the byline's own colour. */
.postmeta a { color: inherit; text-decoration: underline; }
.postmeta a:hover { color: #fff; }
/* A row of restored photos inside a prose block (the About page's Community
   Involvement photos). Each photo keeps its own aspect ratio, so nothing is
   cropped; at 390px the row falls to two columns. */
.prose .photo-row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: 1rem;
  align-items: start;
}
.prose .photo-row figure, .prose .photo-row img { margin: 0; }
/* A former home-page slide shown as a static card: its heading is an h2 (the
   card section has no heading of its own), sized like a card's h3. */
.pillar h2 { font-size: var(--fs-h3); margin-bottom: 0.625rem; }
