/* ---------------------------------------------------------------------------
   site.css — MONRÉ Group.

   The brief was a white page that reads like a well-run operation rather than
   a brochure: the reference was a dashboard, and the useful thing to borrow
   from a dashboard is not its cards but its discipline — one accent colour
   used decisively, data given room, and nothing decorative competing with the
   thing you came to read.

   Structure: tokens, reset, primitives (chip, card, button), then sections in
   the order they appear in the document.
--------------------------------------------------------------------------- */

/* --- Tokens ---------------------------------------------------------------
   Type runs on a 4:3 scale (×1.333) from a 16 px body, which is the same
   progression the page's proportions use, so a heading is never an arbitrary
   size. Space runs on ×1.5 from 4 px. Both are fluid at the top end only —
   small values should not shrink, or dense rows lose their rhythm. */

:root {
  /* Ink. Warm-shifted to sit under a gold accent: a neutral or cool grey next
     to warm metal reads as dirty, and pure #000 on white is a hole. */
  --ink:        #14100A;
  --ink-2:      #3A342A;
  --body:       #5C5548;
  --faint:      #918A7C;
  --line:       #EAE5DB;
  --line-soft:  #F4F1EA;

  /* Canvas. White dominates; the tint is for card fills and alternating
     bands, never for a whole screen. */
  --bg:         #FFFFFF;
  --surface:    #FAF8F3;
  --surface-2:  #F3F0E7;

  /* Brand. The group's own gold, taken from the wordmark and the shop signage
     rather than invented, so the accent and the photography finally agree.
     
     Gold is a light hue, which is the whole difficulty of using it on white:
     the swatch that looks right on a sign fails contrast as body-adjacent
     text. So the ramp darkens sharply through the middle — 600 is the lightest
     step allowed to carry text or an icon on white, and the bright metallic
     values live at 400 and above where they are only ever used as fills,
     borders, or type on a dark ground. 900 is a warm brown-black for inverted
     panels, so the dark blocks belong to the same palette rather than reading
     as a separate neutral. */
  --brand-900:  #17110A;
  --brand-800:  #2B2010;
  --brand-700:  #6B4E12;
  --brand-600:  #8A6512;
  --brand-500:  #A87D18;
  --brand-400:  #C39A3E;
  --brand-100:  #F5EBD6;
  --brand-050:  #FCF8F0;

  --accent-gold: #E8C874;  /* bright metal, on dark grounds only */

  /* Type */
  --display: 'Instrument Sans', 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --sans:    'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;
  --mono:    'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  --t-xs:   0.75rem;    /* 12 */
  --t-sm:   0.8125rem;  /* 13 */
  --t-base: 1rem;       /* 16 */
  --t-md:   1.0625rem;  /* 17 */
  --t-lg:   clamp(1.15rem, 1.6vw, 1.3125rem);
  --t-xl:   clamp(1.4rem, 2.2vw, 1.75rem);
  --t-2xl:  clamp(1.75rem, 3.2vw, 2.3125rem);
  --t-3xl:  clamp(2.2rem, 4.6vw, 3.0625rem);
  --t-4xl:  clamp(2.6rem, 6.4vw, 4.0625rem);

  /* Space */
  --s-1: 0.25rem;  --s-2: 0.5rem;   --s-3: 0.75rem;  --s-4: 1rem;
  --s-5: 1.5rem;   --s-6: 2rem;     --s-7: 2.5rem;   --s-8: 3.5rem;
  --s-9: clamp(3.5rem, 8vw, 5.5rem);
  --s-10: clamp(5rem, 11vw, 8rem);

  /* Shape. Generous but not pill-everything: the reference's warmth comes
     from consistent 3-step rounding, not from maximum radius. */
  --r-sm: 0.5rem;  --r-md: 0.875rem;  --r-lg: 1.25rem;  --r-xl: 1.75rem;

  /* Shadows are hue-shifted into the green, never pure black — a black
     shadow on a white page reads as dirt. */
  --shadow-1: 0 1px 2px rgba(23, 17, 10, 0.05);
  --shadow-2: 0 2px 4px rgba(23, 17, 10, 0.04), 0 8px 20px rgba(23, 17, 10, 0.06);
  --shadow-3: 0 4px 8px rgba(23, 17, 10, 0.05), 0 18px 44px rgba(23, 17, 10, 0.10);

  --wrap: 78rem;
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  /* Length of the map sequence, as page height. Shorten for a brisker run,
     lengthen for a more deliberate one; the beats keep their relative weight
     either way. */
  --track: 400vh;
}

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

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--body);
  font-family: var(--sans);
  font-size: var(--t-md);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: 'cv05' 1, 'ss03' 1;
}

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

h1, h2, h3, h4 {
  margin: 0;
  color: var(--ink);
  font-family: var(--display);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.028em;
  text-wrap: balance;
}

p { margin: 0; text-wrap: pretty; }
ul, ol { margin: 0; padding: 0; list-style: none; }

a { color: inherit; text-decoration: none; }

button, input, select { font: inherit; color: inherit; }

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

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

.skip {
  position: absolute; left: var(--s-4); top: -100px; z-index: 200;
  padding: var(--s-3) var(--s-5);
  background: var(--brand-900); color: #fff;
  border-radius: var(--r-sm);
  transition: top 0.2s var(--ease);
}
.skip:focus { top: var(--s-4); }

/* --- Boot screen -----------------------------------------------------------
   Covers the page while the tiles land: the mark on the brand's own dark, and
   nothing else. A progress readout here would be reporting on tile counts,
   which is the page's business and not the reader's, and naming the wait makes
   it feel longer than simply covering it. */

.boot {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  background: var(--brand-900);
  transition: opacity 0.55s var(--ease), visibility 0.55s;
}
.boot[data-done="true"] { opacity: 0; visibility: hidden; }

/* Scroll is held only while the screen is up. Releasing it is tied to the same
   flag that hides the screen, so the two can never disagree. */
body[data-booting="true"] { overflow: hidden; }

.boot__mark {
  width: auto;
  height: clamp(3rem, 9vw, 4.25rem);
  animation: bootPulse 2.4s var(--ease) infinite;
}

/* A slow breath, not a spinner. The wait is usually a second or two and a
   spinner at that length reads as something having gone wrong. */
@keyframes bootPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.62; transform: scale(0.965); }
}

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

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

.wrap {
  width: min(100% - clamp(2rem, 6vw, 5rem), var(--wrap));
  margin-inline: auto;
}

.section { padding-block: var(--s-10); }
.section--tint { background: var(--surface); }

/* The eyebrow is the smallest step in the scale and the only place letter
   spacing opens up: at 12 px uppercase, tight tracking is unreadable. The
   label carries itself on colour and tracking alone, with no leading rule. */
.eyebrow {
  display: inline-block;
  margin-bottom: var(--s-4);
  color: var(--brand-600);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* Section headings borrow the reference's two-tone headline: the statement in
   ink, the qualifier dropped to muted. One element, two levels of hierarchy,
   no extra ornament. */
.section__head { max-width: 46rem; margin-bottom: var(--s-8); }
.section__title { font-size: var(--t-3xl); }
.section__title em { font-style: normal; color: var(--faint); }
.section__lede {
  margin-top: var(--s-5);
  max-width: 40rem;
  font-size: var(--t-lg);
  line-height: 1.55;
  color: var(--body);
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 2.875rem;          /* 46 px — clears the 44 px touch minimum */
  padding: 0.6rem 1.25rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: none;
  font-family: var(--display);
  font-size: var(--t-base);
  font-weight: 550;
  letter-spacing: -0.011em;
  cursor: pointer;
  transition: background 0.18s var(--ease), border-color 0.18s var(--ease),
              color 0.18s var(--ease), transform 0.18s var(--ease),
              box-shadow 0.18s var(--ease);
}
.btn:active { transform: translateY(1px); }

.btn--primary { background: var(--brand-600); color: #fff; box-shadow: var(--shadow-1); }
.btn--primary:hover { background: var(--brand-700); box-shadow: var(--shadow-2); }

.btn--ghost { border-color: var(--line); color: var(--ink); background: #fff; }
.btn--ghost:hover { border-color: var(--brand-500); color: var(--brand-600); }

.btn--onDark { background: rgba(255, 255, 255, 0.1); color: #fff; border-color: rgba(255, 255, 255, 0.22); }
.btn--onDark:hover { background: rgba(255, 255, 255, 0.18); }

.btn--light { background: #fff; color: var(--brand-900); }
.btn--light:hover { background: var(--brand-050); }

.btn svg { width: 1.125rem; height: 1.125rem; flex: none; }

/* A link that reads as a link without underlining everything: the arrow moves
   on hover, which is a stronger affordance than a colour change alone. */
.arrowlink {
  display: inline-flex; align-items: center; gap: var(--s-2);
  color: var(--brand-600);
  font-weight: 550;
  font-family: var(--display);
}
.arrowlink svg { transition: transform 0.2s var(--ease); }
.arrowlink:hover svg { transform: translateX(4px); }

/* --- Chips ---------------------------------------------------------------- */

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 2.375rem;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: #fff;
  color: var(--ink-2);
  font-size: var(--t-sm);
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.16s var(--ease), border-color 0.16s var(--ease),
              color 0.16s var(--ease);
}
.chip:hover { border-color: var(--brand-400); color: var(--brand-600); }

.chip__count {
  color: var(--faint);
  font-variant-numeric: tabular-nums;
}

.chip[aria-pressed="true"] {
  background: var(--brand-900);
  border-color: var(--brand-900);
  color: #fff;
}
.chip[aria-pressed="true"] .chip__count { color: rgba(255, 255, 255, 0.6); }


/* ==========================================================================
   Header
   ========================================================================== */

.topbar {
  position: fixed;
  inset: 0 0 auto;
  z-index: 100;
  transition: background 0.3s var(--ease), border-color 0.3s var(--ease),
              box-shadow 0.3s var(--ease);
  border-bottom: 1px solid transparent;
}

/* Over the map the bar is transparent and its contents sit on dark imagery, so
   its contents have to invert with it — ink-on-satellite is unreadable, and it
   is the brand mark that suffers most. Everything transitions on the same
   0.3 s curve as the background, so the swap is one movement, not a flicker. */
.topbar[data-solid="false"] .topbar__nav a { color: rgba(255, 255, 255, 0.78); }
.topbar[data-solid="false"] .topbar__nav a:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.12);
}
.topbar[data-solid="false"] .topbar__nav a[aria-current="true"] { color: var(--accent-gold); }

.topbar[data-solid="false"] .topbar__burger {
  border-color: rgba(255, 255, 255, 0.28);
  background: rgba(23, 17, 10, 0.45);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: #fff;
}

.topbar__nav a, .topbar__burger {
  transition: color 0.3s var(--ease), background 0.3s var(--ease),
              border-color 0.3s var(--ease);
}

.topbar[data-solid="true"] {
  background: rgba(255, 255, 255, 0.88);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  border-bottom-color: var(--line);
}

.topbar__inner {
  display: flex;
  align-items: center;
  gap: var(--s-6);
  min-height: 4.5rem;
}

/* The group's own monogram and wordmark, not a typeset stand-in. The wordmark
   is a light gold gradient built for dark grounds, which is exactly where it
   sits while the header is over the map; once the header takes a white surface
   the same gold drops to roughly 2:1 against it, so it is darkened there
   rather than left to fade out. A filter, because the asset is a raster with a
   gradient in it and there is no darker variant to swap to. */
.brand {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  /* Never let the header squeeze the logo. As a shrinkable flex item it gave
     up width to the nav and the button, and because the reset caps images at
     max-width:100% while these carry a fixed height, the lost width came
     straight out of the aspect ratio: the wordmark rendered horizontally
     crushed rather than simply smaller. */
  flex: 0 0 auto;
}
.brand img {
  flex: none;
  max-width: none;
  width: auto;
}
.brand__mark { height: 1.65rem; }
.brand__word { height: 1rem; }

@media (max-width: 30rem) {
  .brand__mark { height: 1.45rem; }
  .brand__word { height: 0.875rem; }
}

.topbar .brand img,
.footer .brand img { transition: filter 0.3s var(--ease); }

.topbar[data-solid="false"] .brand img {
  filter: drop-shadow(0 1px 10px rgba(23, 17, 10, 0.55));
}
.topbar[data-solid="true"] .brand img,
.footer .brand img {
  filter: saturate(1.2) brightness(0.72);
}

.topbar__nav {
  display: none;
  margin-left: auto;
  gap: var(--s-1);
}
.topbar__nav a {
  padding: 0.5rem 0.75rem;
  border-radius: var(--r-sm);
  color: var(--ink-2);
  font-size: var(--t-sm);
  font-weight: 500;
  transition: color 0.16s var(--ease), background 0.16s var(--ease);
}
.topbar__nav a:hover { color: var(--ink); background: var(--surface); }
.topbar__nav a[aria-current="true"] { color: var(--brand-600); }

.topbar__cta { margin-left: auto; }
.topbar__burger {
  display: inline-flex;
  align-items: center; justify-content: center;
  width: 2.75rem; height: 2.75rem;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: #fff;
  cursor: pointer;
}

@media (min-width: 62rem) {
  .topbar__nav { display: flex; }
  .topbar__cta { margin-left: 0; }
  .topbar__burger { display: none; }
}

/* On the narrowest headers the call to action drops to its icon, which buys
   back about 90 px — enough for the logo to stay whole. The label stays in the
   accessibility tree, so the control is still named. */
@media (max-width: 30rem) {
  .topbar__cta { padding-inline: 0.85rem; }
  .topbar__cta .btn__label {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  }
}

/* Mobile drawer */
.navdrawer {
  position: fixed;
  inset: 4.5rem 0 auto;
  z-index: 99;
  padding: var(--s-4) 0 var(--s-6);
  background: #fff;
  border-bottom: 1px solid var(--line);
  box-shadow: var(--shadow-2);
  transform: translateY(-8px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.22s var(--ease), transform 0.22s var(--ease),
              visibility 0.22s;
}
.navdrawer[data-open="true"] { opacity: 1; transform: none; visibility: visible; }
.navdrawer a {
  display: block;
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--line-soft);
  font-family: var(--display);
  font-size: var(--t-lg);
  color: var(--ink);
}
@media (min-width: 62rem) { .navdrawer { display: none; } }

/* ==========================================================================
   Hero — headline sitting on the map
   ========================================================================== */

/* The track is tall; the sticky child inside it is one viewport. Scrolling the
   track moves nothing on screen except the map's own timeline. */
.hero {
  position: relative;
  height: var(--track, 380vh);
}

.hero__sticky {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: clip;
  background: var(--brand-900);
}

/* The headline block. Sized to its content so the flex column can push the
   chip row to the bottom without stretching the copy to meet it.
   
   Dropped below the header rather than tucked under it: the margin is in vh so
   it opens up on a tall phone, which is where the text was sitting closest to
   the top edge. */
.hero__intro {
  flex: 0 0 auto;
  margin-top: clamp(1rem, 6vh, 3.25rem);
}

/* Two tones, and the first line is the brand's own gold. It is the lightest
   thing on the page by design, so it sits on the darkest part of the scrim and
   the second line drops to a translucent white underneath it rather than
   competing. */
.hero__title {
  max-width: 18ch;
  color: var(--accent-gold);
  font-size: var(--t-4xl);
  font-weight: 600;
  letter-spacing: -0.036em;
  line-height: 1.02;
  text-shadow: 0 2px 30px rgba(23, 17, 10, 0.5);
}
/* Second line dropped to a translucent white: the reference's grey second
   line, adapted for a dark ground. */
.hero__title span { color: var(--accent-gold); }
.hero__title em { font-style: normal; color: rgba(255, 255, 255, 0.68); }

.hero__lede {
  max-width: 34rem;
  margin-top: var(--s-5);
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
  color: rgba(255, 255, 255, 0.84);
  font-size: var(--t-lg);
  line-height: 1.5;
  text-shadow: 0 1px 18px rgba(23, 17, 10, 0.55);
}

.hero__map { position: absolute; inset: 0; }
.hero__map canvas { display: block; width: 100%; height: 100%; touch-action: pan-y; }

/* The map only becomes draggable once the sequence has finished, and the
   cursor is the only thing that says so on a pointer device. */
.hero__map[data-explorable="true"] canvas { cursor: grab; }
.hero__map[data-panning="true"] canvas { cursor: grabbing; }

/* The headline sits directly on the imagery, so it needs its own ground. A
   scrim gradient rather than a panel: a panel would cut the map in half and
   lose exactly the seamlessness the brief asked for. */
.hero__scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(23, 17, 10, 0.62) 0%, rgba(23, 17, 10, 0.30) 30%,
                            rgba(23, 17, 10, 0) 58%),
    linear-gradient(94deg, rgba(23, 17, 10, 0.60) 0%, rgba(23, 17, 10, 0.26) 36%,
                            rgba(23, 17, 10, 0) 68%),
    linear-gradient(0deg, rgba(23, 17, 10, 0.42) 0%, rgba(23, 17, 10, 0) 22%);
}

.hero__content {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding-top: 5.5rem;
  padding-bottom: clamp(1.25rem, 3vw, 2rem);
  pointer-events: none;
}
/* Only the controls take the pointer. The wrapper stretches the full width of
   the hero, so letting its children claim events would make the whole top band
   of the map undraggable for the sake of a headline that is not interactive. */
.hero__content a,
.hero__content button,
.hero__content .hero__chips { pointer-events: auto; }




/* Bottom strip: the map's own state, kept out of the headline's way. The
   readout holds the left, the branch chips take whatever is left and scroll
   inside it rather than pushing the row wider. */
.hero__bar {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  flex-wrap: wrap;
}
.hero__bar .hero__chips { flex: 1 1 auto; min-width: 0; }

@media (max-width: 47.99rem) {
  /* Run the strip out to both screen edges and fade its trailing end. A row
     that stops short of the edge with every chip fully drawn looks complete;
     one that runs off under a fade reads as having more to reach. */
  .hero__bar .hero__chips {
    margin-inline: calc(-1 * clamp(1rem, 3vw, 2.5rem));
    padding-inline: clamp(1rem, 3vw, 2.5rem);
    mask-image: linear-gradient(90deg, #000 0, #000 88%, transparent 100%);
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 88%, transparent 100%);
  }

  /* The lede steps aside as soon as the reader starts scrolling: on a phone it
     is three lines deep and sits exactly where the first pins come down. */
  .hero__content[data-scrolled="true"] .hero__lede {
    opacity: 0;
    transform: translateY(-8px);
    pointer-events: none;
  }
}


/* Branch jump chips, live only once the sequence has finished.
 *
 * The strip itself has to take the pointer, not just the buttons on it. With
 * events landing only on the chips, a drag across the row passed through to
 * the map underneath and the row could not be scrolled at all — so on a narrow
 * screen every chip past the third was simply unreachable.
 *
 * touch-action pins the gesture to the horizontal axis, so dragging the row
 * scrolls the row and dragging anywhere else still scrolls the page. */
.hero__chips {
  display: flex;
  gap: var(--s-2);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  touch-action: pan-x;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding-bottom: 2px;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.35s var(--ease), visibility 0.35s;
}
.hero__chips::-webkit-scrollbar { display: none; }
.hero__content[data-explorable="true"] .hero__chips { opacity: 1; visibility: visible; }

.hero__chips .chip {
  flex: 0 0 auto;                 /* never squeeze a chip to fit the row */
  border-color: rgba(255, 255, 255, 0.18);
  background: rgba(23, 17, 10, 0.5);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  color: rgba(255, 255, 255, 0.92);
}
.hero__chips .chip:hover { border-color: rgba(255, 255, 255, 0.5); color: #fff; }


/* Touch: the map takes the finger only after a tap, and a second tap gives it
   back. Only the way out is announced now. Nothing invites the reader in, so
   the map simply stays passive until someone tries tapping it, which costs a
   feature they may not find; but once it has their finger, the page can no
   longer be scrolled by dragging the map, and that state must never be
   silent. */
.tapnote {
  display: none;
  position: absolute;
  left: 50%; top: 5.5rem;
  transform: translateX(-50%);
  white-space: nowrap;
  padding: 0.5rem 1rem;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 999px;
  background: rgba(23, 17, 10, 0.78);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: #fff;
  font-size: var(--t-sm);
}
@media (hover: none) and (pointer: coarse) {
  .hero__content[data-armed="true"] .tapnote { display: block; }
}

/* No WebGL: the hero still has to be a hero. */
.hero__fallback {
  position: absolute; inset: 0;
  display: none;
  background: var(--brand-900) url('../video/almarjan-orbit-poster.jpg') center/cover;
}
.no-webgl .hero__fallback { display: block; }
.no-webgl .hero { height: 100svh; }
.no-webgl .hero__bar { display: none; }

/* ==========================================================================
   Statement
   ========================================================================== */

.statement { padding-block: var(--s-10); }
.statement p {
  max-width: 52rem;
  font-family: var(--display);
  font-size: var(--t-xl);
  font-weight: 400;
  line-height: 1.42;
  letter-spacing: -0.02em;
  color: var(--ink-2);
}
.statement strong { color: var(--ink); font-weight: 600; }

/* ==========================================================================
   Ecosystem — the interactive list
   ========================================================================== */

.eco__toolbar {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
  padding-bottom: var(--s-5);
  margin-bottom: var(--s-6);
  border-bottom: 1px solid var(--line);
}
.eco__filters { display: flex; gap: var(--s-2); flex-wrap: wrap; }
.eco__sep { width: 1px; height: 1.5rem; background: var(--line); }
.eco__count {
  margin-left: auto;
  color: var(--faint);
  font-size: var(--t-sm);
  font-variant-numeric: tabular-nums;
}

.eco__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-4);
}
@media (min-width: 44rem) { .eco__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 72rem) { .eco__grid { grid-template-columns: repeat(3, 1fr); } }

/* One card is the anchor of the grid — without it every tile competes equally
   and the eye has nowhere to land.
 *
 * At three columns it takes two of them and two rows, so the two cards beside
 * it stack rather than stretching to its height. Spanning width alone left a
 * card's worth of empty white beside the lead, which read as a missing tile
 * rather than as emphasis. Its image then has no fixed ratio and simply grows
 * into whatever height the stacked pair next to it settles at. */
@media (min-width: 44rem) {
  .card--lead { grid-column: span 2; }
  .card--lead .card__media { aspect-ratio: 16 / 9; }
}
@media (min-width: 72rem) {
  .card--lead { grid-row: span 2; }
  /* The image takes every spare pixel and the body stays at its content
     height. Letting both flex split the slack instead parked a card's worth of
     empty white under the lead's footer. */
  .card--lead .card__media { aspect-ratio: auto; flex: 1 1 auto; min-height: 20rem; }
  .card--lead .card__body { flex: 0 0 auto; }
}

.card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: #fff;
  overflow: hidden;
  transition: border-color 0.2s var(--ease), box-shadow 0.25s var(--ease),
              transform 0.25s var(--ease);
}
.card:hover { border-color: var(--line); box-shadow: var(--shadow-3); transform: translateY(-3px); }
.card[data-open="true"] { border-color: var(--brand-400); box-shadow: var(--shadow-2); }

.card__media {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--surface-2);
  overflow: hidden;
}
.card__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.5s var(--ease);
}
.card:hover .card__media img { transform: scale(1.035); }

.card__badges {
  position: absolute;
  inset: var(--s-3) var(--s-3) auto;
  display: flex;
  justify-content: flex-end;
  pointer-events: none;
}

.card__tag {
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  background: rgba(23, 17, 10, 0.72);
  backdrop-filter: blur(6px);
  color: #fff;
  font-size: var(--t-xs);
  font-weight: 500;
}

.card__body { display: flex; flex-direction: column; flex: 1; padding: var(--s-5); }

.card__name {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  font-size: var(--t-lg);
  font-weight: 600;
}
.card__name .ar { font-family: var(--sans); font-size: 0.85em; color: var(--faint); }

.card__desc { margin-top: var(--s-2); font-size: var(--t-base); color: var(--body); }

.card__meta {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-4);
  /* Carries the gap above the footer, because the footer's own margin is auto
     and collapses to nothing whenever the card has no slack to absorb. */
  margin-bottom: var(--s-5);
  color: var(--faint);
  font-size: var(--t-sm);
}
.card__meta svg { width: 0.9rem; height: 0.9rem; flex: none; }

/* Pinned to the bottom of the body, so cards sharing a row line their footers
   up however much text each one carries. */
.card__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  margin-top: auto;
  padding-top: var(--s-4);
  border-top: 1px solid var(--line-soft);
}

.card__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: 0.35rem 0;
  border: 0;
  background: none;
  color: var(--brand-600);
  font-family: var(--display);
  font-size: var(--t-sm);
  font-weight: 550;
  cursor: pointer;
}
.card__toggle svg { transition: transform 0.25s var(--ease); }
.card[data-open="true"] .card__toggle svg { transform: rotate(180deg); }

.card__locate {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: #fff;
  color: var(--ink-2);
  font-size: var(--t-xs);
  font-weight: 500;
  cursor: pointer;
  transition: border-color 0.16s var(--ease), color 0.16s var(--ease);
}
.card__locate:hover { border-color: var(--brand-400); color: var(--brand-600); }
.card__locate svg { width: 0.85rem; height: 0.85rem; }

/* The detail drawer. Height is animated via a grid row rather than max-height,
   so it opens to exactly its content and never to a guessed pixel value. */
.card__detail {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.32s var(--ease);
}
.card[data-open="true"] .card__detail { grid-template-rows: 1fr; }
.card__detail > div { overflow: hidden; }

.card__services {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding-top: var(--s-4);
}
.card__services li {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  font-size: var(--t-base);
  color: var(--ink-2);
}
.card__services li::before {
  content: '';
  flex: none;
  width: 0.375rem; height: 0.375rem;
  margin-top: 0.6em;
  border-radius: 999px;
  background: var(--brand-400);
}

.card__ops {
  margin-top: var(--s-4);
  padding: var(--s-4);
  border-radius: var(--r-md);
  background: var(--brand-050);
  font-size: var(--t-base);
  color: var(--ink-2);
}
.card__ops b {
  display: block;
  margin-bottom: var(--s-1);
  color: var(--brand-600);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* Filtering. Hidden cards leave the flow entirely so the grid reflows; the
   ones that stay animate back in staggered by the script. */
.card[hidden] { display: none; }

/* --- Membership ------------------------------------------------------------
   A closing argument to the list above rather than a section of its own, so
   it is separated by a rule and not by a change of ground. The rule is the
   quiet version of a section break: it admits the subject has changed without
   spending a whole band on saying so. */

.member {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-8);
  margin-top: var(--s-9);
  padding-top: var(--s-9);
  border-top: 1px solid var(--line);
}
@media (min-width: 62rem) {
  .member {
    grid-template-columns: 1fr 1fr;
    gap: var(--s-9);
    align-items: center;
  }
}
/* Stacked, the rule above and the card below are both doing the work of a
   separator, so the block does not need the full section-sized gap as well. */
@media (max-width: 40rem) {
  .member { gap: var(--s-7); margin-top: var(--s-8); padding-top: var(--s-8); }
  .member__lede { font-size: var(--t-md); }
  .member__perks { margin-top: var(--s-5); gap: var(--s-2); }
}

.member__title { font-size: var(--t-2xl); }
.member__title em { font-style: normal; color: var(--faint); }
.member__lede {
  margin-top: var(--s-4);
  max-width: 34rem;
  font-size: var(--t-lg);
  line-height: 1.55;
  color: var(--body);
}

.member__perks { margin-top: var(--s-6); display: grid; gap: var(--s-3); }
.member__perks li {
  display: grid;
  grid-template-columns: 1.25rem 1fr;
  gap: var(--s-3);
  align-items: start;
  color: var(--ink-2);
  font-size: var(--t-base);
}
/* 600, not 400 — a tick this small is type, and type on the tint needs the
   darker step to hold its edge. */
.member__perks li::before {
  content: "\2713";
  color: var(--brand-600);
  font-weight: 600;
  line-height: inherit;
}

/* --- The card -------------------------------------------------------------
   Dark, because the accent is. The metallic golds live at 400 and above and
   are fills, not text colours; laid on the section tint they go flat, and a
   membership card that does not read as metal is just a rectangle. The ratio
   is the physical one (85.6 x 54 mm) so it reads as a card at any width.

   The two faces are stacked in 3D and turned together: hiding one with
   `display` would flip nothing, and fading between them reads as a crossfade,
   not a card. */

/* The wrapper is the query container, not the card: `container-type` applies
   layout containment, and putting that on the element that also carries the
   `perspective` is asking for trouble in the one place this component cannot
   afford it. Everything inside the card is then sized in `cqw`, so a card at
   320 px is the same card as one at 430 px rather than a shrunken frame with
   full-size type spilling out of it. */
.member__visual {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-self: center;
  width: 100%;
  max-width: 27rem;
  container-type: inline-size;
}

.mcard {
  position: relative;
  aspect-ratio: 1.586;
  /* Depth has to scale with the card too. A fixed 1400px viewing distance is
     a gentle tilt on a desktop card and almost flat on a phone; expressed
     against the card's own width the turn has the same weight at every size. */
  perspective: 1400px;
  perspective: 340cqw;
  border-radius: var(--r-lg);
}

/* Two durations, because the two turns are doing different jobs. The one the
   page performs on arrival is a demonstration and can take its time; the one
   a reader asks for by hovering or tapping is a response, and a response that
   takes a second and a half feels broken rather than considered. */
.mcard__inner {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transition: transform 1.05s var(--ease);
}
.mcard[data-auto="true"] .mcard__inner { transition-duration: 1.75s; }
.mcard[data-flipped="true"] .mcard__inner { transform: rotateY(180deg); }

.mcard__face {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  /* Held in a variable because the stripe has to bleed back out through it
     and the turn glyph has to sit inside it. Three places, one number. */
  --pad: clamp(0.9rem, 4.8cqw, 1.6rem);
  padding: var(--pad);
  border-radius: var(--r-lg);
  overflow: hidden;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  background: var(--brand-900);
  color: rgba(255, 255, 255, 0.7);
  box-shadow: var(--shadow-3);
}

/* Two lights rather than one: a warm one at the top-left corner where the
   monogram sits, and a second along the far edge. A single gradient reads as
   a printed panel; two read as something with a surface. */
.mcard__face--front {
  background-image:
    radial-gradient(120% 130% at 8% 0%, rgba(232, 200, 116, 0.30), transparent 55%),
    radial-gradient(90% 120% at 100% 100%, rgba(195, 154, 62, 0.16), transparent 60%),
    linear-gradient(152deg, rgba(255, 255, 255, 0.07) 0%, transparent 38%);
}

.mcard__face--back {
  transform: rotateY(180deg);
  background-image:
    radial-gradient(110% 130% at 92% 0%, rgba(232, 200, 116, 0.22), transparent 58%),
    linear-gradient(200deg, rgba(255, 255, 255, 0.06) 0%, transparent 42%);
}

/* The shine is one thing: a hard specular sweep crossing left to right, the
   card catching a light source directly. The two static gradients above are
   the depth; this is the only part that moves. It is quick on purpose — a
   highlight is the moment a surface passes under a light, and a slow one
   stops being a reflection and becomes a thing sliding across the card.

   Pure `transform` and `opacity` so it stays on the compositor, and gated on
   `data-shine` — a loop is cheap until it is running on a card that scrolled
   off a phone ten minutes ago. */
.mcard__face--front::after {
  content: "";
  position: absolute;
  z-index: 2;
  inset: -40% -60%;
  background: linear-gradient(105deg, transparent 42%, rgba(255, 255, 255, 0.16) 50%, transparent 58%);
  transform: translateX(-60%);
  opacity: 0;
  pointer-events: none;
}
/* The pass is 0.9s of a 6s cycle; the rest of the keyframe is it waiting
   off-frame. Timing the gap into the animation rather than the JS keeps the
   whole loop on the compositor and needs no timer. `linear`, because a real
   highlight crossing a flat surface does not accelerate. */
.mcard[data-shine="true"] .mcard__face--front::after {
  animation: mcard-sheen 6s linear infinite;
}
@keyframes mcard-sheen {
  0%   { transform: translateX(-60%); opacity: 0; }
  2%   { opacity: 1; }
  13%  { opacity: 1; }
  15%  { transform: translateX(60%); opacity: 0; }
  100% { transform: translateX(60%); opacity: 0; }
}

/* Everything below is sized against the card, not the page. A phone does not
   get a smaller card with desktop type crammed into it; it gets the same card
   at a smaller size, which is the only way the proportions survive the trip. */

.mcard__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-4);
}
.mcard__mark { width: clamp(2.25rem, 12cqw, 3.5rem); height: auto; }

.mcard__tier {
  padding: 0.3em 0.85em;
  border: 1px solid rgba(232, 200, 116, 0.45);
  border-radius: 999px;
  color: var(--accent-gold);
  font-family: var(--display);
  font-size: clamp(0.58rem, 2.5cqw, 0.75rem);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Reserves the corner the turn glyph sits in, so the meta row can never run
   underneath it on a narrow card. */
.mcard__bottom { padding-right: clamp(1.9rem, 9cqw, 2.6rem); }

.mcard__word { width: clamp(5rem, 32cqw, 8.5rem); height: auto; }
.mcard__kind {
  margin-top: 0.35em;
  color: rgba(255, 255, 255, 0.62);
  font-size: clamp(0.55rem, 2.3cqw, 0.75rem);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

.mcard__meta {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(0.85rem, 5cqw, 1.5rem);
  margin-top: clamp(0.6rem, 3.6cqw, 1.5rem);
}
.mcard__meta dt {
  color: rgba(255, 255, 255, 0.42);
  font-size: clamp(0.5rem, 2.1cqw, 0.625rem);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.mcard__meta dd {
  margin-top: 0.25em;
  color: var(--accent-gold);
  font-family: var(--mono);
  font-size: clamp(0.6rem, 2.6cqw, 0.8125rem);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* The back. A stripe, because that is the one detail every reader already
   knows means "turn it over", and then the thing the card is actually for. */
.mcard__stripe {
  height: clamp(0.5rem, 2.6cqw, 0.7rem);
  margin: calc(var(--pad) * -0.4) calc(var(--pad) * -1) 0;
  background: linear-gradient(90deg, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0.32));
  border-block: 1px solid rgba(232, 200, 116, 0.16);
  flex: none;
}

.mcard__backtitle {
  margin-top: clamp(0.65rem, 3.4cqw, 1.15rem);
  color: var(--accent-gold);
  font-family: var(--display);
  font-size: clamp(0.65rem, 2.9cqw, 0.8125rem);
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* Two columns is the whole point — six lines in one column is a receipt, and
   the reader is meant to take in the breadth at a glance rather than read it.
   It only drops to one where two would put the longest name on three lines. */
.mcard__lines {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(0.15rem, 1cqw, 0.4rem) clamp(0.6rem, 3.5cqw, 1.1rem);
  margin-top: clamp(0.45rem, 2.4cqw, 0.8rem);
  margin-bottom: auto;
  padding-top: clamp(0.45rem, 2.4cqw, 0.8rem);
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.mcard__lines li {
  display: grid;
  grid-template-columns: clamp(0.4rem, 2cqw, 0.6rem) 1fr;
  gap: clamp(0.3rem, 1.6cqw, 0.5rem);
  align-items: baseline;
  color: rgba(255, 255, 255, 0.78);
  font-size: clamp(0.58rem, 2.5cqw, 0.75rem);
  line-height: 1.4;
}
.mcard__lines li::before {
  content: "";
  width: 0.3em;
  height: 0.3em;
  border-radius: 50%;
  background: var(--brand-400);
}

.mcard__foot {
  padding-top: clamp(0.4rem, 2.2cqw, 0.75rem);
  color: rgba(255, 255, 255, 0.4);
  font-size: clamp(0.5rem, 2.1cqw, 0.625rem);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

/* With the button gone the card carries its own affordance. It is etched
   rather than drawn — a lit ring in the corner where a reader's thumb already
   is — because the first automatic turn has already shown what it does, and a
   second explicit instruction after a demonstration reads as distrust. */
.mcard__turn {
  position: absolute;
  z-index: 1;
  right: var(--pad);
  bottom: var(--pad);
  display: grid;
  place-items: center;
  width: clamp(1.4rem, 6.6cqw, 1.9rem);
  aspect-ratio: 1;
  border: 1px solid rgba(232, 200, 116, 0.26);
  border-radius: 50%;
  color: rgba(232, 200, 116, 0.72);
  background: rgba(255, 255, 255, 0.04);
  pointer-events: none;
  transition: opacity 0.3s var(--ease), border-color 0.3s var(--ease);
}
.mcard__turn svg { width: 58%; height: auto; }
/* It has done its job once the card is turned; leaving it lit on a card the
   reader is already using is clutter. */
.mcard[data-flipped="true"] .mcard__turn { opacity: 0; }

/* The card is the control now, so it has to look and behave like one. The
   global focus ring at the top of this file does the visible half. */
.mcard { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.mcard:focus-visible { outline-offset: 5px; }

/* Reduced motion keeps both faces and every way of reaching them — it only
   removes the turn. The card still has a back; it just arrives there without
   spinning, and it never turns unprompted. */
@media (prefers-reduced-motion: reduce) {
  .mcard__inner { transition: none; }
  .mcard__turn { transition: none; }
  /* The loop stops dead. A perpetual shine is exactly the kind of ambient
     movement this setting exists to switch off, so the card keeps its two
     static gradients and nothing on it moves unless the reader moves it. */
  .mcard[data-shine="true"] .mcard__face--front::after { animation: none; }
}


/* ==========================================================================
   Model
   ========================================================================== */

.model__grid {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: 1fr;
}
@media (min-width: 56rem) { .model__grid { grid-template-columns: repeat(3, 1fr); } }

.reason {
  padding: var(--s-6);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: #fff;
  transition: border-color 0.2s var(--ease), box-shadow 0.25s var(--ease);
}
.reason:hover { border-color: var(--brand-400); box-shadow: var(--shadow-2); }
.reason__num {
  display: block;
  margin-bottom: var(--s-5);
  /* 600, not the brighter 400: this is text on white, and the metallic gold
     that reads well on a sign or a dark panel only manages 2.6:1 here. */
  color: var(--brand-600);
  font-family: var(--mono);
  font-size: var(--t-sm);
  font-variant-numeric: tabular-nums;
}
.reason h3 { font-size: var(--t-lg); }
.reason p { margin-top: var(--s-3); font-size: var(--t-base); }

/* The inverted block. One per section at most — its power is entirely in
   being the only thing on the page that is not white. */
.panel {
  margin-top: var(--s-6);
  padding: clamp(2rem, 5vw, 3.5rem);
  border-radius: var(--r-xl);
  background: var(--brand-900);
  color: rgba(255, 255, 255, 0.78);
  background-image: radial-gradient(120% 140% at 12% 0%, rgba(195, 154, 62, 0.26), transparent 58%);
}
.panel h3, .panel h2 { color: #fff; }
.panel__quote {
  max-width: 24ch;
  font-size: var(--t-2xl);
  letter-spacing: -0.03em;
}
.panel__row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s-6);
  flex-wrap: wrap;
}
.panel p { max-width: 34rem; margin-top: var(--s-4); }

/* ==========================================================================
   Operations gallery
   ========================================================================== */

.ops__grid {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: 1fr;
}
@media (min-width: 44rem) { .ops__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 72rem) { .ops__grid { grid-template-columns: repeat(12, 1fr); } }

/* An even grid of four photographs is a contact sheet, not a composition. On
   the widest frame two of them take more width than the others. */
@media (min-width: 72rem) {
  .shot:nth-child(1) { grid-column: span 7; }
  .shot:nth-child(2) { grid-column: span 5; }
  .shot:nth-child(3) { grid-column: span 5; }
  .shot:nth-child(4) { grid-column: span 7; }
}

.shot {
  position: relative;
  display: flex;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface-2);
}
/* height:100% so a narrow tile fills the row height set by its wider
   neighbour — with only an aspect ratio it came up short and left a band of
   background under the photograph. The ratio still governs when the tile is
   alone on its row, which is the single-column case. */
.shot img {
  width: 100%; height: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  transition: transform 0.6s var(--ease);
}
.shot:hover img { transform: scale(1.03); }

/* --- A tile that holds more than one shot ---------------------------------
   Every slide occupies the same grid cell, so they stack without being taken
   out of flow and the tile still sizes itself to its tallest child. The
   alternative — absolute slides — needs a height declared somewhere, and the
   tiles in this grid do not have one: they take it from the row. */
.shot--slides { display: grid; }
.shot--slides .slide {
  grid-area: 1 / 1;
  position: relative;
  margin: 0;
  opacity: 0;
  transition: opacity 0.7s var(--ease);
}
.shot--slides .slide[data-current="true"] { opacity: 1; z-index: 1; }

/* Without the script every slide is visible and stacked; showing the first
   one keeps that from being a pile. Removed by the script on startup so the
   fade has something to fade between. */
.shot--slides:not([data-ready="true"]) .slide:first-child { opacity: 1; }

.slides__dots {
  position: absolute;
  z-index: 2;
  top: var(--s-4);
  right: var(--s-4);
  display: flex;
  gap: var(--s-2);
}
/* Sized to the 44px touch minimum by its padding while the visible dot stays
   small — the target has to be bigger than the mark it draws. */
.slides__dot {
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  display: grid;
  place-items: center;
}
.slides__dot::before {
  content: "";
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.5);
  box-shadow: 0 1px 3px rgba(23, 17, 10, 0.5);
  transition: background 0.25s var(--ease), transform 0.25s var(--ease);
}
.slides__dot:hover::before { background: rgba(255, 255, 255, 0.8); }
.slides__dot[aria-current="true"]::before {
  background: var(--accent-gold);
  transform: scale(1.25);
}

@media (prefers-reduced-motion: reduce) {
  .shot--slides .slide { transition: none; }
}
.shot figcaption {
  position: absolute;
  inset: auto 0 0;
  padding: var(--s-7) var(--s-5) var(--s-4);
  background: linear-gradient(0deg, rgba(23, 17, 10, 0.85), rgba(23, 17, 10, 0));
  color: rgba(255, 255, 255, 0.92);
  font-size: var(--t-sm);
}

/* ==========================================================================
   Growth
   ========================================================================== */

.phases {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: 1fr;
}
@media (min-width: 56rem) { .phases { grid-template-columns: repeat(3, 1fr); } }

.phase {
  display: flex;
  flex-direction: column;
  padding: var(--s-6);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: #fff;
}
.phase__no {
  display: block;
  padding-bottom: var(--s-4);
  border-bottom: 1px solid var(--line-soft);
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
}
.phase h3 { margin-top: var(--s-4); font-size: var(--t-lg); }
.phase__when { margin-top: var(--s-1); font-size: var(--t-sm); color: var(--faint); }
.phase ul { margin-top: var(--s-5); display: flex; flex-direction: column; gap: var(--s-3); }
.phase li {
  display: flex;
  gap: var(--s-3);
  font-size: var(--t-base);
  color: var(--ink-2);

  /* Dealt out one at a time rather than arriving as a block. --i is the item's
     place in its own list and --phase is the card's place in the row, so the
     three lists run left to right instead of all starting at once: the reader
     sees the roadmap being laid down in the order it actually happens.
     
     The delay is the only thing the script sets. Keeping the motion itself in
     CSS means the reduced-motion rule at the foot of this file switches it off
     with everything else, without the script needing to know. */
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.45s var(--ease), transform 0.45s var(--ease);
  transition-delay: calc(var(--phase, 0) * 200ms + var(--i, 0) * 110ms + 160ms);
}
.phase[data-run="true"] li { opacity: 1; transform: none; }

/* The marker draws itself in as its line arrives, which is what makes the list
   read as being ticked off rather than faded up. */
.phase li::before {
  content: '';
  flex: none;
  width: 0.375rem; height: 0.375rem;
  margin-top: 0.6em;
  border-radius: 999px;
  background: var(--brand-400);
  transform: scale(0.2);
  transition: transform 0.4s var(--ease);
  transition-delay: inherit;
}
.phase[data-run="true"] li::before { transform: none; }
.phase--next li::before { background: var(--faint); }

/* ==========================================================================
   Leadership
   ========================================================================== */

.founder {
  display: grid;
  gap: var(--s-7);
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 56rem) { .founder { grid-template-columns: 22rem 1fr; gap: var(--s-8); } }

.founder__photo {
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface-2);
}
.founder__photo img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }

.founder__name { font-size: var(--t-2xl); }
.founder__role {
  margin-top: var(--s-2);
  color: var(--brand-600);
  font-size: var(--t-sm);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.founder p + p { margin-top: var(--s-4); }
.founder__body { margin-top: var(--s-5); max-width: 42rem; font-size: var(--t-base); }

blockquote {
  margin: var(--s-6) 0 0;
  max-width: 40rem;
  padding-left: var(--s-5);
  border-left: 2px solid var(--brand-400);
  font-family: var(--display);
  font-size: var(--t-lg);
  font-weight: 400;
  line-height: 1.45;
  letter-spacing: -0.02em;
  color: var(--ink);
}

.team {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  margin-top: var(--s-8);
  padding-top: var(--s-7);
  border-top: 1px solid var(--line);
}
.team h4 { font-size: var(--t-base); font-weight: 600; }
.team span {
  display: block;
  margin-top: var(--s-1);
  color: var(--faint);
  font-size: var(--t-sm);
}
.team p { margin-top: var(--s-3); font-size: var(--t-sm); }

/* ==========================================================================
   Locations
   ========================================================================== */

.places {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: 1fr;
}
@media (min-width: 44rem) { .places { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 72rem) { .places { grid-template-columns: repeat(4, 1fr); } }

.place {
  display: flex;
  flex-direction: column;
  padding: var(--s-5);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: #fff;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.2s var(--ease), box-shadow 0.25s var(--ease),
              transform 0.25s var(--ease);
}
.place:hover { border-color: var(--brand-400); box-shadow: var(--shadow-2); transform: translateY(-2px); }
.place h3 { margin-top: var(--s-4); font-size: var(--t-lg); }
.place__addr { margin-top: var(--s-2); margin-bottom: var(--s-4); font-size: var(--t-sm); color: var(--body); }
/* Pinned to the bottom so the rules line up across the row whether an address
   wrapped to two lines or one. */
.place__lines {
  margin-top: auto;
  padding-top: var(--s-4);
  border-top: 1px solid var(--line-soft);
  font-size: var(--t-sm);
  color: var(--brand-600);
  font-weight: 500;
}

/* ==========================================================================
   Contact
   ========================================================================== */

.contact { background: var(--brand-900); color: rgba(255, 255, 255, 0.75); }
.contact h2 { color: #fff; }
.contact .eyebrow { color: var(--brand-400); }

.contact__grid {
  display: grid;
  gap: var(--s-8);
  grid-template-columns: 1fr;
}
@media (min-width: 56rem) { .contact__grid { grid-template-columns: 1.1fr 1fr; gap: var(--s-9); } }

.contact__lede { margin-top: var(--s-5); max-width: 32rem; font-size: var(--t-lg); }
.contact__actions { margin-top: var(--s-6); display: flex; flex-wrap: wrap; gap: var(--s-3); }

.details { display: flex; flex-direction: column; gap: var(--s-5); }
.details > div { padding-bottom: var(--s-5); border-bottom: 1px solid rgba(255, 255, 255, 0.12); }
.details > div:last-child { border-bottom: 0; padding-bottom: 0; }
.details dt {
  color: rgba(255, 255, 255, 0.45);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.details dd {
  margin: var(--s-2) 0 0;
  color: #fff;
  font-family: var(--display);
  font-size: var(--t-lg);
  letter-spacing: -0.02em;
}
.details dd small { display: block; margin-top: var(--s-2); font-family: var(--sans); font-size: var(--t-sm); color: rgba(255, 255, 255, 0.6); letter-spacing: 0; }
.details a:hover { color: var(--accent-gold); }

/* ==========================================================================
   Footer
   ========================================================================== */

.footer {
  padding-block: var(--s-8) var(--s-6);
  border-top: 1px solid var(--line);
}
.footer__grid {
  display: grid;
  gap: var(--s-7);
  grid-template-columns: 1fr;
  padding-bottom: var(--s-7);
}
@media (min-width: 56rem) { .footer__grid { grid-template-columns: 1.4fr 1fr 1fr; } }

.footer p { margin-top: var(--s-4); max-width: 24rem; font-size: var(--t-sm); }

/* The trademark line. It belongs to the wordmark above it, not to the
   paragraph below, so it sits tight under the logo and the descriptive line
   keeps its full gap — the spacing is what tells a reader which of the two it
   is. 600, not the brighter metallic step: this is small type on white. */
.footer .brand__tag {
  margin-top: var(--s-3);
  color: var(--brand-600);
  font-family: var(--display);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.footer h4 {
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
}
.footer ul { margin-top: var(--s-4); display: flex; flex-direction: column; gap: var(--s-3); }
.footer li a { font-size: var(--t-sm); color: var(--ink-2); }
.footer li a:hover { color: var(--brand-600); }
.footer__base {
  display: flex;
  justify-content: space-between;
  gap: var(--s-4);
  flex-wrap: wrap;
  padding-top: var(--s-5);
  border-top: 1px solid var(--line);
  color: var(--faint);
  font-size: var(--t-sm);
}

/* ==========================================================================
   Motion
   ========================================================================== */

/* Filtering the ecosystem grid. Short and small: the cards have not moved
   far, and a big entrance on a re-filter reads as a page load. */
@keyframes cardIn {
  from { opacity: 0; transform: translateY(10px) scale(0.99); }
  to   { opacity: 1; transform: none; }
}

/* Entries only, 500 ms, ease-out, and never more than a small translate — a
   marketing page that animates on exit as well starts to feel like it is
   arguing with the scroll. */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
}
.reveal[data-shown="true"] { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
  .reveal { opacity: 1; transform: none; }
  .phase li { opacity: 1; transform: none; }
  .phase li::before { transform: none; }
  .hero { height: 100svh; }
}
