:root {
  /* ---- brand source colors (only three hand-picked values in the whole system) ---- */
  --navy: #141c27;
  --silver: #bfc4ca;
  --bronze: #b0733d;
  --ink: #0c1219;

  /* ---- derived tints/shades: every other color is computed from the three above ---- */
  --navy-deep: color-mix(in srgb, var(--navy) 100%, black 30%);
  --bronze-light: color-mix(in srgb, var(--bronze) 100%, white 22%);
  --line: rgba(191, 196, 202, 0.16);
  --line-strong: rgba(191, 196, 202, 0.28);

  /* ---- layout gutter: first column of any full-bleed grid aligns here ---- */
  --gutter: 48px;

  /* ---- spacing scale: all section padding / gaps / margins derive from this ---- */
  --space-xs: 8px;
  --space-sm: 16px;
  --space-md: 24px;
  --space-lg: 40px;
  --space-xl: 64px;
  --space-2xl: 96px;
  --space-3xl: 128px;

  /* ---- one section-to-section rhythm, reused everywhere so gaps read as identical while scrolling ---- */
  --section-pad: var(--space-3xl);
}

@media (max-width: 900px) {
  :root {
    --gutter: 24px;
    --section-pad: var(--space-xl);
  }
}

@media (max-width: 640px) {
  :root {
    --gutter: 20px;
    --section-pad: var(--space-lg);
  }
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  background: var(--navy);
  color: var(--silver);
  font-family: "Inter", sans-serif;
  line-height: 1.5;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

img,
video {
  display: block;
  max-width: 100%;
}

.display {
  font-family: "Fraunces", serif;
}

.mono {
  font-family: "IBM Plex Mono", monospace;
  letter-spacing: 0.02em;
}

.wrap {
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 var(--gutter);
}

a {
  color: inherit;
}

/* ---- page loader ---- */
#pageLoader {
  position: fixed;
  inset: 0;
  z-index: 999;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--navy);
  transition:
    opacity 0.5s ease,
    visibility 0.5s ease;
}

#pageLoader.loader-hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.orbital-loader {
  position: relative;
  width: 56px;
  height: 56px;
}

.orbital-loader .ring {
  position: absolute;
  inset: 0;
  border: 2px solid transparent;
  border-radius: 50%;
}

.orbital-loader .ring--1 {
  border-top-color: var(--bronze-light);
  animation: orbitalSpin 1s linear infinite;
}

.orbital-loader .ring--2 {
  inset: 9px;
  border-top-color: var(--silver);
  animation: orbitalSpinReverse 1.5s linear infinite;
}

.orbital-loader .ring--3 {
  inset: 18px;
  border-top-color: var(--bronze);
  animation: orbitalSpin 0.75s linear infinite;
}

@keyframes orbitalSpin {
  to {
    transform: rotate(360deg);
  }
}

@keyframes orbitalSpinReverse {
  to {
    transform: rotate(-360deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .orbital-loader .ring {
    animation: none;
  }

  .orbital-loader .ring--1 {
    border-color: var(--line-strong);
    border-top-color: var(--bronze-light);
  }
}

/* ---- fiber thread motif ----
   Lives in the margin between the content column's right edge and the
   viewport's right edge. It must never reach the body copy (bright filament
   strokes running through pull-quotes, list rows and table cells) and must
   never spill past the viewport (the drawing gets cut in half). That margin
   is only ~176px wide on a 1536px viewport and ~368px on a 1920px one, so
   the thread's width tracks it instead of being fixed. */
.fiber-thread {
  position: fixed;
  top: 0;
  /* Pinned to the viewport's right edge, and sized to whatever margin is
     actually free beside the content column — never given a fixed 340px box.
     A fixed width has to be positioned from one side or the other: anchored
     to the content edge it runs off-screen on anything narrower than ~1920px
     (a 1920 monitor at 125% Windows scaling is a 1536px viewport, which cut
     ~190px off the ribbon); anchored to the viewport edge it runs back into
     the body copy. Letting the width flex keeps the whole drawing on-screen
     at every viewport width and DPI scale.

     612px = 592px (the wrap's content edge: 1280/2 - 48px gutter) + 20px
     clearance. `%` on a fixed element resolves against the initial containing
     block, which includes the scrollbar, so the extra keeps real clearance
     rather than exactly 0. */
  right: 0;
  left: auto;
  height: 100vh;
  width: min(340px, calc(50% - 612px));
  pointer-events: none;
  z-index: 0;
  opacity: 1;
}

/* preserveAspectRatio="none" scales the strokes with the box, so a narrower
   thread would also draw thinner, fainter filaments. Pin the stroke widths to
   device pixels so the bundle reads identically at every width. */
.fiber-thread path,
.fiber-thread line {
  vector-effect: non-scaling-stroke;
}

/* below this the free margin is under ~90px — too narrow for the bundle to
   read as anything but a squashed sliver, so drop it entirely */
@media (max-width: 1400px) {
  .fiber-thread {
    display: none;
  }
}

/* ---- nav ---- */
nav {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-md) var(--gutter);
  background: rgba(20, 28, 39, 0.85);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}

.logo-mark {
  display: flex;
  align-items: center;
}

.logo-mark img {
  height: 100px;
  width: auto;
}

.nav-links {
  display: flex;
  gap: 34px;
  list-style: none;
}

.nav-links a {
  position: relative;
  display: inline-block;
  color: var(--silver);
  text-decoration: none;
  font-size: 16px;
  letter-spacing: 0.02em;
  padding: 6px 4px;
  transition:
    color 0.2s,
    transform 0.2s;
}

.nav-links a:hover {
  color: var(--bronze-light);
}

.nav-links a::after {
  content: "";
  position: absolute;
  left: 4px;
  right: 4px;
  bottom: -1px;
  height: 2px;
  background: var(--bronze-light);
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.25s;
}

.nav-links a:hover::after {
  transform: scaleX(1);
}

.nav-links a.active {
  color: #f2f0ec;
  transform: translateY(-1px);
}

.nav-links a.active::after {
  background: var(--bronze);
  transform: scaleX(1);
}

.nav-cta {
  background: transparent;
  border: 1px solid var(--bronze);
  border-radius: 8px;
  color: var(--bronze-light);
  padding: 10px 22px;
  font-size: 16px;
  letter-spacing: 0.04em;
  text-decoration: none;
  transition: all 0.25s;
  white-space: nowrap;
}

.nav-cta:hover {
  background: var(--bronze);
  color: var(--navy-deep);
}

@media (max-width: 900px) {
  .nav-cta {
    display: none;
  }
}

.nav-burger {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px;
}

.nav-burger span {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--silver);
  margin: 5px 0;
}

.mobile-menu {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 60;
  background: var(--navy);
  padding: var(--space-md) var(--space-lg);
  flex-direction: column;
}

.mobile-menu.open {
  display: flex;
}

.mobile-menu-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--space-2xl);
}

.mobile-menu a {
  color: var(--silver);
  text-decoration: none;
  font-size: 22px;
  font-family: "Fraunces", serif;
  padding: 16px 0;
  border-bottom: 1px solid var(--line);
}

.mobile-close {
  background: none;
  border: none;
  color: var(--silver);
  font-size: 28px;
  cursor: pointer;
  line-height: 1;
}

@media (max-width: 900px) {
  .nav-links {
    display: none;
  }

  .nav-burger {
    display: block;
  }
}

/* ---- hero ---- */
.hero {
  position: relative;
  z-index: 1;
  min-height: 94vh;
  display: flex;
  align-items: center;
  overflow: hidden;
}

.hero-media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.hero-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

.hero-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg,
      rgba(20, 28, 39, 0.92) 0%,
      rgba(20, 28, 39, 0.55) 45%,
      rgba(20, 28, 39, 0.25) 100%);
}

.hero-video-mobile {
  display: none;
}

@media (max-width: 767px) {
  .hero-video-desktop {
    display: none;
  }

  .hero-video-mobile {
    display: block;
  }

  .hero-media::after {
    background: linear-gradient(180deg,
        rgba(20, 28, 39, 0.55) 0%,
        rgba(20, 28, 39, 0.75) 55%,
        rgba(20, 28, 39, 0.95) 100%);
  }
}

.hero-inner {
  position: relative;
  z-index: 2;
  max-width: 760px;
  padding: var(--space-lg) var(--gutter);
}

.eyebrow {
  font-size: 12px;
  letter-spacing: 0.16em;
  color: var(--bronze-light);
  text-transform: uppercase;
  margin-bottom: var(--space-md);
  display: block;
}

h1.hero-head {
  font-size: clamp(34px, 5.2vw, 68px);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.01em;
  color: #f2f0ec;
  margin-bottom: var(--space-lg);
}

.hero-sub {
  font-size: 17px;
  color: var(--silver);
  max-width: 520px;
  margin-bottom: var(--space-2xl);
  line-height: 1.65;
}

.hero-ctas {
  display: flex;
  gap: var(--space-md);
  flex-wrap: wrap;
}

.btn-primary {
  background: var(--bronze);
  color: #0c1219;
  border: none;
  border-radius: 8px;
  padding: 15px 30px;
  font-size: 14px;
  letter-spacing: 0.03em;
  font-weight: 600;
  text-decoration: none;
  display: inline-block;
  transition: background 0.25s;
}

.btn-primary:hover {
  background: var(--bronze-light);
}

.btn-secondary {
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  color: #f2f0ec;
  padding: 15px 30px;
  font-size: 14px;
  letter-spacing: 0.03em;
  text-decoration: none;
  display: inline-block;
  transition: border-color 0.25s;
}

.btn-secondary:hover {
  border-color: var(--silver);
}

@media (max-width: 640px) {
  .hero-inner {
    padding: var(--space-md) var(--gutter);
  }

  .hero {
    min-height: 100vh;
  }
}

/* ---- section shared ---- */
section {
  position: relative;
  z-index: 1;
}

.section-head {
  max-width: 640px;
  margin-bottom: var(--space-xl);
}

.section-eyebrow {
  font-size: 27px;
  font-weight: 500;
  letter-spacing: 0.14em;
  color: var(--bronze-light);
  text-transform: uppercase;
  margin-bottom: var(--space-md);
  display: block;
}

.section-title {
  font-family: "Fraunces", serif;
  font-weight: 400;
  font-size: clamp(26px, 3.2vw, 40px);
  line-height: 1.16;
  color: #f2f0ec;
}

.section-body {
  font-size: 16px;
  color: var(--silver);
  line-height: 1.75;
  max-width: 700px;
}

/* centered section intro variant, used where a heading should sit on its own as a statement */
.section-head--center {
  max-width: none;
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

.section-head--center .section-eyebrow {
  margin-left: auto;
  margin-right: auto;
}

.why-project .section-head--center .section-eyebrow {
  font-size: clamp(22px, 4vw, 35px);
  letter-spacing: 0.06em;
  max-width: 900px;
}

/* ---- why-project tiles ---- */
.why-project {
  padding: var(--section-pad) 0;
}

.tile-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.tile {
  background: var(--navy);
  padding: var(--space-xl) var(--space-lg);
}

/* Dividers are borders on the tiles themselves, not 1px grid gaps letting
   a lighter container background show through. That older technique put a
   light fill behind the whole grid, and on fractional device-pixel
   boundaries — Windows display scaling, fluid widths below 1280 — its
   outer edge antialiased into a stray hairline down one side of the grid.
   A border can only ever paint between two tiles. */
.tile + .tile {
  border-left: 1px solid var(--line);
}

.tile:nth-child(3n + 1) {
  padding-left: 0;
}

.tile h3 {
  font-family: "Fraunces", serif;
  font-weight: 600;
  font-size: 28px;
  color: #f2f0ec;
  margin-bottom: var(--space-sm);
}

.tile p {
  font-size: 17.5px;
  color: var(--silver);
  line-height: 1.65;
}

@media (max-width: 900px) {
  .tile-grid {
    grid-template-columns: 1fr;
  }

  /* stacked: the divider moves to the top edge of each following tile */
  .tile + .tile {
    border-left: none;
    border-top: 1px solid var(--line);
  }

  .tile:nth-child(3n + 1) {
    padding-left: var(--space-lg);
  }
}

/* ---- process video section ---- */
.process-section {
  padding: 0;
}

.process-media {
  position: relative;
  width: 100%;
  aspect-ratio: 16/9;
  overflow: hidden;
}

.process-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.process-caption {
  max-width: 1280px;
  margin: 0 auto;
  padding: var(--space-lg) var(--gutter) var(--section-pad);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-md);
}

.process-caption p {
  font-size: clamp(15px, 1.3vw, 20px);
  color: var(--silver);
  max-width: none;
  width: 100%;
  line-height: 1.6;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 0.7s ease,
    transform 0.7s ease;
}

.process-caption .tag {
  font-size: 30px;
  font-family: "Fraunces", serif;
  letter-spacing: 0.06em;
  color: var(--bronze-light);
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 0.7s ease,
    transform 0.7s ease;
  transition-delay: 0.25s;
}

.process-section.is-visible .process-caption p,
.process-section.is-visible .process-caption .tag {
  opacity: 1;
  transform: translateY(0);
}

@media (max-width: 900px) {
  .process-caption p {
    white-space: normal;
    font-size: 16px;
  }

  .process-caption .tag {
    font-size: 24px;
  }
}

@media (max-width: 640px) {
  .process-caption {
    padding: var(--space-md) var(--gutter) var(--section-pad);
  }

  .process-caption p {
    font-size: 14.5px;
  }

  .process-caption .tag {
    font-size: 20px;
  }
}

/* ---- stat bar ---- */
.stat-bar {
  position: relative;
  z-index: 1;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  background: var(--navy-deep);
}

.stat {
  padding: var(--space-xl) var(--space-lg);
  border-right: 1px solid var(--line);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.stat:last-child {
  border-right: none;
}

.stat-label {
  font-size: 12.5px;
  letter-spacing: 0.1em;
  color: var(--silver);
  text-transform: uppercase;
  margin-bottom: var(--space-sm);
  opacity: 0.8;
}

.stat-value {
  font-size: clamp(26px, 3vw, 40px);
  color: var(--bronze-light);
  font-weight: 500;
}

@media (max-width: 900px) {
  .stat-bar {
    grid-template-columns: repeat(2, 1fr);
  }

  .stat {
    padding: var(--space-lg) var(--space-md);
    border-bottom: 1px solid var(--line);
  }

  .stat:nth-child(2n) {
    border-right: none;
  }

  .stat:nth-last-child(-n + 2) {
    border-bottom: none;
  }
}

@media (max-width: 640px) {
  .stat-bar {
    grid-template-columns: 1fr;
  }

  .stat {
    border-right: none !important;
    border-bottom: 1px solid var(--line);
  }

  .stat:last-child {
    border-bottom: none;
  }
}

/* ---- why basalt ---- */
.why-basalt {
  padding: var(--section-pad) 0;
}

.basalt-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2xl);
  align-items: start;
}

.basalt-media {
  position: sticky;
  top: 100px;
}

/* rounded here rather than only on the Material page, where the same
   component was already 16px — square corners on Home were the odd one
   out against every other framed image on the site */
.basalt-media img {
  width: 100%;
  border: 1px solid var(--line);
  border-radius: 16px;
}

.shimmer-wrap {
  margin-top: var(--space-sm);
  border: 1px solid var(--line);
  border-radius: 16px;
  overflow: hidden;
}

.shimmer-wrap video {
  width: 100%;
  display: block;
}

.adv-list {
  list-style: none;
  margin: var(--space-lg) 0;
}

.adv-list li {
  display: flex;
  gap: var(--space-md);
  padding: var(--space-sm) 0;
  border-bottom: 1px solid var(--line);
  font-size: 15px;
  color: #e9e7e2;
}

.adv-list li .num {
  font-family: "IBM Plex Mono", monospace;
  color: var(--bronze-light);
  font-size: 13px;
  padding-top: 2px;
}

.pull-quote {
  font-family: "Fraunces", serif;
  font-weight: 400;
  font-style: italic;
  font-size: clamp(19px, 2vw, 24px);
  color: #f2f0ec;
  line-height: 1.5;
  border-left: 2px solid var(--bronze);
  padding-left: var(--space-md);
  margin: var(--space-lg) 0;
}

.callout-box {
  background: rgba(176, 115, 61, 0.08);
  border: 1px solid rgba(176, 115, 61, 0.3);
  border-radius: 10px;
  padding: var(--space-md) var(--space-lg);
  font-size: 14.5px;
  color: var(--silver);
  line-height: 1.65;
}

@media (max-width: 900px) {
  .basalt-grid {
    grid-template-columns: 1fr;
    gap: var(--space-lg);
  }

  .basalt-media {
    position: static;
  }
}

/* ---- teaser ---- */
.teaser {
  padding: var(--section-pad) 0;
}

.teaser-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-lg);
}

/* flex column so the three cards' "Explore →" links settle on one
   baseline regardless of how many lines their copy runs to */
.teaser-card {
  display: flex;
  flex-direction: column;
  background: var(--navy);
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  overflow: hidden;
  text-align: center;
  transition: background 0.3s;
}

.teaser-card:hover {
  background: var(--navy-deep);
}

.teaser-img {
  width: 100%;
  aspect-ratio: 4/3;
  object-fit: cover;
  opacity: 0.9;
  border-radius: 13px 13px 0 0;
}

.teaser-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: var(--space-lg);
}

.teaser-card p {
  margin-left: auto;
  margin-right: auto;
}

.teaser-card h3 {
  font-family: "Fraunces", serif;
  font-weight: 400;
  font-size: 20px;
  color: #f2f0ec;
  margin-bottom: var(--space-sm);
}

.teaser-card p {
  color: var(--silver);
  font-size: 14px;
  line-height: 1.6;
  margin-bottom: var(--space-md);
}

.teaser-link {
  /* pushed to the bottom of the card, and kept to its own width so the
     hover underline hugs the text instead of spanning the card */
  margin-top: auto;
  align-self: center;
  color: var(--bronze-light);
  font-size: 13px;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  padding-bottom: 2px;
  transition: border-color 0.2s;
}

.teaser-link:hover {
  border-color: var(--bronze-light);
}

@media (max-width: 900px) {
  .teaser-grid {
    grid-template-columns: 1fr;
  }
}

/* ---- industry outlook ---- */
.outlook {
  position: relative;
  padding: var(--section-pad) 0;
  background: var(--navy-deep);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  overflow: hidden;
}

.outlook-figure {
  position: absolute;
  top: 50%;
  right: var(--gutter);
  transform: translateY(-50%);
  font-family: "IBM Plex Mono", monospace;
  font-size: min(20vw, 300px);
  font-weight: 500;
  line-height: 1;
  color: var(--bronze);
  opacity: 0.17;
  pointer-events: none;
  user-select: none;
  white-space: nowrap;
}

.outlook-inner {
  position: relative;
  max-width: 920px;
}

@media (max-width: 1100px) {
  .outlook-figure {
    display: none;
  }
}

.market-callout {
  margin-top: var(--space-lg);
  padding: var(--space-md) var(--space-lg);
  border-left: 2px solid var(--bronze);
  background: rgba(191, 196, 202, 0.04);
  font-size: 15px;
  color: #f2f0ec;
  line-height: 1.6;
}

.market-callout .mono {
  color: var(--bronze-light);
}

/* ---- closing band ---- */
.closing-band {
  position: relative;
  padding: var(--section-pad) var(--gutter);
  text-align: center;
  overflow: hidden;
}

.closing-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.closing-bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.closing-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at center,
      rgba(12, 18, 25, 0.66) 0%,
      rgba(12, 18, 25, 0.5) 55%,
      rgba(12, 18, 25, 0.38) 100%);
}

.closing-inner {
  position: relative;
  z-index: 1;
  max-width: 1040px;
  margin: 0 auto;
}

.closing-inner p {
  font-family: "Fraunces", serif;
  font-weight: 400;
  font-size: clamp(20px, 2.6vw, 30px);
  margin: 0 0 var(--space-lg);
  line-height: 1.5;
  color: #f5f3ef;
  text-shadow: 0 2px 20px rgba(12, 18, 25, 0.6);
}

.closing-cta {
  background: var(--bronze);
  color: #0c1219;
  border-radius: 8px;
  padding: 16px 34px;
  text-decoration: none;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.03em;
  display: inline-block;
  transition: background 0.25s;
}

.closing-cta:hover {
  background: var(--bronze-light);
}

/* ---- footer ---- */
footer {
  padding: var(--space-lg) var(--gutter) var(--space-md);
  background: var(--navy-deep);
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--space-md);
}

.footer-tag {
  color: var(--silver);
  font-size: 12.5px;
  letter-spacing: 0.03em;
}

.footer-copy {
  color: rgba(191, 196, 202, 0.5);
  font-size: 12px;
}

/* ---- reveal ---- */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 0.7s ease,
    transform 0.7s ease;
}

.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.stat.reveal {
  transform: translateY(28px);
}

.stat.reveal:nth-child(1) {
  transition-delay: 0s;
}

.stat.reveal:nth-child(2) {
  transition-delay: 0.1s;
}

.stat.reveal:nth-child(3) {
  transition-delay: 0.2s;
}

.stat.reveal:nth-child(4) {
  transition-delay: 0.3s;
}

.stat.reveal.is-visible {
  transform: translateY(0);
}

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

  html {
    scroll-behavior: auto;
  }
}

a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--bronze-light);
  outline-offset: 3px;
}

/* ============================================================
   Animation pass (additive) — local testing only, per
   Home-Animation-Prompt.md. Nothing above this line was edited.
   ============================================================ */

/* ---- 1. hero text: staggered entrance ---- */
.hero-inner.reveal {
  opacity: 1;
  transform: none;
}

.hero-inner .eyebrow,
.hero-inner .hero-head,
.hero-inner .hero-sub,
.hero-inner .hero-ctas {
  opacity: 0;
  transform: translateY(10px);
  transition:
    opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}

.hero-inner .eyebrow {
  transition-delay: 0s;
}

.hero-inner .hero-head {
  transition-delay: 0.15s;
}

.hero-inner .hero-sub {
  transition-delay: 0.3s;
}

.hero-inner .hero-ctas {
  transition-delay: 0.45s;
}

.hero-inner.is-visible .eyebrow,
.hero-inner.is-visible .hero-head,
.hero-inner.is-visible .hero-sub,
.hero-inner.is-visible .hero-ctas {
  opacity: 1;
  transform: translateY(0);
}

/* ---- 2. fiber-thread motif: line-draw is handled in script.js via
   stroke-dasharray/dashoffset on .fiber-strand paths; no CSS needed ---- */

/* ---- 3. stat bar count-up: numeric values are animated by script.js;
   no layout CSS needed beyond the existing .stat-value styling ---- */

/* ---- 4. why-project tiles: softened clip-path reveal (a full 100%
   panel-wipe read as harsh/jarring, so this now rises a much shorter
   distance and fades at the same time to blend the clip edge) ---- */
.tile-grid.reveal {
  opacity: 1;
  transform: none;
}

.tile-grid .tile {
  clip-path: inset(28% 0 0 0);
  opacity: 0;
  transition:
    clip-path 1s cubic-bezier(0.16, 1, 0.3, 1),
    opacity 1s cubic-bezier(0.16, 1, 0.3, 1);
}

.tile-grid .tile:nth-child(1) {
  transition-delay: 0s;
}

.tile-grid .tile:nth-child(2) {
  transition-delay: 0.15s;
}

.tile-grid .tile:nth-child(3) {
  transition-delay: 0.3s;
}

.tile-grid.is-visible .tile {
  clip-path: inset(0 0 0 0);
  opacity: 1;
}

/* ---- 5. product image: scale + focus on scroll-in (once, via .reveal) ---- */
.basalt-media.reveal {
  opacity: 1;
  transform: none;
}

.basalt-media img {
  transform: scale(1.08);
  filter: blur(6px);
  transition:
    transform 1s cubic-bezier(0.16, 1, 0.3, 1),
    filter 1s cubic-bezier(0.16, 1, 0.3, 1);
}

.basalt-media.is-visible img {
  transform: scale(1);
  filter: blur(0);
}

/* ---- 6. advantage list: staggered slide-in from right ---- */
.basalt-copy .adv-list li {
  opacity: 0;
  transform: translateX(16px);
  transition:
    opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}

.basalt-copy .adv-list li:nth-child(1) {
  transition-delay: 0s;
}

.basalt-copy .adv-list li:nth-child(2) {
  transition-delay: 0.1s;
}

.basalt-copy .adv-list li:nth-child(3) {
  transition-delay: 0.2s;
}

.basalt-copy .adv-list li:nth-child(4) {
  transition-delay: 0.3s;
}

.basalt-copy .adv-list li:nth-child(5) {
  transition-delay: 0.4s;
}

.basalt-copy.is-visible .adv-list li {
  opacity: 1;
  transform: translateX(0);
}

/* ---- 7. teaser cards: text-only entrance (image left untouched — no
   transform/animation on .teaser-img, it visibly softened image
   rendering during the transition, so it now just appears via the
   original block-level .reveal fade like before) ---- */
.teaser-grid .teaser-body {
  opacity: 0;
  transform: translateY(16px);
  transition:
    opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}

.teaser-card:nth-child(1) .teaser-body {
  transition-delay: 0.1s;
}

.teaser-card:nth-child(2) .teaser-body {
  transition-delay: 0.22s;
}

.teaser-card:nth-child(3) .teaser-body {
  transition-delay: 0.34s;
}

.teaser-grid.is-visible .teaser-body {
  opacity: 1;
  transform: translateY(0);
}

/* ---- 8. outlook "12%" figure: count-up (script.js) + subtle scale pulse ---- */
.outlook-figure .count-num {
  display: inline-block;
  transform: scale(0.96);
  transition: transform 1s cubic-bezier(0.16, 1, 0.3, 1);
}

.outlook-figure .count-num.count-pulse {
  transform: scale(1);
}

/* ---- 9. process tag: sequential stage reveal ---- */
.process-caption .tag {
  opacity: 1;
  transform: none;
}

.process-caption .tag .tag-word,
.process-caption .tag .tag-arrow {
  display: inline-block;
  opacity: 0;
  transform: translateX(-6px);
  transition:
    opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}

.process-caption .tag .tag-word:nth-child(1) {
  transition-delay: 0s;
}

.process-caption .tag .tag-arrow:nth-child(2) {
  transition-delay: 0.22s;
}

.process-caption .tag .tag-word:nth-child(3) {
  transition-delay: 0.44s;
}

.process-caption .tag .tag-arrow:nth-child(4) {
  transition-delay: 0.66s;
}

.process-caption .tag .tag-word:nth-child(5) {
  transition-delay: 0.88s;
}

.process-section.is-visible .process-caption .tag .tag-word,
.process-section.is-visible .process-caption .tag .tag-arrow {
  opacity: 1;
  transform: translateX(0);
}

/* ---- 10. closing band background: slow looping Ken Burns ---- */
@keyframes fiberKenBurns {
  0%,
  100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.08);
  }
}

.closing-bg img {
  animation: fiberKenBurns 22s ease-in-out infinite;
}

/* ---- footer: stack the two lines and center them ---- */
footer {
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  gap: var(--space-sm);
}

/* ---- reduced motion: snap everything in this section to its final state ---- */
@media (prefers-reduced-motion: reduce) {

  .hero-inner .eyebrow,
  .hero-inner .hero-head,
  .hero-inner .hero-sub,
  .hero-inner .hero-ctas {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .tile-grid .tile {
    clip-path: none;
    opacity: 1;
    transition: none;
  }

  .basalt-media img {
    transform: none;
    filter: none;
    transition: none;
  }

  .basalt-copy .adv-list li {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .teaser-grid .teaser-body {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .outlook-figure .count-num {
    transform: none;
    transition: none;
  }

  .process-caption .tag .tag-word,
  .process-caption .tag .tag-arrow {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .closing-bg img {
    animation: none;
  }
}

/* ============================================================
   Material page (material.html) — additive, per
   MATERIAL-Build-Prompt.md. Reuses tokens/components above;
   new component CSS only where Home has no equivalent.
   ============================================================ */

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

/* ---- section 1: hero, centered variant ---- */
.hero.hero--center {
  justify-content: center;
}

.hero--center .hero-media::after {
  background: radial-gradient(
    ellipse at center,
    rgba(20, 28, 39, 0.82) 0%,
    rgba(20, 28, 39, 0.6) 45%,
    rgba(20, 28, 39, 0.35) 100%
  );
}

.hero--center .hero-inner {
  text-align: center;
  max-width: 860px;
}

.hero--center .eyebrow {
  font-size: 13px;
}

.hero--center .hero-head {
  font-size: clamp(38px, 5.8vw, 76px);
}

.hero--center .hero-sub {
  font-size: 18px;
  max-width: 600px;
  margin-left: auto;
  margin-right: auto;
}

.hero--center .hero-ctas {
  justify-content: center;
}

/* ---- section 2: approach + split process strip ---- */
.approach {
  padding: var(--section-pad) 0 0;
}

.approach .section-head {
  max-width: none;
}

.approach-body {
  max-width: none;
}

.approach-body .section-body {
  max-width: none;
}

.approach-body .section-body + .section-body {
  margin-top: var(--space-md);
}

/* the process visual sits inside .wrap (contained, like every other
   section on this page) rather than full-bleed, so it stays well-behaved
   on very wide viewports instead of stretching into a thin letterboxed strip */
.approach .process-section {
  margin-top: var(--space-2xl);
}

.process-media--split {
  display: grid;
  grid-template-columns: 1fr 1.4fr;
  /* the two panes sit flush against each other, no divider */
  gap: 0;
  aspect-ratio: unset;
  height: 420px;
  border-radius: 16px;
  overflow: hidden;
  background: var(--line);
}

.process-media--split img,
.process-media--split video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Mobile stacks this pane into its own 16:9 box (below), which the stone
   photo now matches exactly — so `contain` and `cover` render identically
   there and this base rule only has to serve the desktop/tablet layout.
   On desktop the pane is a narrow ~1:1 column at a fixed 420px height,
   far narrower than the image's native 16:9, so `contain` let it float
   as a thin strip with empty navy bars above and below. `cover` fills
   the column the same way the video pane beside it already does. */
.process-media--contain {
  object-fit: cover;
}

.process-caption--wrap {
  padding-left: 0;
  padding-right: 0;
}

.process-caption--wrap p {
  white-space: normal;
  max-width: 640px;
}

@media (max-width: 700px) {
  .process-media--split {
    grid-template-columns: 1fr;
    height: auto;
  }

  .process-media--split img,
  .process-media--split video {
    aspect-ratio: 16/9;
  }
}

@media (max-width: 640px) {
  .process-media--split {
    height: auto;
  }
}

/* ---- section 3: system chain ---- */
.system-section {
  padding: var(--section-pad) 0;
}

/* full wrap width, matching every other section on the page (Properties,
   Comparison) so their left/right edges all line up with each other */
.system-section .section-head {
  max-width: none;
}

.system-section .section-head .section-body {
  max-width: none;
}

.system-chain {
  max-width: none;
  margin-top: var(--space-lg);
}

.system-chain-closing {
  margin-top: var(--space-lg);
  font-style: italic;
  color: var(--bronze-light);
  font-size: 15px;
}

/* ---- section 4: technical properties ---- */
.properties-section {
  padding: var(--section-pad) 0;
  background: var(--navy-deep);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.properties-section .section-head {
  max-width: none;
}

/* single grid so left/right rows share row tracks and align height-for-height;
   row 6 exists only in the right column and simply reads as a trailing row */
.properties-table {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: var(--space-2xl);
  margin-top: var(--space-lg);
}

.properties-cell {
  display: flex;
  align-items: flex-start;
  padding: var(--space-sm) 0;
  border-bottom: 1px solid var(--line);
}

.properties-cell--primary {
  grid-column: 1;
  gap: var(--space-md);
  font-size: 15px;
  color: #e9e7e2;
}

.properties-cell--primary .num {
  font-family: "IBM Plex Mono", monospace;
  color: var(--bronze-light);
  font-size: 13px;
  padding-top: 2px;
}

.properties-cell--secondary {
  grid-column: 2;
  position: relative;
  padding-left: var(--space-md);
  font-size: 14px;
  color: var(--silver);
  line-height: 1.6;
}

.properties-cell--secondary::before {
  content: "—";
  position: absolute;
  left: 0;
  color: var(--bronze);
}

@media (max-width: 900px) {
  .properties-table {
    display: block;
  }

  .properties-cell--primary,
  .properties-cell--secondary {
    grid-row: auto;
  }
}

/* ---- section 5: comparison (centerpiece) ---- */
.comparison-section {
  padding: var(--section-pad) 0;
}

.comparison-section .section-head {
  max-width: none;
}

.comparison-intro {
  max-width: none;
  margin-bottom: var(--space-2xl);
}

.dot-matrix-wrap {
  overflow-x: auto;
  margin-bottom: var(--space-2xl);
  background: var(--navy-deep);
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  padding: var(--space-lg);
}

.dot-matrix {
  width: 100%;
  border-collapse: collapse;
  min-width: 480px;
}

.dot-matrix th,
.dot-matrix td {
  padding: var(--space-sm) var(--space-md);
  border-bottom: 1px solid var(--line);
  text-align: center;
}

.dot-matrix thead th {
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--silver);
  font-weight: 500;
}

.dot-matrix tbody th {
  text-align: left;
  font-size: 14px;
  color: #e9e7e2;
  font-weight: 400;
}

.dot-matrix thead th:first-child {
  text-align: left;
}

.dots {
  display: inline-flex;
  gap: 4px;
}

.dots i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1px solid var(--bronze);
  background: transparent;
  display: inline-block;
}

.dots i.on {
  background: var(--bronze);
}

.dot-matrix-caption {
  margin-top: var(--space-sm);
  font-size: 12.5px;
  color: rgba(191, 196, 202, 0.6);
  font-style: italic;
}

.comparison-table-wrap {
  background: var(--navy-deep);
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  padding: var(--space-lg);
  overflow-x: auto;
}

.comparison-table {
  width: 100%;
  border-collapse: collapse;
  min-width: 560px;
}

.comparison-table th,
.comparison-table td {
  padding: var(--space-sm) var(--space-md);
  border-bottom: 1px solid var(--line);
  text-align: center;
}

.comparison-table th:first-child,
.comparison-table td:first-child {
  text-align: left;
}

.comparison-table thead th {
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--silver);
  font-weight: 500;
}

.comparison-table tbody td:first-child {
  color: #e9e7e2;
}

.comparison-row--basalt {
  font-weight: 600;
  border-left: 3px solid var(--bronze);
  background: rgba(176, 115, 61, 0.08);
}

.comparison-row--basalt td {
  color: #f2f0ec;
}

.comparison-row--basalt td:first-child {
  padding-left: calc(var(--space-md) - 3px);
}

/* capped: at the section's full 1184px a one-line callout stretched into
   an empty banner. The tables above stay full width — these read as
   editorial asides, so they get a measure closer to the body copy. */
.comparison-callouts {
  margin-top: var(--space-2xl);
  max-width: 900px;
}

/* ---- section 6: products (single-slide carousel) ---- */
.products-section {
  padding: var(--section-pad) 0;
}

/* tighter arrow gutters buy the track ~30px of width back, which pays for
   the narrower slide below without shrinking the card */
.product-carousel {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

.product-carousel-track {
  position: relative;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  touch-action: pan-y;
  cursor: grab;
  /* Horizontal fade only, and a narrow one. The old 6% fade was wider
     than the 37px of neighbour card actually on screen, so the peek this
     carousel is built around was invisible. The vertical fade is gone
     too: the padding below now lets the card's drop shadow finish inside
     the box, which reads crisper than fading the card's own edges out. */
  -webkit-mask-image: linear-gradient(
    to right,
    transparent 0%,
    black 3%,
    black 97%,
    transparent 100%
  );
  mask-image: linear-gradient(
    to right,
    transparent 0%,
    black 3%,
    black 97%,
    transparent 100%
  );
  padding: 26px 0 76px;
}

/* the rail holds every slide side by side; translating it horizontally is
   what produces the slide animation and the real (not decorative) peek of
   neighbour cards at the left/right edges of the track */
.product-carousel-rail {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  transition: transform 0.55s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: transform;
}

.product-slide {
  /* 78% not 83%: leaves ~90px of the neighbouring card on each side, so
     it actually reads as a rail of cards rather than a single panel */
  flex: 0 0 78%;
  display: flex;
  align-items: center;
  gap: var(--space-xl);
  background: var(--navy-deep);
  border: 1px solid var(--line-strong);
  border-radius: 20px;
  padding: var(--space-lg);
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.3);
  opacity: 0.4;
  transform: scale(0.94);
  transition:
    opacity 0.55s ease,
    transform 0.55s ease;
}

.product-slide.is-active {
  opacity: 1;
  transform: scale(1);
}

.product-slide-media {
  flex-shrink: 0;
  height: min(42vh, 360px);
  aspect-ratio: 9/16;
  border-radius: 14px;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  background: var(--navy);
}

.product-slide-media video,
.product-slide-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.product-slide-body {
  flex: 1;
  min-width: 0;
}

.product-slide-index {
  display: block;
  font-size: 12px;
  color: var(--bronze-light);
  margin-bottom: var(--space-sm);
}

.product-slide-body h3 {
  font-family: "Fraunces", serif;
  font-weight: 400;
  font-size: clamp(22px, 2.4vw, 29px);
  color: #f2f0ec;
  margin-bottom: var(--space-sm);
}

.product-slide-body p {
  color: var(--silver);
  font-size: 16px;
  line-height: 1.68;
  max-width: 440px;
}

.carousel-arrow {
  flex-shrink: 0;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: transparent;
  color: var(--silver);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition:
    border-color 0.2s,
    color 0.2s;
}

.carousel-arrow:hover {
  border-color: var(--bronze);
  color: var(--bronze-light);
}

.carousel-dots {
  display: flex;
  justify-content: center;
  gap: 10px;
  /* the track's own bottom padding (shadow clearance) is the gap here */
  margin-top: 0;
}

.carousel-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: transparent;
  padding: 0;
  cursor: pointer;
  transition:
    background 0.2s,
    border-color 0.2s;
}

.carousel-dot.is-active {
  background: var(--bronze);
  border-color: var(--bronze);
}

.product-carousel-track.is-dragging {
  cursor: grabbing;
}

.product-carousel-track.is-dragging .product-carousel-rail {
  transition: none;
}

.carousel-hint {
  display: none;
  text-align: center;
  margin-top: var(--space-sm);
  font-size: 12px;
  color: rgba(191, 196, 202, 0.55);
  letter-spacing: 0.04em;
}

@media (max-width: 900px) {
  .product-carousel {
    gap: var(--space-sm);
  }

  .product-carousel-track {
    /* still enough for the card's shadow to land — the old 16px here
       re-introduced the hard clip that the desktop padding just fixed */
    padding: 18px 0 56px;
  }

  .product-carousel-rail {
    gap: var(--space-sm);
  }

  .product-slide {
    flex: 0 0 86%;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-md);
    padding: var(--space-md);
  }

  .product-slide-media {
    width: 100%;
    height: auto;
    max-height: 46vh;
  }

  .product-slide-index {
    margin-bottom: var(--space-xs);
  }

  .product-slide-body h3 {
    margin-bottom: var(--space-xs);
  }

  .product-slide-body p {
    max-width: none;
  }

  .carousel-arrow {
    display: none;
  }

  .carousel-hint {
    display: block;
  }
}

/* ---- section 7: applications ---- */
.applications-section {
  padding: var(--section-pad) 0;
  background: var(--navy-deep);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.applications-section .section-head {
  max-width: none;
}

.applications-intro {
  max-width: none;
  margin-bottom: var(--space-xl);
}

.applications-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
}

.app-pill {
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  padding: 10px 20px;
  font-size: 14px;
  color: var(--silver);
  transition:
    color 0.2s,
    border-color 0.2s;
}

.app-pill:hover {
  color: var(--bronze-light);
  border-color: var(--bronze);
}

/* ---- section 8: sustainability ---- */
.sustainability-section {
  padding: var(--section-pad) 0;
}

.esg-list {
  list-style: none;
  margin: var(--space-lg) 0;
}

.esg-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-sm) 0;
  border-bottom: 1px solid var(--line);
  font-size: 15px;
  color: #e9e7e2;
}

.esg-accent-media {
  width: 56px;
  height: 56px;
  flex-shrink: 0;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--line-strong);
}

.esg-accent-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (max-width: 900px) {
  .comparison-table-wrap,
  .comparison-callouts {
    max-width: 100%;
  }
}

/* ============================================================
   Project page (project.html) — additive, per
   PROJECT-BUILD-PROMPT.md. Reuses the tokens and components
   above; new component CSS only where Home/Material have no
   equivalent.
   ============================================================ */

/* ---- section 1: hero over the masterplan render ---- */

/* The render ships as a bright daylight 3D export (green lawns, violet
   roofs). Graded back it reads as an engineering plan inside the
   navy/bronze/silver system instead of fighting it. */
.hero-media--still {
  overflow: hidden;
}

.hero-still {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 44%;
  filter: saturate(0.4) contrast(1.1) brightness(0.76);
  transform-origin: 58% 46%;
  animation: projectKenBurns 20s cubic-bezier(0.33, 0, 0.2, 1) forwards;
}

@keyframes projectKenBurns {
  from {
    transform: scale(1);
  }

  to {
    transform: scale(1.06);
  }
}

/* faint plan grid, drawn only over the render — pushes the "masterplan"
   read without adding a single new asset */
.hero-media--still::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(191, 196, 202, 0.075) 1px, transparent 1px),
    linear-gradient(90deg, rgba(191, 196, 202, 0.075) 1px, transparent 1px);
  background-size: 92px 92px;
  -webkit-mask-image: radial-gradient(
    ellipse at 64% 52%,
    black 0%,
    transparent 70%
  );
  mask-image: radial-gradient(ellipse at 64% 52%, black 0%, transparent 70%);
}

.hero--project .hero-media::after {
  z-index: 1;
  background:
    linear-gradient(
      100deg,
      rgba(20, 28, 39, 0.96) 0%,
      rgba(20, 28, 39, 0.84) 44%,
      rgba(20, 28, 39, 0.46) 100%
    ),
    linear-gradient(
      180deg,
      rgba(20, 28, 39, 0.5) 0%,
      rgba(20, 28, 39, 0) 38%,
      rgba(12, 18, 25, 0.9) 100%
    );
}

@media (max-width: 767px) {
  .hero--project .hero-media::after {
    background: linear-gradient(
      180deg,
      rgba(20, 28, 39, 0.62) 0%,
      rgba(20, 28, 39, 0.8) 55%,
      rgba(20, 28, 39, 0.96) 100%
    );
  }
}

/* the kicker is a four-part corridor string, not a two-word tag */
.eyebrow--chain {
  max-width: 620px;
  font-size: 11.5px;
  line-height: 1.95;
  letter-spacing: 0.14em;
}

.hero--project .hero-sub {
  margin-bottom: var(--space-md);
}

.hero-note {
  max-width: 520px;
  margin-bottom: var(--space-xl);
  padding-left: var(--space-md);
  border-left: 1px solid var(--line-strong);
  font-size: 14px;
  line-height: 1.7;
  color: rgba(191, 196, 202, 0.74);
}

.hero--project .hero-inner .hero-note {
  opacity: 0;
  transform: translateY(10px);
  transition:
    opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: 0.42s;
}

.hero--project .hero-inner.is-visible .hero-note {
  opacity: 1;
  transform: translateY(0);
}

.hero--project .hero-inner .hero-ctas {
  transition-delay: 0.56s;
}

/* ---- section 2: project at a glance ---- */
.stat-bar-head {
  position: relative;
  z-index: 1;
  padding: var(--section-pad) var(--gutter) var(--space-lg);
  text-align: center;
  font-size: 12.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--bronze-light);
}

.stat-unit {
  font-size: 16px;
  color: var(--silver);
}

.stat-label--sub {
  margin-top: 8px;
  margin-bottom: 0;
  font-size: 11px;
  opacity: 0.6;
}

/* ---- section 3: architecture diagram ---- */
.architecture-section {
  padding: var(--section-pad) 0;
}

.arch-diagram {
  max-width: 960px;
  margin: 0 auto;
}

.arch-svg {
  display: block;
  width: 100%;
  height: auto;
}

/* a 960-unit viewBox squeezed onto a phone renders the mono labels
   illegibly small, so narrow screens get the stacked run instead */
.arch-svg--stack {
  display: none;
}

@media (max-width: 720px) {
  .arch-svg--wide {
    display: none;
  }

  .arch-svg--stack {
    display: block;
    max-width: 360px;
    margin: 0 auto;
  }
}

.arch-rail {
  fill: none;
  stroke: var(--line-strong);
  stroke-width: 1.25;
}

.arch-flow {
  fill: none;
  stroke: var(--bronze);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-dasharray: 5 17;
  animation: archFlow 2.6s linear infinite;
}

@keyframes archFlow {
  to {
    /* two full dash periods, so the loop has no visible seam */
    stroke-dashoffset: -44;
  }
}

.arch-node {
  fill: var(--navy-deep);
  stroke: var(--silver);
  stroke-width: 1.25;
  opacity: 0.85;
}

.arch-node--key {
  stroke: var(--bronze);
  stroke-width: 1.8;
  opacity: 1;
}

.arch-core {
  fill: var(--silver);
}

.arch-core--key {
  fill: var(--bronze);
}

.arch-halo {
  fill: none;
  stroke: var(--bronze);
  stroke-width: 1;
  stroke-dasharray: 3 7;
  opacity: 0.45;
  animation: archHalo 30s linear infinite;
}

.arch-svg--wide .arch-halo {
  transform-box: view-box;
  transform-origin: 480px 140px;
}

.arch-svg--stack .arch-halo {
  transform-box: view-box;
  transform-origin: 64px 310px;
}

@keyframes archHalo {
  to {
    transform: rotate(360deg);
  }
}

.arch-label,
.arch-seg {
  font-family: "IBM Plex Mono", monospace;
}

.arch-label {
  fill: #f2f0ec;
  font-size: 14px;
  letter-spacing: 0.12em;
}

.arch-sub {
  font-family: "Inter", sans-serif;
  fill: var(--silver);
  font-size: 12.5px;
  letter-spacing: 0.03em;
  opacity: 0.72;
}

.arch-seg {
  fill: var(--bronze-light);
  font-size: 11.5px;
  letter-spacing: 0.16em;
}

/* centered statement variant of .pull-quote: the left bronze rule moves
   above the line so the quote can sit on the page axis */
.pull-quote--display {
  max-width: 880px;
  margin: var(--space-2xl) auto var(--space-xl);
  padding-left: 0;
  border-left: none;
  text-align: center;
  font-size: clamp(21px, 2.5vw, 31px);
  line-height: 1.45;
}

.pull-quote--display::before {
  content: "";
  display: block;
  width: 56px;
  height: 2px;
  margin: 0 auto var(--space-lg);
  background: var(--bronze);
}

.quote-arrow {
  padding: 0 8px;
  color: var(--bronze);
  font-style: normal;
}

.architecture-body {
  max-width: 720px;
  margin: 0 auto;
}

/* ---- section 4: location strategy (the Canada accent) ----
   The only brick-red on this site lives inside these photographs, as
   flag fabric. Every control, edge and label around them stays
   navy/bronze/silver — that restraint is what makes the red land. */
.location-section {
  padding: var(--section-pad) 0;
}

.canada-carousel {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  margin-top: var(--space-xl);
  padding: 0 var(--space-md);
}

.canada-track {
  position: relative;
  flex: 1;
  min-width: 0;
  /* overflow must be hidden to clip the rail horizontally, and CSS can't
     clip one axis while leaving the other visible — so the vertical
     padding has to be deep enough for the slide's drop shadow to finish
     inside the box. At 16px it was sliced off in a hard straight line. */
  overflow: hidden;
  padding: 26px 0 72px;
  touch-action: pan-y;
  cursor: grab;
  /* narrow fade only: a wide one swallowed the neighbouring slides
     entirely, which killed the peek the carousel is built around */
  -webkit-mask-image: linear-gradient(
    to right,
    transparent 0%,
    black 2.5%,
    black 97.5%,
    transparent 100%
  );
  mask-image: linear-gradient(
    to right,
    transparent 0%,
    black 2.5%,
    black 97.5%,
    transparent 100%
  );
}

.canada-track.is-dragging {
  cursor: grabbing;
}

.canada-track.is-dragging .canada-rail {
  transition: none;
}

.canada-rail {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  transition: transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: transform;
}

/* sized off the viewport's *shorter* constraint so a 16:9 slide is as
   large as it can be without ever overflowing the screen vertically
   (desktop) or horizontally (phone) — and with enough room left over
   for the neighbouring slides to genuinely peek in */
.canada-slide {
  flex: 0 0 min(1180px, 76vw, calc(64vh * 16 / 9));
  aspect-ratio: 16 / 9;
  margin: 0;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: 18px;
  background: var(--navy-deep);
  /* tightened from 0 30px 60px so the whole falloff fits the track's
     padding instead of needing ~90px of it */
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
  opacity: 0.3;
  transform: scale(0.95);
  transition:
    opacity 0.7s ease,
    transform 0.7s ease;
}

.canada-slide.is-active {
  opacity: 1;
  transform: scale(1);
}

.canada-slide img,
.canada-slide video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.canada-carousel .carousel-arrow {
  width: 56px;
  height: 56px;
  font-size: 26px;
  background: rgba(12, 18, 25, 0.55);
  backdrop-filter: blur(6px);
}

/* the track's deep bottom padding already supplies the breathing room */
.canada-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-lg);
  margin-top: 0;
}

.canada-controls .carousel-dots {
  margin-top: 0;
}

.canada-counter {
  font-size: 12.5px;
  letter-spacing: 0.14em;
  color: var(--bronze-light);
}

.location-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2xl);
  margin-top: var(--space-2xl);
}

.location-columns .section-body {
  max-width: none;
}

.location-head {
  margin-bottom: var(--space-md);
  padding-bottom: var(--space-sm);
  border-bottom: 1px solid var(--line);
  font-family: "Fraunces", serif;
  font-weight: 400;
  font-size: clamp(21px, 2.2vw, 28px);
  color: #f2f0ec;
}

@media (max-width: 900px) {
  .location-columns {
    grid-template-columns: 1fr;
    gap: var(--space-lg);
  }

  .canada-carousel {
    padding: 0;
    gap: 0;
  }
}

/* On a phone a 16:9 slide can only ever be ~190px tall, which is far too
   small for the page's centrepiece — narrow screens get a taller 4:3 crop
   so the imagery keeps some presence. */
@media (max-width: 700px) {
  .canada-slide {
    flex: 0 0 min(88vw, calc(56vh * 16 / 9));
    aspect-ratio: 4 / 3;
  }
}

/* ---- section 5: execution roadmap ---- */
.roadmap-section {
  padding: var(--section-pad) 0;
  background: var(--navy-deep);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.roadmap-grid {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 0.52fr 1fr;
  gap: var(--space-lg);
  align-items: stretch;
  padding-top: var(--space-lg);
}

/* the timeline itself: one rule across the top of both phases, fading
   out as the schedule runs into the future */
.roadmap-grid::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(
    90deg,
    var(--bronze) 0%,
    rgba(176, 115, 61, 0.55) 55%,
    rgba(191, 196, 202, 0.16) 100%
  );
}

.phase-card {
  position: relative;
}

.phase-card::before {
  content: "";
  position: absolute;
  top: -44px;
  left: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--bronze);
  box-shadow: 0 0 0 4px var(--navy-deep);
}

.phase-media {
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 14px;
}

.phase-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.phase-body {
  padding-top: var(--space-md);
}

.phase-index {
  display: block;
  margin-bottom: var(--space-sm);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bronze-light);
}

.phase-title {
  margin-bottom: var(--space-sm);
  font-family: "Fraunces", serif;
  font-weight: 400;
  font-size: clamp(20px, 2.1vw, 26px);
  color: #f2f0ec;
}

.phase-card p {
  font-size: 15px;
  line-height: 1.7;
  color: var(--silver);
}

.phase-figure {
  color: var(--bronze-light);
}

/* tall vertical accent, stretched to the row height rather than cropped
   into a square — same treatment as the B8 beat above */
.roadmap-detail {
  display: flex;
  min-height: 380px;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--navy);
}

.roadmap-detail img {
  flex: 1;
  min-height: 0;
  width: 100%;
  object-fit: cover;
  object-position: 50% 45%;
}

/* Held to the content column rather than run full-bleed: at page width a
   16:9 clip had to be cropped into a very wide, very short letterbox that
   read as stretched. The soft navy fade top and bottom stays. */
.roadmap-video {
  position: relative;
  aspect-ratio: 16 / 9;
  margin: var(--space-2xl) 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 16px;
}

.roadmap-video video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.roadmap-video::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(14, 20, 27, 0.9) 0%,
    rgba(14, 20, 27, 0) 22%,
    rgba(14, 20, 27, 0) 74%,
    rgba(14, 20, 27, 0.92) 100%
  );
}

/* pills rather than a fixed grid: seven items never divide evenly into
   any column count, and an auto-fit grid left a dead filler cell on the
   last row. Wrapping pills size to their own content instead. */
.req-strip {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
}

.req-item {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 11px 20px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  transition:
    border-color 0.2s,
    color 0.2s;
}

.req-item:hover {
  border-color: var(--bronze);
}

.req-icon {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  fill: none;
  stroke: var(--bronze-light);
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.req-label {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--silver);
}

.req-label .mono {
  color: #e9e7e2;
}

@media (max-width: 900px) {
  .roadmap-grid {
    grid-template-columns: 1fr;
  }

  .roadmap-detail {
    aspect-ratio: 3 / 4;
    min-height: 0;
    max-height: 62vh;
  }

  .phase-card::before {
    display: none;
  }
}

/* ---- section 6: planned product mix ---- */
.mix-section {
  padding: var(--section-pad) 0;
}

/* the capacity split, drawn straight from the table below — the numbers
   are the visual, so this section needs no imagery of its own */
.mix-bar {
  display: flex;
  height: 14px;
  margin-bottom: var(--space-md);
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--navy-deep);
}

.mix-seg {
  display: block;
  width: var(--share);
  transition: width 1.1s cubic-bezier(0.16, 1, 0.3, 1);
}

.mix-bar.reveal .mix-seg {
  width: 0;
}

.mix-bar.reveal.is-visible .mix-seg {
  width: var(--share);
}

.mix-seg--1,
.mix-swatch--1 {
  background: var(--bronze);
}

.mix-seg--2,
.mix-swatch--2 {
  background: color-mix(in srgb, var(--bronze) 60%, var(--navy));
}

.mix-seg--3,
.mix-swatch--3 {
  background: color-mix(in srgb, var(--bronze) 32%, var(--navy));
}

.mix-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-lg);
  margin-bottom: var(--space-xl);
  font-size: 12.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--silver);
}

.mix-key {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.mix-key b {
  font-weight: 500;
  color: var(--bronze-light);
}

.mix-swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 3px;
}

.table-caption {
  max-width: 780px;
  margin-top: var(--space-md);
  font-size: 13.5px;
  font-style: italic;
  line-height: 1.7;
  color: rgba(191, 196, 202, 0.7);
}

/* ---- section 7: the Oman supply corridor ----
   Different geography, no Canadian flag: strictly bronze/navy/silver. */
/* The closing image used to bleed into the next section, so the bottom
   padding was zero. Now that it is a contained card it needs the normal
   section rhythm underneath it. */
.corridor-section {
  padding: var(--section-pad) 0;
}

.corridor-grid {
  display: grid;
  grid-template-columns: 1fr 1.05fr;
  gap: var(--space-2xl);
  align-items: start;
}

.corridor-copy .section-body {
  max-width: none;
  margin-top: var(--space-md);
}

.corridor-copy .system-chain {
  margin-top: var(--space-xl);
}

/* the imagery runs alongside the chain as one mosaic rather than a
   separate gallery below it */
.corridor-media {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-sm);
}

.corridor-cell {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--navy-deep);
}

.corridor-cell img,
.corridor-cell video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.corridor-cell--wide {
  grid-column: 1 / -1;
  height: 200px;
}

.corridor-cell--tall {
  height: 300px;
}

/* Same reasoning as .roadmap-video: contained to the column so the frame
   keeps its own proportions instead of being cropped into a thin band. At
   16:9 this shows essentially the whole photograph, ship included, so no
   object-position nudge is needed any more. */
.corridor-closing {
  position: relative;
  aspect-ratio: 16 / 9;
  margin-top: var(--space-3xl);
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 16px;
}

.corridor-closing img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.corridor-closing::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(20, 28, 39, 0.88) 0%,
    rgba(20, 28, 39, 0) 26%,
    rgba(20, 28, 39, 0) 72%,
    rgba(20, 28, 39, 0.9) 100%
  );
}

@media (max-width: 900px) {
  .corridor-grid {
    grid-template-columns: 1fr;
    gap: var(--space-xl);
  }

  .corridor-cell--wide {
    height: 180px;
  }

  .corridor-cell--tall {
    height: 250px;
  }
}

/* ---- section 8: closing band ----
   The reprise is set in Fraunces italic so it reads as a statement,
   not as a duplicate of the mono footer signature below it. */
.closing-inner .closing-tagline {
  margin: var(--space-xl) 0 0;
  font-family: "Fraunces", serif;
  font-style: italic;
  font-size: clamp(15px, 1.6vw, 19px);
  letter-spacing: 0.02em;
  color: var(--bronze-light);
  text-shadow: 0 2px 14px rgba(12, 18, 25, 0.7);
}

/* ---- reduced motion: hold every project-page animation at rest ---- */
@media (prefers-reduced-motion: reduce) {
  .hero-still {
    animation: none;
  }

  .hero--project .hero-inner .hero-note {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .arch-flow,
  .arch-halo {
    animation: none;
  }

  .canada-rail {
    transition: none;
  }

  .canada-slide {
    transition: none;
  }

  .mix-bar.reveal .mix-seg {
    width: var(--share);
    transition: none;
  }
}

/* ============================================================
   Investors page (investors.html) — additive, per
   INVESTORS-BUILD-PROMPT.md. Persuasion by evidence rather than
   by imagery: fewer pictures, more whitespace, more mono. Every
   token, type ramp and component below comes from the blocks
   above; the gated economics grid is the only genuinely new
   component on the page.
   ============================================================ */

/* One padding shell for this page's sections. Every section block above
   repeats `padding: var(--section-pad) 0`, and half of them repeat the
   recessed navy-deep band as well — naming that once is cheaper than
   borrowing five unrelated section classes purely for their padding and
   leaving the next reader wondering why the investors page contains a
   `.roadmap-section`. */
.inv-section {
  padding: var(--section-pad) 0;
}

.inv-section--recessed {
  background: var(--navy-deep);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.inv-section .section-head {
  max-width: none;
}

.inv-section .section-head .section-body {
  max-width: 820px;
}

/* ---- section 1: hero over the bushing plate ----
   The plate is a small, dark, physically real object photographed on
   near-black navy — not a bright daylight 3D export. It needs neither
   the Project page's heavy corrective grade nor its masterplan grid
   overlay, and a strong Ken Burns push across a static object reads as
   a fake camera move rather than atmosphere. */
.hero--investors .hero-media--still::before {
  display: none;
}

.hero--investors .hero-still {
  object-position: center 50%;
  filter: saturate(0.92) contrast(1.06) brightness(0.94);
  transform-origin: 50% 50%;
  animation: investorsKenBurns 24s cubic-bezier(0.33, 0, 0.2, 1) forwards;
}

@keyframes investorsKenBurns {
  from {
    transform: scale(1);
  }

  to {
    transform: scale(1.03);
  }
}

/* Lighter scrim than .hero--project: the source is already near-black,
   so the full masterplan overlay crushed the plate out of frame
   entirely. The left column still carries enough navy for #f2f0ec
   headline text to clear AA against it. */
.hero--investors .hero-media::after {
  z-index: 1;
  background:
    linear-gradient(
      100deg,
      rgba(20, 28, 39, 0.94) 0%,
      rgba(20, 28, 39, 0.76) 40%,
      rgba(20, 28, 39, 0.12) 100%
    ),
    linear-gradient(
      180deg,
      rgba(20, 28, 39, 0.42) 0%,
      rgba(20, 28, 39, 0) 40%,
      rgba(12, 18, 25, 0.74) 100%
    );
}

@media (max-width: 767px) {
  .hero--investors .hero-media::after {
    background: linear-gradient(
      180deg,
      rgba(20, 28, 39, 0.6) 0%,
      rgba(20, 28, 39, 0.8) 55%,
      rgba(20, 28, 39, 0.95) 100%
    );
  }
}

.hero--investors .hero-sub {
  margin-bottom: var(--space-md);
}

.hero--investors .hero-inner .hero-note {
  opacity: 0;
  transform: translateY(10px);
  transition:
    opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: 0.42s;
}

.hero--investors .hero-inner.is-visible .hero-note {
  opacity: 1;
  transform: translateY(0);
}

.hero--investors .hero-inner .hero-ctas {
  transition-delay: 0.56s;
}

/* ---- section 2: investment snapshot ----
   Five entries rather than the four Home and Project use, so the bar
   steps 5 → 3 → 2 → 1. Each step restates every divider it owns: the
   base .stat-bar breakpoints assume a four-item bar, and a five-item
   one lands its row breaks in different places. */
.stat-bar--five {
  grid-template-columns: repeat(5, 1fr);
}

.stat-bar--five .stat.reveal:nth-child(5) {
  transition-delay: 0.4s;
}

/* Five into three (and then into two) always leaves a hole in the last
   row, and a lone trailing stat sitting in column 1 with dead space beside
   it reads as a broken grid. So the rows are balanced instead: a 6-track
   grid lets row one run 2+2+2 and row two run 3+3, and at the two-column
   step the fifth stat spans the full width and centres itself. */
@media (max-width: 1180px) {
  .stat-bar--five {
    grid-template-columns: repeat(6, 1fr);
  }

  .stat-bar--five .stat {
    grid-column: span 2;
    border-right: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
  }

  .stat-bar--five .stat:nth-child(4),
  .stat-bar--five .stat:nth-child(5) {
    grid-column: span 3;
  }

  .stat-bar--five .stat:nth-child(3n),
  .stat-bar--five .stat:last-child {
    border-right: none;
  }

  .stat-bar--five .stat:nth-last-child(-n + 2) {
    border-bottom: none;
  }
}

@media (max-width: 900px) {
  .stat-bar--five {
    grid-template-columns: repeat(2, 1fr);
  }

  /* :nth-child(4) has to be named again, not just covered by the plain
     .stat reset — the span-3 rule above is a class+pseudo and outranks it.
     Left in place it made the two-column grid auto-create a third implicit
     track, which is what knocked the last stat off centre. */
  .stat-bar--five .stat,
  .stat-bar--five .stat:nth-child(4) {
    grid-column: auto;
  }

  /* the odd one out goes full width rather than hugging the left column */
  .stat-bar--five .stat:nth-child(5) {
    grid-column: 1 / -1;
  }

  /* item 3 opens a new row here, so it gets its divider back */
  .stat-bar--five .stat:nth-child(3n) {
    border-right: 1px solid var(--line);
  }

  .stat-bar--five .stat:nth-child(2n),
  .stat-bar--five .stat:last-child {
    border-right: none;
  }

  .stat-bar--five .stat:nth-last-child(-n + 2) {
    border-bottom: 1px solid var(--line);
  }

  .stat-bar--five .stat:last-child {
    border-bottom: none;
  }
}

@media (max-width: 640px) {
  .stat-bar--five {
    grid-template-columns: 1fr;
  }

  .stat-bar--five .stat:nth-last-child(-n + 2) {
    border-bottom: 1px solid var(--line);
  }

  .stat-bar--five .stat:last-child {
    border-bottom: none;
  }
}

/* ---- section 3: the case for basalt ---- */
.force-tiles {
  margin-bottom: var(--space-2xl);
}

/* the three market-position lines are claims with no cited source, so
   they stay at prose weight — setting an uncited claim as a large mono
   statistic is exactly what makes an investor stop trusting a page */
.claim-list .market-callout:first-child {
  margin-top: 0;
}

/* ---- section 4: supporting product photograph ----
   One image, one section, generous margin. The spool is shot on the
   same near-navy ground the page is built from, so a plain framed card
   is all it needs. */
.product-plate {
  margin-top: var(--space-3xl);
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--navy-deep);
}

/* height:auto is load-bearing, not tidying — the explicit width/height
   attributes on the <img> (there to reserve space against layout shift)
   land as a used height, and a non-auto height makes the browser ignore
   aspect-ratio entirely. Without it every crop below is a no-op and the
   image renders at its full natural height. */
.product-plate img {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

/* The stone and the spool sit in the middle ~40% of a 16:9 frame. Held at
   16:9 on a phone that is a 220px-tall letterbox with two small objects
   lost in the centre of it, so the frame gets taller as the viewport gets
   narrower — cover then crops the empty sides away and the subjects fill
   roughly 70% of the width instead of 40%. */
@media (max-width: 900px) {
  .product-plate img {
    aspect-ratio: 4 / 3;
  }
}

@media (max-width: 560px) {
  .product-plate img {
    aspect-ratio: 1 / 1;
  }
}

/* ---- section 6: gated economics chart ----
   The one new component on this page. The metaphor is a document with
   its figures withheld, not a paywall: the panel names every indicator
   the model contains and draws a bar where each figure would sit, then
   the footer points at the only route to the numbers. There is no
   hidden text behind a bar to blur — none of these values exist
   anywhere in this page's source.

   Bar length encodes each indicator's relative FAVORABILITY, never its
   magnitude. That distinction matters because several of these are
   "lower is better" (payback period, break-even point): a long bar on
   those means "fast" / "low", not "large". Every length below is a
   hand-picked value from a qualitative tier — strong or moderate — and
   is never computed from, or annotated with, a real figure.

   One --tier percentage per column drives both orientations: bar height
   on the desktop column chart, bar width on the mobile row list. */
/* no margin-top of its own: .section-head already carries the site's
   standard --space-xl gap under every section opener, and adding a
   second one here is what left the band looking half-empty */
.econ-panel {
  padding: var(--space-lg);
  background: var(--navy-deep);
  border: 1px solid var(--line);
  border-radius: 14px;
}

/* the section sits in a recessed (navy-deep) band, so the panel's own
   navy-deep fill would blend straight into it and lose its edges —
   lightened one step to stay a distinct surface, the same relationship
   .tile has to .why-project */
.inv-section--recessed .econ-panel {
  background: var(--navy);
}

.econ-intro {
  max-width: 78ch;
  font-size: 16px;
  line-height: 1.75;
  color: #f2f0ec;
}

.econ-note {
  margin-top: var(--space-sm);
  font-size: 13px;
  line-height: 1.6;
  color: rgba(191, 196, 202, 0.6);
}

/* ---- the chart ----
   --plot-h is shared by the plot column and the baseline rule, so the
   axis line always lands exactly where the bars stand. */
.econ-chart {
  --plot-h: 200px;
  position: relative;
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: var(--space-sm);
  margin-top: var(--space-lg);
}

/* the baseline: one continuous rule under all eight columns rather than
   a per-column border, which the grid gap would otherwise chop up */
.econ-chart::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: var(--plot-h);
  height: 1px;
  background: var(--line-strong);
}

.econ-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 0;
}

.econ-plot {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 100%;
  height: var(--plot-h);
}

/* the lock rides just above each bar's top edge — `bottom` resolves
   against the plot height, so it tracks --tier automatically instead of
   needing a second per-column value. Drawn as a mask rather than an
   inline SVG so the icon still takes its color from --bronze-light
   instead of hard-coding a fourth brand hex. */
.econ-plot::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: var(--tier);
  width: 13px;
  height: 13px;
  margin-bottom: 10px;
  transform: translateX(-50%);
  background-color: var(--bronze-light);
  -webkit-mask: var(--lock-glyph) center / contain no-repeat;
  mask: var(--lock-glyph) center / contain no-repeat;
}

.econ-chart {
  --lock-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4.6' y='10.4' width='14.8' height='10.6' rx='1.8'/%3E%3Cpath d='M8 10.4V7.5a4 4 0 0 1 8 0v2.9'/%3E%3C/svg%3E");
}

.econ-bar {
  display: block;
  /* deliberately narrower than its column: the space between bars is
     what makes eight of them read as a chart rather than a filled block */
  width: 46%;
  height: var(--tier);
  /* the fill is held well below the accent's lightness on purpose — at
     similar values the bronze edge disappears into the bar and the
     column loses the one mark that ties it to the brand */
  border-left: 3px solid var(--bronze-light);
  background-color: color-mix(in srgb, var(--bronze) 48%, var(--navy-deep));
  background-image: linear-gradient(
    180deg,
    rgba(242, 240, 236, 0.08),
    rgba(242, 240, 236, 0)
  );
}

.econ-col-label {
  margin-top: 14px;
  font-size: 11.5px;
  line-height: 1.45;
  text-align: center;
  color: rgba(191, 196, 202, 0.75);
  /* long indicator names are allowed to wrap onto their own lines here
     rather than being truncated — the whole point of the section is
     "here is everything the model covers" */
  overflow-wrap: break-word;
}

/* ---- tiers (row-list widths) ----
   Arbitrary percentages across three qualitative tiers. Break-even
   stands out alone at the top as the strongest de-risking signal; NPV,
   IRR, ROI and payback sit close together beneath it, since the story
   there is that all four are comparably strong and spreading them out
   would invent a ranking between them. Total planned investment is a
   neutral anchor — the capital ask, not a verdict — so it is held
   clearly below the strong cluster rather than competing with it. */
.econ-col:nth-child(1) {
  --tier: 88%;
} /* NPV — strong cluster */
.econ-col:nth-child(2) {
  --tier: 86%;
} /* IRR — strong cluster */
.econ-col:nth-child(3) {
  --tier: 83%;
} /* ROI — strong cluster */
.econ-col:nth-child(4) {
  --tier: 85%;
} /* payback period — strong cluster (a short payback is the good outcome) */
.econ-col:nth-child(5) {
  --tier: 95%;
} /* break-even point — standout (a low break-even is the good outcome) */
.econ-col:nth-child(6) {
  --tier: 68%;
} /* total planned investment — neutral anchor, the capital ask */
.econ-col:nth-child(7) {
  --tier: 55%;
} /* production cost per kg — shortest true bar */
.econ-col:nth-child(8) {
  --tier: 68%;
} /* CAPEX — segmented, see below */

/* ---- CAPEX: a breakdown, not a value ----
   Several cost categories rather than one number, so it is drawn as a
   cluster of thin segments. Widths and opacities are arbitrary and mean
   nothing beyond "this has several components". It is also the only
   column with no bronze edge — that accent marks a single withheld
   figure, and this column isn't one. */
.econ-segments {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  width: 46%;
  height: var(--tier);
}

.econ-segment {
  flex: none;
  height: 100%;
  background-color: color-mix(in srgb, var(--bronze) 48%, var(--navy-deep));
}

.econ-segment:nth-child(1) {
  width: 22%;
  opacity: 0.9;
}
.econ-segment:nth-child(2) {
  width: 15%;
  opacity: 0.62;
}
.econ-segment:nth-child(3) {
  width: 26%;
  opacity: 0.78;
}
.econ-segment:nth-child(4) {
  width: 13%;
  opacity: 0.55;
}
.econ-segment:nth-child(5) {
  width: 19%;
  opacity: 0.7;
}

/* one lock in the section eyebrow, one over each bar — the bars are
   where the withheld figure actually is, so that is where the mark
   belongs */
.econ-lock {
  width: 15px;
  height: 15px;
  margin-right: 10px;
  vertical-align: -2px;
  fill: none;
  stroke: var(--bronze-light);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.econ-access {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-md);
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid var(--line);
}

.econ-access p {
  max-width: 560px;
  font-size: 15px;
  line-height: 1.7;
  color: #f2f0ec;
}

.econ-access-link {
  font-size: 14.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--bronze-light);
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.25s;
}

.econ-access-link:hover {
  color: #f2f0ec;
}

/* ---- desktop column heights ----
   Absolute heights here rather than the row list's percentages, so the
   column chart's proportions are set directly instead of falling out of
   --plot-h. Break-even is the tallest bar on the chart and stands alone
   as the strongest de-risking signal; NPV, IRR, ROI and payback are
   held within a few pixels of each other because the point is that they
   are comparably strong. Total planned investment drops to its own
   clearly lower step — it is the capital ask, a neutral anchor, and
   must not read as "as strong as" the performance indicators. Mobile
   keeps the percentage values above; these apply over the switch only.

   The column chart also leads with the capital ask and then walks
   through the returns, where the row list leads with the strongest
   result. Source order stays the list's; `order` re-sequences the
   columns for the chart only. */
@media (min-width: 641px) {
  .econ-col:nth-child(1) {
    --tier: 124px;
    order: 2;
  } /* NPV — strong cluster */
  .econ-col:nth-child(2) {
    --tier: 122px;
    order: 3;
  } /* IRR — strong cluster */
  .econ-col:nth-child(3) {
    --tier: 118px;
    order: 4;
  } /* ROI — strong cluster */
  .econ-col:nth-child(4) {
    --tier: 120px;
    order: 5;
  } /* payback period — strong cluster */
  .econ-col:nth-child(5) {
    --tier: 134px;
    order: 6;
  } /* break-even point — standout, tallest bar on the chart */
  .econ-col:nth-child(6) {
    --tier: 95px;
    order: 1;
  } /* total planned investment — neutral anchor */
  .econ-col:nth-child(7) {
    --tier: 78px;
    order: 7;
  } /* production cost per kg — shortest true bar */
  .econ-col:nth-child(8) {
    --tier: 66%;
    order: 8;
  } /* CAPEX — segmented, left as built */
}

/* a shorter plot before the layout switches, so eight columns never get
   squeezed to illegibility right up against the breakpoint */
@media (max-width: 1100px) and (min-width: 641px) {
  .econ-chart {
    --plot-h: 168px;
    gap: 10px;
  }

  .econ-bar,
  .econ-segments {
    width: 60%;
  }

  .econ-segments {
    gap: 2px;
  }

  .econ-col-label {
    font-size: 10.5px;
    letter-spacing: 0;
  }
}

/* ---- mobile: a different chart, not a shrunken one ----
   Eight columns cannot stay legible on a narrow viewport at any size,
   and a horizontally scrolling bar chart would hide most of the
   categories by default — the opposite of what this section is for. So
   the same tier data is re-read as a vertical list of horizontal bars,
   one row per indicator, every label intact on its own line. */
@media (max-width: 640px) {
  .econ-panel {
    padding: var(--space-md);
  }

  .econ-chart {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
    /* the note reads better as a footnote under the rows here, which is
       also where a caption belongs once the chart is a list */
    order: 1;
  }

  /* there is no shared baseline once the bars are rows — left in, the
     desktop axis rule cuts straight across the middle of the list */
  .econ-chart::after {
    content: none;
  }

  .econ-panel {
    display: flex;
    flex-direction: column;
  }

  .econ-note {
    order: 2;
    margin-top: var(--space-md);
  }

  .econ-access {
    order: 3;
  }

  /* label above, bar beneath — column-reverse gets that from the same
     DOM the desktop chart needs (bar first, label under the axis) */
  .econ-col {
    flex-direction: column-reverse;
    align-items: stretch;
  }

  .econ-plot {
    display: block;
    width: 100%;
    height: auto;
  }

  /* the per-bar lock is dropped here: at row scale it crowds the bar,
     and the panel eyebrow already carries the withheld mark */
  .econ-plot::after {
    content: none;
  }

  .econ-bar {
    width: var(--tier);
    height: 11px;
    border-left-width: 3px;
  }

  .econ-col-label {
    margin: 0 0 9px;
    font-size: 13px;
    text-align: left;
    color: #f2f0ec;
  }

  /* the segment cluster rotates with everything else: thin strips laid
     end to end instead of standing side by side */
  .econ-segments {
    width: var(--tier);
    height: 11px;
    gap: 4px;
  }

  .econ-segment {
    height: 100%;
  }

  .econ-segment:nth-child(1) {
    width: 26%;
  }
  .econ-segment:nth-child(2) {
    width: 16%;
  }
  .econ-segment:nth-child(3) {
    width: 24%;
  }
  .econ-segment:nth-child(4) {
    width: 14%;
  }
  .econ-segment:nth-child(5) {
    width: 20%;
  }

  .econ-access {
    align-items: flex-start;
    flex-direction: column;
    gap: var(--space-sm);
  }
}

/* ---- section 9: access-request form ----
   Navy fields, silver text, bronze focus ring. The global
   a/button focus rule doesn't reach form controls, so they get the
   same treatment named explicitly. */
.closing-band--request .section-title,
.closing-band--request .section-body {
  text-shadow: 0 2px 20px rgba(12, 18, 25, 0.6);
}

.closing-band--request .section-body {
  max-width: 660px;
  margin: var(--space-md) auto 0;
}

/* Home and Project use this band for a single line and a button, where the
   texture reads as atmosphere. Here it carries a whole form, so the image
   is scaled up into its bright bronze midsection and silver field labels
   land on it well under AA. The scrim goes nearly opaque behind the form
   and keeps a hint of texture up at the headline. */
.closing-band--request .closing-bg::after {
  background: linear-gradient(
    180deg,
    rgba(12, 18, 25, 0.84) 0%,
    rgba(12, 18, 25, 0.93) 40%,
    rgba(12, 18, 25, 0.96) 100%
  );
}

.access-form {
  max-width: 720px;
  margin: var(--space-2xl) auto 0;
  text-align: left;
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-md);
}

.form-field {
  display: flex;
  flex-direction: column;
  margin-bottom: var(--space-md);
}

.form-field label {
  margin-bottom: 8px;
  font-size: 11.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--silver);
}

.form-field .req {
  color: var(--bronze-light);
}

.access-form input,
.access-form select,
.access-form textarea {
  width: 100%;
  padding: 13px 15px;
  font-family: "Inter", sans-serif;
  font-size: 15px;
  color: #f2f0ec;
  background-color: rgba(12, 18, 25, 0.72);
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  transition:
    border-color 0.2s,
    background-color 0.2s;
}

.access-form textarea {
  min-height: 120px;
  line-height: 1.6;
  resize: vertical;
}

/* the native control's arrow is drawn by the OS in its own palette and
   reads as a light-mode artefact on a navy field */
.access-form select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23bfc4ca' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 15px center;
  background-size: 12px;
}

/* the dropdown list itself is painted by the OS, so it needs its own
   colours or it opens as near-white on near-white */
.access-form option {
  background: var(--navy-deep);
  color: #f2f0ec;
}

.access-form input:hover,
.access-form select:hover,
.access-form textarea:hover {
  border-color: var(--silver);
}

.access-form input:focus-visible,
.access-form select:focus-visible,
.access-form textarea:focus-visible {
  outline: 2px solid var(--bronze-light);
  outline-offset: 2px;
  border-color: var(--bronze);
}

.form-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-lg);
  margin-top: var(--space-md);
}

/* buttons inherit neither the page font nor a pointer cursor */
button.btn-primary {
  font-family: "Inter", sans-serif;
  cursor: pointer;
}

/* scoped to the band: bare .form-fallback loses to `.closing-inner p`,
   which set this line in 30px Fraunces alongside the submit button */
.closing-inner .form-fallback {
  margin: 0;
  font-family: "Inter", sans-serif;
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--silver);
  text-shadow: none;
}

.closing-inner .form-fallback a {
  color: var(--bronze-light);
}

@media (max-width: 640px) {
  .form-row {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .econ-access .btn-primary,
  .form-actions .btn-primary {
    width: 100%;
    text-align: center;
  }
}

/* ---- narrow-screen rhythm ----
   --section-pad steps down from 128px to 64px to 40px as the viewport
   narrows, but the fixed --space-2xl (96px) and --space-3xl (128px)
   margins used *between* blocks never move. On a phone that inverts the
   hierarchy: the gap between an eyebrow and its own heading ended up
   three times the padding separating one section from the next. These
   bring the in-section rhythm back under the section rhythm. Everything
   is scoped to this page so Home, Material and Project are untouched. */
@media (max-width: 900px) {
  /* Two different rhythms live on this page: the gap BETWEEN sections and
     the gaps INSIDE one. Tightening the inner gaps (below) without touching
     this one left the section break barely larger than the largest gap
     inside a section, so the whole page read as one continuous column.
     --section-pad alone ramps 128 → 64 → 40, which collapses too fast for a
     text-dense page; these hold it at 80 → 64 so the boundary always wins
     without reopening the canyons this page had before. */
  .inv-section {
    padding: calc(var(--space-xl) + var(--space-sm)) 0;
  }

  .inv-section .section-head {
    margin-bottom: var(--space-lg);
  }

  .inv-section .pull-quote--display {
    margin: var(--space-xl) auto var(--space-lg);
  }

  .force-tiles {
    margin-bottom: var(--space-lg);
  }

  /* stacked tiles keep the base rule's 40px side padding, which indents
     them out of line with every other block in the wrap, and 64px of
     vertical padding on top of the section-head margin above them */
  .force-tiles .tile,
  .force-tiles .tile:nth-child(3n + 1) {
    padding: var(--space-lg) 0;
  }

  .product-plate {
    margin-top: var(--space-xl);
  }
}

@media (max-width: 640px) {
  .inv-section {
    padding: var(--space-xl) 0;
  }

  /* the section opener keeps a real pause under it — this is section
     furniture, not in-section content spacing */
  .inv-section .section-head {
    margin-bottom: var(--space-lg);
  }

  /* 27px of letterspaced uppercase is a headline's worth of width on a
     350px screen, but the eyebrow is the strongest "a new section starts
     here" cue on the page, so it only comes down as far as it must */
  .inv-section .section-eyebrow {
    margin-bottom: var(--space-sm);
    font-size: 23px;
  }

  .inv-section .pull-quote--display {
    margin: var(--space-lg) auto var(--space-md);
  }

  .inv-section .pull-quote--display::before {
    margin-bottom: var(--space-md);
  }

  .inv-section .adv-list {
    margin: var(--space-md) 0;
  }

  .inv-section .system-chain-closing {
    margin-top: var(--space-md);
  }

  .inv-section .comparison-table-wrap {
    padding: var(--space-md);
  }

  .force-tiles {
    margin-bottom: 0;
  }

  .force-tiles .tile,
  .force-tiles .tile:nth-child(3n + 1) {
    padding: var(--space-md) 0;
  }

  .product-plate {
    margin-top: var(--space-lg);
  }
}

/* ---- reduced motion: hold every investors-page animation at rest ----
   .hero--investors .hero-still outranks the plain .hero-still reset in
   the project block above, so it has to be named again here. */
@media (prefers-reduced-motion: reduce) {
  .hero--investors .hero-still {
    animation: none;
  }

  .hero--investors .hero-inner .hero-note {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ============================================================
   Team & Capabilities page (team.html) — additive, per
   BUILD-PROMPT-team-page.md. Two new components are authorized
   here: the leadership/executive card grid and the text-only
   variant of the existing product carousel. Everything else on
   the page reuses classes defined in the blocks above.
   ============================================================ */

/* ---- section 1: hero over the engineer's-desk still ----
   .hero-media::after's base gradient (0.92 → 0.55 → 0.25) isn't strong
   enough for this image: its detail sits right of centre and the left
   third, where the headline lands, is calm but not dark. The stronger
   variant already exists but is scoped to .hero--project, so this page
   gets its own copy rather than widening that selector. */
.hero--team .hero-media::after {
  z-index: 1;
  background:
    linear-gradient(
      100deg,
      rgba(20, 28, 39, 0.96) 0%,
      rgba(20, 28, 39, 0.84) 44%,
      rgba(20, 28, 39, 0.46) 100%
    ),
    linear-gradient(
      180deg,
      rgba(20, 28, 39, 0.5) 0%,
      rgba(20, 28, 39, 0) 38%,
      rgba(12, 18, 25, 0.9) 100%
    );
}

@media (max-width: 767px) {
  .hero--team .hero-media::after {
    background: linear-gradient(
      180deg,
      rgba(20, 28, 39, 0.62) 0%,
      rgba(20, 28, 39, 0.8) 55%,
      rgba(20, 28, 39, 0.96) 100%
    );
  }
}

/* ---- team page: leadership + executive grids (new component) ---- */
.leadership-section,
.executive-section {
  padding: var(--section-pad) 0;
}

.leader-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-lg);
}

/* mirrors .teaser-card: photo on top, flex column so bios of different
   lengths don't leave the cards ragged */
.leader-card {
  display: flex;
  flex-direction: column;
  background: var(--navy);
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  overflow: hidden;
  transition: background 0.3s;
}

.leader-card:hover {
  background: var(--navy-deep);
}

.leader-photo {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: center 20%;
  opacity: 0.92;
  border-radius: 13px 13px 0 0;
}

/* the placeholder is a square monogram, not a portrait — contain it and
   sit it on the navy field rather than cropping the mark */
.leader-photo--placeholder {
  object-fit: contain;
  background: var(--navy-deep);
  opacity: 0.5;
}

.leader-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: var(--space-md);
}

.leader-name {
  font-family: "Fraunces", serif;
  font-weight: 400;
  font-size: 19px;
  line-height: 1.25;
  color: #f2f0ec;
  margin-bottom: var(--space-xs);
}

.leader-role {
  display: block;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--bronze-light);
  margin-bottom: var(--space-xs);
}

.leader-meta {
  display: block;
  font-size: 11.5px;
  letter-spacing: 0.05em;
  color: rgba(191, 196, 202, 0.62);
  margin-bottom: var(--space-sm);
}

.leader-bio {
  font-size: 14px;
  line-height: 1.62;
  color: var(--silver);
}

.leader-pending {
  font-size: 13px;
  font-style: italic;
  line-height: 1.6;
  color: rgba(191, 196, 202, 0.5);
}

.leader-card--placeholder {
  border-style: dashed;
}

@media (max-width: 1100px) {
  .leader-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 560px) {
  .leader-grid {
    grid-template-columns: 1fr;
  }
}

/* Fail-open for the scroll reveal on this grid.
   script.js's reveal observer fires at `threshold: 0.3`, so an element can
   only ever reveal if it fits within ~3.3 viewport heights. At four columns
   the grid is ~680px and is never at risk, but once it stacks it reaches
   2773px at 375px wide and 3517px at 560px — a phone viewport tops out at
   an intersection ratio of 0.23-0.29 there and the callback simply never
   fires, leaving the whole leadership section at opacity 0 permanently.
   script.js is shared by every page and out of bounds for this build, so
   the grid opts out of the fade below the width where it can still animate
   safely. The section heading above it still fades in. */
@media (max-width: 1100px) {
  .leader-grid.reveal {
    opacity: 1;
    transform: none;
  }
}

/* Leadership carries three cards in a track measured for four, which
   left them hugging the left edge with a hole on the right. The columns
   keep the four-column measure — so each card is exactly the width it
   already was — and the three of them are centred in the row instead of
   being restretched. Only above the first breakpoint: at two columns and
   one column the grid already fills its row. */
@media (min-width: 1101px) {
  .leadership-section .leader-grid {
    grid-template-columns: repeat(3, calc((100% - 3 * var(--space-lg)) / 4));
    justify-content: center;
  }
}

/* three placeholder cards shouldn't stretch across a four-column track */
.leader-grid--three {
  grid-template-columns: repeat(3, 1fr);
}

@media (max-width: 1100px) {
  .leader-grid--three {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 560px) {
  .leader-grid--three {
    grid-template-columns: 1fr;
  }
}

/* ---- team page: founder's message (text-only carousel variant) ----
   Same rail/dot/arrow/drag JS as the Material page — the base class
   names are reused verbatim so that script needs zero selector edits.
   These rules only restyle the slide now that its media block is gone. */
.founder-section {
  padding: var(--section-pad) 0;
}

/* equal-height cards: the base rail centers slides, which reads as
   ragged once the media block is gone and slide heights differ */
.product-carousel--text .product-carousel-rail {
  align-items: stretch;
}

.product-carousel--text .product-slide--text {
  display: block;
  padding: var(--space-xl) var(--space-lg);
}

/* the body is the whole card now, so let the measure breathe past the
   440px cap the base rule sets for copy sitting next to a video */
.product-carousel--text .product-slide--text .product-slide-body p {
  max-width: 62ch;
  font-size: 17px;
  line-height: 1.78;
}

.product-carousel--text .product-slide--text .product-slide-body h3 {
  margin-bottom: var(--space-md);
}

/* Scoped to match the sibling paragraph rule above, not left as a bare
   .founder-sign: the signature is a <p> inside .product-slide-body, so
   both `.product-slide-body p` (0,1,1) and the variant's own paragraph
   rule (0,3,1) outrank a plain class selector — the bronze and the 14px
   below never reached the element, and the signature rendered as another
   block of 17px silver body copy. Values are unchanged; only the
   selector's weight is. */
.product-carousel--text
  .product-slide--text
  .product-slide-body
  p.founder-sign {
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid var(--line);
  font-size: 14px;
  line-height: 1.7;
  color: var(--bronze-light);
}

.founder-sign strong {
  font-weight: 600;
}

@media (max-width: 900px) {
  .product-carousel--text .product-slide--text {
    padding: var(--space-lg) var(--space-md);
  }

  .product-carousel--text .product-slide--text .product-slide-body p {
    font-size: 15.5px;
  }
}

/* ---- team page: Executive Team correction (client, follow-up round) ----
   Three cards carrying real names and, since the client supplied them,
   real portraits. Scoped to .leader-card--compact only, so the
   Leadership cards above (photo on top, stacked body) are untouched.

   Layout is a row rather than a column here: portrait on the left, the
   name/role block filling the rest and centred against the photo's
   height. */
.leader-card--compact {
  flex-direction: row;
  align-items: stretch;
}

/* All three source files are 3:4 portraits, so the frame is set to 3/4
   and the image lands in it uncropped — object-fit has no overflow to
   trim, which is why the faces stay whole at this size. The card takes
   its height from this, which is what makes the row taller than the
   text-only version it replaces. */
.leader-thumb {
  flex: none;
  width: 132px;
  /* the img carries width/height attributes so the browser can reserve
     the box before the file loads; those attributes are presentational
     hints, and without an explicit height:auto here the intrinsic pixel
     height wins and aspect-ratio never gets a say */
  height: auto;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  opacity: 0.92;
}

/* .leader-body is already flex-column from the base rule; it only needs
   vertical centring (the look the client asked to keep) and permission
   to shrink so a long role wraps inside the card instead of pushing it
   wider. Name and role stack as separate lines by structure — the h3 is
   block and .leader-role is block — so a short title like "Financial
   Manager" and a long one both render as the same two-line shape. */
.leader-card--compact .leader-body {
  justify-content: center;
  min-width: 0;
}

.leader-card--compact .leader-name {
  display: block;
  margin-bottom: 4px;
}
