/* ==========================================================================
   LusoCod Systems — "Atlantic / Linear" dark design system
   Single hand-written stylesheet. No build step, no framework, no @import.
   --------------------------------------------------------------------------
   AMBIENT BACKGROUND CONTRACT
   The layered background is split in two:
     1. Base radial gradient + 64px slate grid -> PURE PSEUDO-ELEMENTS on
        <body> (body::before / body::after). No markup required at all.
     2. The feTurbulence noise plane + the 4 floating blurred "light pool"
        blobs live inside ONE optional DOM node. Exact markup, as the FIRST
        child of <body>:

            <div class="ambient" data-ambient aria-hidden="true">
              <i class="ambient-c"></i>
              <i class="ambient-d"></i>
              <i class="ambient-noise"></i>
            </div>

        Blobs 1+2 are .ambient::before/::after; blobs 3+4 are the .ambient-c /
        .ambient-d <i> elements; .ambient-noise is the grain plane.
        If the element is absent, motion.js injects it (with those three <i>
        children) on load. It is purely decorative, so no-JS pages simply get
        the gradient + grid and remain fully readable.
   --------------------------------------------------------------------------
   Sections
     01 Tokens
     02 Reset & base
     03 Ambient background layers
     04 Typography
     05 Utilities (label, text-gradient, rule, sr-only, skip-link)
     06 Layout (container, section, bento)
     07 Components (button, card, pill, form, header, footer)
     08 Page components (static hero, capabilities, project stages, credits)
     09 Motion (reveal, parallax)
     10 Responsive
     11 prefers-reduced-motion
   ========================================================================== */

/* ---------------------------------------------------------------- 01 Tokens */
:root {
  /* surfaces */
  --bg-deep: #E9EEF2;
  --bg-base: #FFFFFF;
  --bg-subtle: #F4F7F9;
  --bg-elevated: #FFFFFF;
  --surface: rgba(52, 69, 79, 0.04);
  --surface-hover: rgba(52, 69, 79, 0.07);

  /* foreground — --fg is the EXACT logo slate */
  --fg: #34454F;              /* 9.93:1 on white */
  --fg-muted: #4F6473;        /* 5.06:1 on white */
  /* Tertiary. The brief specified #647784 (4.65:1 on white), but measured from
     rendered pixels it composites to 4.32:1 on the --bg-subtle band, which is
     where most labels actually sit — so it is stepped down one notch:
     5.44:1 white / 5.06:1 on --bg-subtle / 4.85:1 over the darkest wash. */
  --fg-subtle: #4F6473;
  /* Large-text-only tone (>=24px), where 3:1 applies — keeps the tertiary
     hierarchy visible on the big rail numerals. 3.56:1 white, 3.17:1 worst. */
  --fg-faint: #7A8A95;

  /* accent (the exact logo blue) */
  --accent: #195EA1;          /* 6.65:1 on white */
  --accent-bright: var(--accent);   /* legacy alias: no lifted blue on light */
  --accent-deep: #124779;     /* 9.57:1 on white */
  --slate: #34454F;
  --accent-tint: rgba(25, 94, 161, 0.08);
  --accent-glow: rgba(25, 94, 161, 0.18);
  --footer-bg: #34454F;

  /* lines */
  --border: rgba(52, 69, 79, 0.14);
  --border-hover: rgba(52, 69, 79, 0.24);
  --border-accent: rgba(25, 94, 161, 0.34);
  /* Form-control boundary. WCAG 1.4.11 asks for >=3:1 against the field fill,
     so this is deliberately far stronger than the decorative --border hairline
     that cards use. #7A8A95 = 3.56:1 on white, 3.17:1 over the darkest ambient
     wash — the brief’s #7E8F9A measured 2.98:1 there. */
  --border-field: #7A8A95;

  /* elevation — soft grey, always multi-layer */
  --shadow-card: 0 1px 2px rgba(52, 69, 79, .06), 0 8px 24px rgba(52, 69, 79, .08);
  --shadow-card-hover: 0 2px 4px rgba(52, 69, 79, .08), 0 16px 40px rgba(52, 69, 79, .12);

  /* geometry */
  --max: 1280px;
  /* Sticky-header height. The header measures 134px at every breakpoint
     (76px min-height + .75rem padding each side + the wrapped nav row), so a
     single token tracks it; anchors add a 24px breath on top. */
  --header-h: 134px;
  --anchor-offset: calc(var(--header-h) + 1.5rem);
  --radius-lg: 16px;
  --radius-md: 12px;
  --radius-sm: 8px;

  /* motion */
  --ease-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --t-fast: 200ms;
  --t-base: 300ms;
  --t-enter: 600ms;

  /* type */
  --sans: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* legacy aliases kept so existing markup does not break */
  --blue: var(--accent);
  --blue-deep: var(--accent-deep);
  --ink: var(--fg);
  --muted: var(--fg-muted);
  --line: var(--border);
  --paper: var(--bg-base);
  --mist: var(--bg-subtle);
  --dark: var(--footer-bg);
  --radius: var(--radius-sm);
}

/* ------------------------------------------------------- 02 Reset & base */
* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* The header is position:sticky, so without this every in-page anchor lands
     with its eyebrow tucked under it. Set on the scroll container so it covers
     hash navigation, scrollIntoView AND sequential keyboard focus. */
  scroll-padding-top: var(--anchor-offset);
  background: var(--bg-base);
  -webkit-text-size-adjust: 100%;
}

body {
  position: relative;
  margin: 0;
  min-height: 100%;
  color: var(--fg);
  /* Transparent, not --bg-base. <html> carries the opaque canvas colour; if
     <body> paints its own opaque fill too it covers body::before / ::after,
     which sit at z-index -3/-2 in the ROOT stacking context (body is
     position:relative with z-index:auto, so it establishes none). That is what
     was burying the whole ambient layer. */
  background: transparent;
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, svg, video { display: block; max-width: 100%; }
a { color: inherit; }
button, input, textarea, select { font: inherit; color: inherit; }
hr { border: 0; height: 1px; background: var(--border); }

::selection { background: var(--accent); color: #fff; }

/* Focus: never removed, always replaced. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}
a:focus-visible, button:focus-visible, input:focus-visible,
textarea:focus-visible, select:focus-visible, summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* On the dark bookends the slate-blue ring would sink, so it inverts there. */
.site-footer :focus-visible { outline-color: #FFFFFF; }

/* ------------------------------------------- 03 Ambient background layers */
/* Base gradient + turbulence noise, painted on body::before (fixed). */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -3;
  pointer-events: none;
  background:
    /* Light-theme atmosphere: three very soft blue washes over pure white.
       Deliberately restrained. On white, a strong blurred pool reads as a
       dirty screen rather than as depth, so these alphas were tuned DOWN from
       rendered-pixel measurements, not chosen from the token table: composited
       with the two .ambient blobs and the grid, the darkest backdrop pixel
       anywhere on the page is #F0F2F4, which keeps --fg-muted at 4.51:1. */
    radial-gradient(70vw 60vh at 22% 52%, rgba(25, 94, 161, .016), transparent 70%),
    radial-gradient(60vw 55vh at 88% 78%, rgba(25, 94, 161, .017), transparent 72%),
    linear-gradient(to bottom, #F9FBFC 0%, #FFFFFF 42%, #FFFFFF 100%);
}

/* Noise + 64px grid share body::after (two stacked background layers). */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background-image:
    linear-gradient(to right, var(--slate) 1px, transparent 1px),
    linear-gradient(to bottom, var(--slate) 1px, transparent 1px);
  background-size: 64px 64px, 64px 64px;
  /* A technical-drawing substrate, visible but never competing with type.
     The grid is a FIXED layer behind every white section, so body copy really
     does sit on top of these hairlines — measured from rendered pixels, .05
     put the darkest backdrop at #DEE4E8 and dropped --fg-muted to 3.94:1.
     At .028 the darkest grid pixel is ~#EFF2F4 and muted text clears 4.5:1. */
  opacity: .028;
}

/* Separate noise plane so it can carry its own opacity (.015). */
.ambient::before,
.ambient::after { content: ""; }

.ambient {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;          /* contains blobs -> no horizontal overflow */
  pointer-events: none;
}

/* Noise plane — the third <i> inside .ambient, so it carries its own
   opacity (.015) without fading the blobs. */
.ambient > i.ambient-noise {
  position: absolute;
  inset: 0;
  width: auto;
  height: auto;
  border-radius: 0;
  filter: none;
  animation: none;
  /* Dropped on light. The feTurbulence plane is a dark grain; over white it
     reads as a dirty screen rather than as texture, and it costs the page its
     cleanliness for nothing. The rule is kept so the node motion.js injects
     is still styled and inert. */
  display: none;
  opacity: 0;
  /* feTurbulence noise, inline data URI, no network request */
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  background-repeat: repeat;
}

/* Blobs 1-4 — WASH REMOVED.
   On white these blurred pools had no geometry to justify them: the one over
   the process section read as a smudge on the paper rather than as depth,
   while the 64px grid is doing the real atmospheric work. The rules are kept
   (sized, positioned, inert) so the node motion.js injects is still styled and
   so the layer can be reinstated by restoring a background here. Removing them
   also lifts the darkest background pixel, which buys back contrast headroom. */
/* Blob 1 — large accent pool, top-left */
.ambient::before {
  position: absolute;
  top: -22vh;
  left: -18vw;
  width: min(1400px, 120vw);
  height: min(1400px, 120vw);
  border-radius: 50%;
  background: none;
  filter: none;
  opacity: 0;
  animation: ambient-float-a 9s ease-in-out infinite;
}

/* Blob 2 — slate atmosphere, bottom-right */
.ambient::after {
  position: absolute;
  right: -24vw;
  bottom: -26vh;
  width: min(1200px, 110vw);
  height: min(1200px, 110vw);
  border-radius: 50%;
  background: none;
  filter: none;
  opacity: 0;
  animation: ambient-float-b 10s ease-in-out infinite;
}

/* Blobs 3 + 4 — injected/authored inner <i> elements */
.ambient > i {
  position: absolute;
  display: block;
  border-radius: 50%;
  pointer-events: none;
}
.ambient > i.ambient-c {
  top: 28vh;
  right: -14vw;
  width: min(1100px, 105vw);
  height: min(1100px, 105vw);
  background: none;
  filter: none;
  opacity: 0;
  animation: ambient-float-b 8.5s ease-in-out infinite;
}
.ambient > i.ambient-d {
  bottom: 6vh;
  left: -10vw;
  width: min(1000px, 100vw);
  height: min(1000px, 100vw);
  background: none;
  filter: none;
  opacity: 0;
  animation: ambient-float-a 10s ease-in-out infinite reverse;
}

@keyframes ambient-float-a {
  0%, 100% { transform: translateY(-20px) rotate(-1deg); }
  50%      { transform: translateY(20px) rotate(1deg); }
}
@keyframes ambient-float-b {
  0%, 100% { transform: translateY(20px) rotate(1deg); }
  50%      { transform: translateY(-20px) rotate(-1deg); }
}

/* --------------------------------------------------------- 04 Typography */
h1, h2, h3, h4, p { margin-top: 0; }

/* Progressive enhancement: silently ignored where unsupported. */
h1, h2 { text-wrap: balance; }
p, .lede, .hero-lede { text-wrap: pretty; }

h1, h2, h3, h4 {
  color: var(--fg);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.05;
}

h1, .display {
  margin-bottom: 1.5rem;
  font-size: clamp(2.5rem, 5.2vw, 4.25rem);
}
h2 {
  margin-bottom: 1.25rem;
  font-size: clamp(2rem, 3.8vw, 3rem);
}
h3 {
  margin-bottom: .75rem;
  font-size: clamp(1.15rem, 1.6vw, 1.35rem);
  line-height: 1.25;
  letter-spacing: -0.02em;
}
h4 {
  margin-bottom: .6rem;
  font-size: 1rem;
  line-height: 1.35;
  letter-spacing: -0.01em;
}

p, li { color: var(--fg-muted); line-height: 1.65; }
.lede {
  max-width: 54ch;
  color: var(--fg-muted);
  font-size: clamp(1.05rem, 1.6vw, 1.3rem);
  line-height: 1.55;
}

strong { color: var(--fg); font-weight: 600; }

/* Prose links use the brighter accent for contrast. */
p a, li a, .prose a, .text-link {
  color: var(--accent);
  text-underline-offset: .25em;
  transition: color var(--t-fast) var(--ease-expo);
}
p a:hover, li a:hover, .prose a:hover, .text-link:hover { color: var(--accent-deep); }

/* Self-sufficient prose block: measure + vertical rhythm.
   Composes safely with .section-body (the narrower max-width wins). */
.prose {
  max-width: 64ch;
  color: var(--fg-muted);
}
.prose > :first-child { margin-top: 0; }
.prose > :last-child { margin-bottom: 0; }
.prose p { margin: 0 0 1.15rem; }
.prose h2 { margin: 2.5rem 0 1rem; }
.prose h3 { margin: 2rem 0 .65rem; }
.prose ul, .prose ol { margin: 0 0 1.15rem; padding-left: 1.25rem; }
.prose li { margin-bottom: .45rem; padding-left: .15rem; }
.prose li::marker { color: var(--fg-subtle); }
.prose li > ul, .prose li > ol { margin: .45rem 0 0; }
.prose hr, .prose .rule { margin: 2rem 0; }
/* When both are applied, keep the tighter measure. */
.section-body.prose { max-width: 56ch; }

/* ---------------------------------------------------------- 05 Utilities */
.label, .eyebrow {
  display: block;
  margin: 0 0 1.25rem;
  color: var(--fg-subtle);
  font-family: var(--mono);
  font-size: .72rem;
  font-weight: 500;
  letter-spacing: .18em;
  line-height: 1.3;
  text-transform: uppercase;
}

/* Fallback colour set BEFORE the clip so unsupported browsers still paint. */
.text-gradient {
  color: var(--fg);
  /* Re-specified for light: a shallow slate ramp, deep at the cap line and
     settling onto the exact logo slate. Both stops are solid and darker than
     or equal to --fg, so every line stays >=9.9:1 on white — the effect is
     weight, not fade. */
  background: linear-gradient(to bottom, #263640 0%, #34454F 58%, #34454F 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .text-gradient { color: var(--fg); background: none; }
}

.rule {
  height: 1px;
  border: 0;
  background: linear-gradient(to right, transparent, rgba(52, 69, 79, .26), transparent);
}

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

.skip-link {
  position: fixed;
  left: 1rem;
  top: -5rem;
  z-index: 60;
  padding: .7rem 1.1rem;
  border: 1px solid var(--border-accent);
  border-radius: var(--radius-sm);
  color: #fff;
  background: var(--accent-deep);
  text-decoration: none;
  font-size: .85rem;
  font-weight: 600;
  transition: top var(--t-base) var(--ease-expo);
}
.skip-link:focus, .skip-link:focus-visible { top: 1rem; }

.trap-field { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }

/* ------------------------------------------------------------- 06 Layout */
.container { width: min(calc(100% - 3rem), var(--max)); margin: 0 auto; }

.section { position: relative; padding: clamp(4rem, 9vw, 8rem) 0; }
.section + .section { border-top: 1px solid var(--border); }
.section-pad { padding: clamp(4rem, 9vw, 8rem) 0; }
.section-intro { max-width: 58ch; }
.narrow-intro { margin-bottom: clamp(2.5rem, 5vw, 3.5rem); }

/* Bento grid — deliberately non-uniform at desktop. */
.bento {
  display: grid;
  grid-template-columns: 1fr;
  grid-auto-rows: minmax(180px, auto);
  gap: 1rem;
  /* list reset so .bento can be an <ol>/<ul> of <li> cards */
  margin: 0;
  padding: 0;
  list-style: none;
}
/* Every bento child is a grid item that must be allowed to shrink. */
.bento > * { min-width: 0; max-width: 100%; }
/* Single-column default: all span helpers are inert until 768px. */
.span-2, .span-3, .span-4, .span-6, .row-2 { grid-column: auto; }

/* Tablet band. A 3-column track cannot resolve the 6-column span mix
   (span-4 -> full row, span-2 -> two thirds) without leaving a dead gutter
   down the right side, so this band runs its own 2-column composition: the
   wide card takes a full row, the pair below it takes half a row each. No card
   stops short of another card's edge. */
@media (min-width: 768px) and (max-width: 1023px) {
  .bento { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.25rem; }
  .span-2 { grid-column: span 1; }   /* half row */
  .span-3 { grid-column: 1 / -1; }
  .span-4 { grid-column: 1 / -1; }   /* full row */
  .span-6 { grid-column: 1 / -1; }
  /* A full-row card must not also claim two rows, or the half cards beside it
     would have nothing to sit next to. */
  .row-2 { grid-row: auto; }
}
@media (min-width: 1024px) {
  .bento { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 1.5rem; }
  .span-2 { grid-column: span 2; }
  .span-3 { grid-column: span 3; }
  .span-4 { grid-column: span 4; }
  .span-6 { grid-column: 1 / -1; }   /* full-bleed row at 6 cols */
  .row-2 { grid-row: span 2; }
}

.split-section {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2.5rem, 7vw, 7rem);
  align-items: start;
}
.section-body { max-width: 56ch; }
.section-body p + p { margin-top: 1.1rem; }

/* --------------------------------------------------------- 07 Components */

/* --- Buttons --- */
.button {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: 44px;
  padding: .7rem 1.25rem;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-size: .92rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-decoration: none;
  cursor: pointer;
  overflow: hidden;
  background: none;
  transition:
    background-color var(--t-fast) var(--ease-expo),
    border-color var(--t-fast) var(--ease-expo),
    color var(--t-fast) var(--ease-expo),
    box-shadow var(--t-fast) var(--ease-expo),
    transform var(--t-fast) var(--ease-expo);
}
.button:active { transform: scale(.98); }

.button-primary {
  color: #fff;
  background: var(--accent);
  box-shadow:
    0 1px 2px rgba(18, 71, 121, .30),
    0 4px 12px rgba(25, 94, 161, .25),
    inset 0 1px 0 rgba(255, 255, 255, .20);
}
.button-primary:hover, .button-primary:focus-visible {
  background: var(--accent-deep);
  box-shadow:
    0 1px 2px rgba(18, 71, 121, .34),
    0 8px 20px rgba(25, 94, 161, .30),
    inset 0 1px 0 rgba(255, 255, 255, .20);
}
/* shine sweep */
.button-primary::after {
  content: "";
  position: absolute;
  top: 0;
  left: -120%;
  width: 60%;
  height: 100%;
  pointer-events: none;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .28), transparent);
  transition: left var(--t-enter) var(--ease-expo);
}
.button-primary:hover::after, .button-primary:focus-visible::after { left: 140%; }

.button-secondary {
  color: var(--fg);
  background: #FFFFFF;
  border-color: var(--border-hover);
  box-shadow:
    0 1px 2px rgba(52, 69, 79, .06),
    0 2px 8px rgba(52, 69, 79, .07);
}
.button-secondary:hover, .button-secondary:focus-visible {
  color: var(--accent-deep);
  background: #FFFFFF;
  border-color: var(--accent);
  box-shadow:
    0 1px 2px rgba(52, 69, 79, .08),
    0 4px 14px rgba(52, 69, 79, .10);
}

.button-ghost {
  color: var(--fg-muted);
  background: transparent;
  border-color: transparent;
}
.button-ghost:hover, .button-ghost:focus-visible {
  color: var(--fg);
  background: var(--surface);
}

.button[disabled], .button:disabled { opacity: .55; cursor: default; transform: none; }

.text-link {
  font-size: .92rem;
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid var(--border-accent);
  padding-bottom: 2px;
}
.text-link span { display: inline-block; margin-left: .35rem; transition: transform var(--t-fast) var(--ease-expo); }
.text-link:hover span { transform: translateX(3px); }

/* --- Card --- */
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(1.25rem, 2.2vw, 1.75rem);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  /* On light, a card is separated by border + shadow, not by fill: it stays
     white and the page tint behind it does the work. */
  background: var(--bg-elevated);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  isolation: isolate;
  transition:
    transform var(--t-base) var(--ease-expo),
    border-color var(--t-base) var(--ease-expo),
    box-shadow var(--t-base) var(--ease-expo);
}
/* 1px top-edge accent. The dark system used a white highlight to catch the
   light; on white the same gesture has to be a darker line to read at all. */
.card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(to right, transparent, rgba(25, 94, 161, .28), transparent);
}
.card:hover, .card:focus-within {
  transform: translateY(-4px);
  border-color: var(--border-accent);
  box-shadow: var(--shadow-card-hover);
}
.card > * { position: relative; z-index: 1; }
.card h3 { color: var(--fg); }
.card p:last-child { margin-bottom: 0; }

/* Mouse-tracking spotlight (JS sets --mx / --my). */
.card[data-spotlight]::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(300px circle at var(--mx, 50%) var(--my, 50%), var(--accent-tint), transparent 70%);
  transition: opacity var(--t-base) var(--ease-expo);
}
.card[data-spotlight]:hover::after, .card[data-spotlight]:focus-within::after { opacity: 1; }

/* --- Pill / badge --- */
.pill, .badge {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .3rem .75rem;
  border: 1px solid var(--border-accent);
  border-radius: 999px;
  background: var(--surface);
  color: var(--fg-muted);
  font-family: var(--mono);
  font-size: .7rem;
  font-weight: 500;
  letter-spacing: .12em;
  line-height: 1.4;
  text-transform: uppercase;
  white-space: nowrap;
}
.badge { color: var(--accent-bright); }

/* Row of pills/badges — real gap, no whitespace-node spacing. */
.pill-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
/* If used as a list, put .pill/.badge on the <li> itself. */
.pill-row > li { min-width: 0; }
/* Used as a tag footer under body copy, so it needs air above it — but only
   when something actually precedes it. The :not(:first-child) guard keeps a
   pill row that opens a card flush, and a plain margin-top still collapses
   correctly against a preceding block's margin-bottom. */
.pill-row:not(:first-child) { margin-top: 1.5rem; }

/* --- Forms --- */
.field-row { margin-bottom: 1.35rem; }
.field-row label {
  display: block;
  margin-bottom: .45rem;
  color: var(--fg);
  font-size: .84rem;
  font-weight: 600;
}
.optional { margin-left: .35rem; color: var(--fg-subtle); font-size: .78rem; font-weight: 400; }

input[type="text"], input[type="email"], input[type="tel"], input[type="url"],
input[type="search"], textarea, select,
.field-row input, .field-row textarea {
  width: 100%;
  padding: .75rem .85rem;
  color: var(--fg);
  background: #FFFFFF;
  border: 1px solid var(--border-field);
  border-radius: var(--radius-sm);
  transition:
    border-color var(--t-fast) var(--ease-expo),
    box-shadow var(--t-fast) var(--ease-expo);
}
::placeholder { color: var(--fg-subtle); opacity: 1; }
.field-row textarea, textarea { min-height: 140px; resize: vertical; }

input:focus, textarea:focus, select:focus {
  outline: none;                                  /* replaced by the ring below */
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-tint);
}
input:focus-visible, textarea:focus-visible, select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.field-row.is-invalid input, .field-row.is-invalid textarea { border-color: #B3261E; }
.field-error { display: block; min-height: 1.2em; margin-top: .3rem; color: #B3261E; font-size: .79rem; }
.privacy-note { margin: 1rem 0 0; color: var(--fg-subtle); font-size: .79rem; }
.form-status { margin: 1rem 0 0; color: var(--fg-muted); font-size: .84rem; }
.form-status.is-error { color: #B3261E; }     /* 6.36:1 on white */
.form-status.is-success { color: #10684A; }   /* 6.28:1 on white */

/* --- Header --- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 30;
  background: rgba(255, 255, 255, .78);
  border-bottom: 1px solid var(--border);
}
@supports ((backdrop-filter: blur(16px)) or (-webkit-backdrop-filter: blur(16px))) {
  .site-header {
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
  }
}
/* Fallback when backdrop-filter is unsupported: opaque enough to stay legible */
@supports not ((backdrop-filter: blur(16px)) or (-webkit-backdrop-filter: blur(16px))) {
  .site-header { background: #FFFFFF; }
}
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  min-height: 76px;
  padding-top: .75rem;
  padding-bottom: .75rem;
}
.brand { display: inline-flex; align-items: center; min-height: 44px; }
/* NO FILTER. The brand master paints hull, masts and wordmark in #34454F and
   the flag/sails in #195EA1. Both are drawn for paper, and on the white header
   they land at 9.93:1 and 6.65:1 respectively — so the asset renders exactly
   as authored. The dark system needed a contrast()/brightness() lift here;
   that is the whole reason the page went light, and it is gone. */
.brand img,
.site-header .brand img {
  width: 176px;
  height: auto;
  filter: none;
}
/* (The footer carries no logo, so there is no dark surface the mark sits on
   and no filter anywhere in the system.) */

.site-nav {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.2vw, 2rem);
  color: var(--fg-muted);
  font-size: .88rem;
}
.site-nav a {
  text-decoration: none;
  transition: color var(--t-fast) var(--ease-expo);
}
.site-nav a:hover, .site-nav a:focus-visible { color: var(--fg); }
.language-link { color: var(--accent-bright); font-weight: 600; letter-spacing: .06em; }

.nav-toggle {
  display: none;
  align-items: center;
  min-height: 44px;
  padding: .5rem .75rem;
  border: 1px solid var(--border-hover);
  border-radius: var(--radius-sm);
  color: var(--fg);
  background: var(--surface);
  cursor: pointer;
  font-size: .82rem;
  font-weight: 600;
}
.nav-toggle:hover { background: var(--surface-hover); }

/* --- Footer --- */
.site-footer {
  position: relative;
  z-index: 1;
  padding: 2.5rem 0;
  /* #C8D2D8 on #34454F = 6.19:1 — the muted footer tone still clears 4.5:1. */
  color: #C8D2D8;
  background: var(--footer-bg);      /* logo slate as a dark bookend */
  border-top: 1px solid var(--footer-bg);
}
.site-footer p, .site-footer li { color: #C8D2D8; }
.footer-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  font-size: .82rem;
}
.footer-inner p { margin: 0; }
.footer-links { display: flex; flex-wrap: wrap; gap: 1.25rem; }
.footer-links a { color: #E4EAEE; text-underline-offset: .25em; }  /* 8.24:1 */
.footer-links a:hover { color: #FFFFFF; }

/* ------------------------------------------- 08 Legacy page components */
.hero {
  position: relative;
  isolation: isolate;
  background: radial-gradient(ellipse at 90% 10%, rgba(130, 178, 219, .24), transparent 60%), linear-gradient(135deg, #F3F7FA, #E3EDF5);
  border-bottom: 1px solid var(--border);
}
.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(2.5rem, 4vw, 4.5rem);
}
.hero-copy { max-width: 760px; }
.hero-copy h1 {
  font-size: clamp(3rem, 5.6vw, 5rem);
  line-height: 1.03;
  letter-spacing: -.045em;
}
.hero-emphasis { color: var(--accent); }
.hero-lede {
  max-width: 52ch;
  margin-bottom: 2.25rem;
  color: var(--fg-muted);
  font-size: clamp(1.125rem, 1.65vw, 1.5rem);
  line-height: 1.55;
}
.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1.25rem; }

.hero-media {
  position: relative;
  min-height: clamp(440px, 40vw, 600px);
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--bg-subtle);
  box-shadow: 0 12px 30px rgba(27, 57, 82, .16), 0 28px 65px rgba(27, 57, 82, .12);
}
.hero-media > picture { display: contents; }
.hero-media > picture > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Nine equal cards keep every capability easy to scan. */
.capability-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.25rem;
}
.capability-card { min-width: 0; }
.capability-icon {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  margin-bottom: 1.5rem;
  border-radius: var(--radius-sm);
  color: var(--accent);
  background: var(--accent-tint);
}
.capability-icon svg { width: 1.5rem; height: 1.5rem; }
.capability-card h3 { margin-bottom: 1rem; font-size: 1.15rem; }
.capability-card ul { margin: 0; padding: 0; list-style: none; font-size: .9rem; }
.capability-card li { padding: .5rem 0; border-top: 1px solid var(--border); }

/* Ordered in the markup; visually expressed as concise milestones. */
.project-stages {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2.5rem 3rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.project-stage { min-width: 0; border-top: 1px solid var(--border-accent); padding-top: 1.25rem; }
.project-stage h3 { margin-bottom: 1rem; font-size: 1.15rem; }
.project-stage ul { margin: 0; padding-left: 1.1rem; font-size: .95rem; }
.project-stage li { padding-left: .2rem; margin-bottom: .45rem; }
.project-stage li::marker { color: var(--accent); }

.about-grid { align-items: end; }
.contact-grid { display: grid; grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); gap: clamp(2.5rem, 7vw, 7rem); align-items: start; }
.contact-email { display: inline-block; margin-top: 1rem; color: var(--accent-bright); font-size: 1.1rem; font-weight: 600; text-underline-offset: .25em; }
.contact-form { max-width: 560px; }

.credits-nav { display: flex; flex-wrap: wrap; align-items: center; gap: 1.25rem; font-size: .88rem; color: var(--fg-muted); }
.credits-nav a { text-decoration: none; }
.credits-nav a:hover, .credits-nav a:focus-visible { color: var(--fg); }
details { margin-top: 1rem; }
summary { color: var(--accent-bright); cursor: pointer; font-weight: 600; }
details pre {
  max-width: 100%;
  margin: 1rem 0 0;
  padding: 1rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--fg-muted);
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font: .78rem/1.55 var(--mono);
}

/* Distinct section backgrounds give the page depth and a clear rhythm. */
#capabilities { background: #EAF0F5; }
.section-light { background: var(--bg-subtle); }
.section-blue {
  --fg: #F5F8FC;
  --fg-muted: #CFDCE7;
  --fg-subtle: #AAC6DC;
  --border: rgba(207, 220, 231, .20);
  --border-accent: rgba(140, 200, 255, .50);
  --accent: #8CC8FF;
  background: radial-gradient(ellipse at 100% 0%, rgba(32, 90, 137, .50), transparent 70%), #142C3F;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.section-ink {
  background: #DEE8F0;
  border-bottom: 1px solid var(--border);
}
.contact-section { background: #F3F7FA; }
.section-blue + .section, .section-ink + .section { border-top: 0; }
.section-blue h2, .section-blue h3 { color: var(--fg); }
.section-intro p:not(.eyebrow):not(.label), .section-body p { color: var(--fg-muted); font-size: 1.05rem; }

/* --------------------------------- 08b Desktop composition */
@media (min-width: 1024px) {
  /* Hero vertical rhythm. The shared section rhythm (up to 8rem top and
     bottom) pushed the hero past a 900px-tall viewport once the 134px sticky
     header is counted, so the fold landed in empty white. Still generous,
     just deliberate. */
  .hero.section-pad { padding-top: clamp(3.5rem, 5vw, 5rem); padding-bottom: clamp(3.5rem, 5vw, 5rem); }

  /* --- About: heading left, prose right, divided by a hairline. Quiet, but
     composed — and the section finally uses its container. --- */
  .about-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: clamp(3rem, 6vw, 5rem);
    align-items: start;
  }
  .about-layout .section-intro { max-width: none; margin-bottom: 0; }
  .about-layout .section-body.prose {
    max-width: none;
    padding-left: clamp(2rem, 4vw, 3rem);
    border-left: 1px solid var(--border);
  }
  .about-layout .section-body.prose p { max-width: 60ch; }


}

/* ------------------------------------------------------------- 09 Motion */
/* Elements are visible by default; only the .js class hides them. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(20px);
  transition:
    opacity var(--t-enter) var(--ease-expo),
    transform var(--t-enter) var(--ease-expo);
  transition-delay: var(--reveal-delay, 0s);
  will-change: opacity, transform;
}
.js [data-reveal].is-visible { opacity: 1; transform: none; }

/* Hero parallax target (JS writes the custom properties). */
.js [data-parallax] {
  opacity: var(--parallax-opacity, 1);
  transform: translateY(var(--parallax-y, 0px)) scale(var(--parallax-scale, 1));
  will-change: opacity, transform;
}

/* --------------------------------------------------------- 10 Responsive */
@media (max-width: 1023px) {
  .hero-grid, .contact-grid, .split-section { grid-template-columns: minmax(0, 1fr); gap: 3rem; }
  .hero-copy { max-width: 820px; }
  .capability-grid, .project-stages { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hero-media { min-height: min(74vw, 560px); }
}

@media (max-width: 767px) {
  .container { width: min(calc(100% - 2rem), var(--max)); }
  .brand img { width: 150px; }

  /* Mobile menu panel — markup/ARIA unchanged, styling only. */
  .js .nav-toggle { display: inline-flex; }
  .js .site-nav {
    position: absolute;
    top: 100%;
    right: 0;
    left: 0;
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: .5rem 1rem 1rem;
    background: rgba(255, 255, 255, .97);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow-card-hover);
  }
  @supports ((backdrop-filter: blur(16px)) or (-webkit-backdrop-filter: blur(16px))) {
    .js .site-nav { -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px); }
  }
  .js .site-nav.is-open { display: flex; }
  .js .site-nav a {
    padding: .8rem .25rem;
    border-bottom: 1px solid var(--border);
  }
  .js .site-nav a:last-child { border-bottom: 0; }

  .hero-copy h1 { font-size: clamp(2.6rem, 10.5vw, 4rem); }
  .hero-media { min-height: 0; aspect-ratio: 4 / 3; }
  .footer-inner { flex-direction: column; align-items: flex-start; }
  h1, .display { font-size: clamp(2.25rem, 10vw, 3.25rem); }
}

@media (max-width: 639px) {
  .capability-grid, .project-stages { grid-template-columns: minmax(0, 1fr); }
  .project-stages { gap: 1.5rem; }
}

@media (max-width: 420px) {
  .container { width: min(calc(100% - 1.5rem), var(--max)); }
}

/* ------------------------------------------ 11 prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .ambient::before, .ambient::after, .ambient > i { animation: none !important; }
  .js [data-reveal] { opacity: 1 !important; transform: none !important; }
  .js [data-parallax] { opacity: 1 !important; transform: none !important; }
  .card[data-spotlight]::after { display: none; }
  .card:hover { transform: none; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
    transition-duration: .01ms !important;
  }
}
