/* ============================================================
   Reflex marketing site (reflex.rehab)
   One set of CSS custom properties drives the whole site.
   Ported from the ATDev design system (atdev.tech, styles/atos.css)
   with the brand tokens retuned to the Reflex palette, taken from the
   Reflex logo artwork: royal blue #1A6ACC, navy #07214A,
   bright blue #67B6FF, light blue #A8D8FF, pale #E8F4FF.
   Typography stays the ATDev family set (Montserrat, Raleway) so the
   two properties read as one company.
   Light is the default; a dark theme overrides the tokens.
   ============================================================ */

:root {
  /* palette */
  --bg: #F9FAFB;
  --bg-2: #FFFFFF;
  --bg-3: #EDF3FD;
  --surface: rgba(3, 9, 13, 0.03);
  --surface-2: rgba(3, 9, 13, 0.06);
  --line: rgba(3, 9, 13, 0.10);
  --line-2: rgba(3, 9, 13, 0.18);

  --text: #03090D;
  --muted: #606161;
  --faint: #6B7280;

  /* Reflex brand blues, lifted from the logo artwork.
     --brand is the accent components use for text, icons and links, so it
     shifts per theme to stay >= AA. --brand-fill, --brand-soft and
     --brand-navy are fixed brand values for fills, gradients and graphics,
     where contrast is not a text concern.
     Royal blue carries both roles here: #1A6ACC measures 5.3:1 under white
     and 5.1:1 as text on the off-white page, so unlike the ATDev set it
     needs no separate darker value for buttons. */
  --brand: #1A6ACC;
  --brand-deep: #1A6ACC;
  --brand-fill: #67B6FF;
  --brand-soft: #A8D8FF;
  --brand-navy: #07214A;

  --brand-fill-rgb: 103, 182, 255;
  --brand-deep-rgb: 26, 106, 204;
  --brand-soft-rgb: 168, 216, 255;
  --brand-navy-rgb: 7, 33, 74;

  --grad: linear-gradient(135deg, #1A6ACC 0%, #67B6FF 100%);
  --grad-soft: linear-gradient(135deg, rgba(var(--brand-deep-rgb), .10), rgba(var(--brand-fill-rgb), .12));
  /* gradient for clipped TEXT: darkened in light for AA contrast, bright in dark */
  --grad-ink: linear-gradient(135deg, #07214A 0%, #1A6ACC 100%);

  --radius: 12px;
  --radius-sm: 8px;
  --container: 1200px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  --font: "Montserrat", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-body: "Raleway", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  /* Eyebrow/label face. The original site has no monospace, so labels use
     Montserrat and lean on the letter-spacing already set on those rules. */
  --mono: "Montserrat", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* themed surfaces (overridden by the dark theme below) */
  --nav-bg: rgba(255, 255, 255, 0.82);
  --nav-bg-solid: rgba(255, 255, 255, 0.97);
  --grid-line: rgba(3, 9, 13, 0.06);

  color-scheme: light;
}

/* ============ DARK THEME ============
   Light is the default. The dark palette activates when
   data-theme="dark" is set on <html> (by the no-FOUC head script
   and the nav toggle). --brand brightens to the bright blue so
   accent text stays legible on near-black (9.2:1). */
:root[data-theme="dark"] {
  --bg: #03090D;
  --bg-2: #0A1219;
  --bg-3: #0E1922;
  --surface: rgba(255, 255, 255, 0.03);
  --surface-2: rgba(255, 255, 255, 0.055);
  --line: rgba(255, 255, 255, 0.10);
  --line-2: rgba(255, 255, 255, 0.18);

  --text: #F9FAFB;
  --muted: #A8B3BD;
  --faint: #8C97A2;

  --brand: #67B6FF;

  --grad-ink: linear-gradient(135deg, #67B6FF 0%, #A8D8FF 100%);

  --nav-bg: rgba(3, 9, 13, 0.78);
  --nav-bg-solid: rgba(3, 9, 13, 0.97);
  --grid-line: rgba(255, 255, 255, 0.05);

  color-scheme: dark;
}

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

html { scroll-behavior: smooth; scroll-padding-top: 90px; }

body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  transition: background .3s var(--ease), color .3s var(--ease);
}

/* The original site pairs Montserrat for headings and UI with Raleway for
   running text. body sets Montserrat above; prose opts into Raleway. */
p, li, blockquote, dd, figcaption, .nav__links a { font-family: var(--font-body); }
h1, h2, h3, h4, h5, h6 { font-family: var(--font); }

/* ambient page texture */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  background:
    radial-gradient(900px 600px at 12% -5%, rgba(var(--brand-deep-rgb),.10), transparent 60%),
    radial-gradient(800px 600px at 98% 8%, rgba(var(--brand-fill-rgb),.08), transparent 55%);
  pointer-events: none;
  z-index: 0;
}

img, svg, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }

::selection { background: rgba(var(--brand-deep-rgb),.4); color: #fff; }

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

.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 24px;
  position: relative;
  z-index: 1;
}
.container--narrow { max-width: 840px; }

/* screen-reader-only text (e.g. "opens in new tab") */
.visually-hidden, .sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: -999px;
  top: 12px;
  z-index: 200;
  background: var(--brand-deep);
  color: #fff;
  padding: 10px 18px;
  border-radius: 8px;
  font-weight: 600;
}
.skip-link:focus { left: 16px; }

/* ============ BUTTONS ============ */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  font-size: 0.95rem;
  padding: 11px 20px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform .25s var(--ease), box-shadow .25s var(--ease), background .25s var(--ease), border-color .25s var(--ease);
  white-space: nowrap;
  font-family: var(--font);
}
.btn--lg { padding: 14px 26px; font-size: 1rem; }
/* Primary CTA, matching the original site: solid blue, white uppercase label,
   darkening on hover. Deep blue rather than bright blue as the resting fill so
   white label text clears AA (6.5:1); bright blue would sit at 2.6:1. */
.btn--solid {
  background: var(--brand-deep);
  color: #fff;
  text-transform: uppercase;
  letter-spacing: .04em;
  box-shadow: 0 4px 14px -6px rgba(var(--brand-deep-rgb),.55);
}
.btn--solid:hover { background: #134FA0; transform: translateY(-2px); box-shadow: 0 10px 24px -8px rgba(var(--brand-deep-rgb),.7); }
.btn--ghost {
  background: var(--surface);
  border-color: var(--line-2);
  color: var(--text);
  backdrop-filter: blur(8px);
}
.btn--ghost:hover { background: var(--surface-2); border-color: var(--brand); transform: translateY(-2px); }

/* ============ NAV ============ */
/* Always a solid bar, as on the original site. It used to be transparent until
   scrolled, which only worked over a dark hero: over the blue brand hero the
   muted link colour was unreadable. Scrolling just adds a little elevation. */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  background: var(--nav-bg);
  backdrop-filter: blur(16px) saturate(140%);
  border-bottom: 1px solid var(--line);
  transition: box-shadow .3s var(--ease), background .3s var(--ease);
}
.nav.is-scrolled {
  background: var(--nav-bg-solid);
  box-shadow: 0 6px 20px -14px rgba(3, 9, 13, .55);
}
.nav__inner {
  max-width: var(--container);
  margin: 0 auto;
  padding: 14px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}
.brand { display: inline-flex; align-items: center; gap: 10px; }
/* The Reflex wordmark, images/reflex-wordmark.svg. Height-driven, width auto,
   so the 3.91:1 artwork keeps its ratio. The width/height attributes on the
   <img> match the viewBox and reserve the box before the SVG loads, so the nav
   does not shift. */
.brand__logo {
  height: 30px;
  width: auto;
  transition: opacity .25s var(--ease);
}
.brand__logo--sm { height: 26px; }
.brand:hover .brand__logo { opacity: 0.8; }
/* The wordmark art is near-black (#03090D), matching the brand sheet. Rather
   than ship a second file for the dark theme, drive it to pure white:
   brightness(0) flattens every channel to black first, so invert(1) lands on
   #FFF regardless of the source colour. A bare invert(1) would give a warm
   off-white instead, since it inverts #03090D to #FCF6F2. */
:root[data-theme="dark"] .brand__logo { filter: brightness(0) invert(1); }


.nav__menu { display: flex; align-items: center; gap: 28px; }
.nav__links { display: flex; gap: 28px; }
.nav__links a {
  color: var(--muted);
  font-size: 0.92rem;
  font-weight: 500;
  position: relative;
  transition: color .2s var(--ease);
}
.nav__links a::after {
  content: "";
  position: absolute;
  left: 0; bottom: -6px;
  height: 2px; width: 0;
  background: var(--grad);
  transition: width .25s var(--ease);
}
.nav__links a:hover,
.nav__links a.is-current { color: var(--text); }
.nav__links a:hover::after,
.nav__links a.is-current::after { width: 100%; }

.nav__cta { display: flex; gap: 10px; align-items: center; }

/* theme toggle */
.theme-toggle {
  display: inline-grid;
  place-items: center;
  width: 40px; height: 40px;
  flex-shrink: 0;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  backdrop-filter: blur(8px);
  transition: border-color .2s var(--ease), color .2s var(--ease), background .2s var(--ease), transform .2s var(--ease);
}
.theme-toggle:hover { border-color: var(--brand); color: var(--brand); transform: translateY(-2px); }
.theme-toggle__icon { width: 18px; height: 18px; }
/* Light is the base: show the moon (click to go dark). Dark shows the sun. */
.theme-toggle__icon--sun { display: none; }
:root[data-theme="dark"] .theme-toggle__icon--moon { display: none; }
:root[data-theme="dark"] .theme-toggle__icon--sun { display: block; }

.nav__toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px;
}
.nav__toggle span {
  width: 24px; height: 2px;
  background: var(--text);
  border-radius: 2px;
  transition: transform .3s var(--ease), opacity .3s var(--ease);
}
.nav.is-open .nav__toggle span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav.is-open .nav__toggle span:nth-child(2) { opacity: 0; }
.nav.is-open .nav__toggle span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ============ HERO ============ */
.hero {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  padding: 140px 0 80px;
  overflow: hidden;
}
.hero--short { min-height: 72vh; padding: 160px 0 80px; }
.hero__aurora {
  position: absolute;
  inset: -20% -10% auto -10%;
  height: 120%;
  background:
    radial-gradient(40% 50% at 22% 30%, rgba(var(--brand-fill-rgb),.30), transparent 70%),
    radial-gradient(45% 55% at 78% 28%, rgba(var(--brand-deep-rgb),.34), transparent 70%),
    radial-gradient(40% 45% at 55% 75%, rgba(var(--brand-soft-rgb),.20), transparent 70%);
  filter: blur(20px);
  animation: drift 18s ease-in-out infinite alternate;
  z-index: 0;
}
@keyframes drift {
  0%   { transform: translate3d(0,0,0) scale(1); }
  50%  { transform: translate3d(2%, -3%, 0) scale(1.08); }
  100% { transform: translate3d(-3%, 2%, 0) scale(1.04); }
}
.hero__grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: 54px 54px;
  -webkit-mask-image: radial-gradient(110% 90% at 50% 0%, #000 35%, transparent 78%);
          mask-image: radial-gradient(110% 90% at 50% 0%, #000 35%, transparent 78%);
  z-index: 0;
}
/* optional background video, kept dark and subtle to match the aesthetic */
.hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
}
/* ---- hero photo legibility ----
   The photo used to be dimmed globally (0.14 under a .55-.85 scrim), which
   bought text contrast by destroying the image: only ~6% of the photo's own
   tonal range survived, so you could not tell what you were looking at.

   The dimming is now split in two. A light flat wash keeps the photo tied to
   the brand, and a SEPARATE scrim (::before) darkens only the ellipse the copy
   sits in. Contrast is paid for locally, where the text is, instead of being
   charged to the whole image. Net effect: ~62% of the photo's range survives in
   the open areas here (10x the old figure), 73% on the brand hero, and measured
   text contrast goes UP rather than down - 4.21:1 to 6.22:1 on the home title.

   Worst case is p99 of the text band against the brightest gradient stop and
   the weakest wash end simultaneously - see docs/accessibility-audit-2026-08.md.
   Re-measure if you touch any of the three alphas. */
.hero__media video,
.hero__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0.70;
}
.hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(249,250,251,.12), rgba(249,250,251,.24));
}
/* Local scrim behind the copy. z-index is required, not decorative: a ::before
   is the first child in tree order and would otherwise paint UNDER the img.
   .hero__media already carries z-index:0, so this stays contained.
   Geometry is deliberate - the solid stop runs to 45% of an 68%x70% ellipse,
   i.e. x 19-81% / y 18-82%, so the whole content column gets the FULL .76 and
   the falloff happens outside it. A scrim that faded across the text instead
   would leave the first and last lines short of contrast. */
.hero__media::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: radial-gradient(ellipse 68% 70% at 50% 50%,
              rgba(255,255,255,.76) 0%,
              rgba(255,255,255,.76) 45%,
              rgba(255,255,255,0) 100%);
}
:root[data-theme="dark"] .hero__media::after {
  background: linear-gradient(180deg, rgba(3,9,13,.12), rgba(3,9,13,.24));
}
:root[data-theme="dark"] .hero__media::before {
  background: radial-gradient(ellipse 68% 70% at 50% 50%,
              rgba(3,9,13,.76) 0%,
              rgba(3,9,13,.76) 45%,
              rgba(3,9,13,0) 100%);
}
/* ---- hero slideshow ----
   Stacked images that crossfade. The dimming lives on .hero__slides so the
   slides themselves are free to animate 0 -> 1 without fighting it.
   The three-class selectors are deliberate: the base `.hero__media img` rule
   (0,2,0) would otherwise clamp every slide to the dimmed value and kill the
   fade. `:not(.is-active)` buys the extra class needed to outrank it without
   resorting to !important. Both themes share one value now - contrast is the
   ::before scrim's job, so the photo no longer has to be dimmed per theme. */
.hero__slides { position: absolute; inset: 0; opacity: 0.70; }
.hero--brand .hero__slides { opacity: 0.85; }
.hero__slide {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.hero__media .hero__slides .hero__slide { transition: opacity 1.1s var(--ease); }
.hero__media .hero__slides .hero__slide.is-active { opacity: 1; }
.hero__media .hero__slides .hero__slide:not(.is-active) { opacity: 0; }

/* ---- Ken Burns drift ----
   CONSTRAINT, do not relax casually: pure scale, always >= 1, about a fixed
   origin. No translate, ever. Scaling up about a point inside the headline band
   means the source pixels still on screen are a subset of the un-zoomed framing,
   which keeps the contrast story tractable. Add a translate and that is gone:
   content slides in from outside the frame and all four slides need re-measuring
   from scratch. The varied transform-origin supplies the pan-like feel instead.

   Note the subset argument bounds which SOURCE pixels are shown, not how bright
   they render. At rest the 1920px source is downsampled to ~70%, which averages
   bright peaks away; zooming in reduces that downsampling and lets them through,
   so measured contrast can dip slightly as it zooms. It was swept across the
   whole range rather than assumed - worst case 4.62:1, in
   docs/accessibility-audit-2026-08.md. Re-sweep if the zoom ceiling changes. */
@keyframes kenburns {
  from { transform: scale(1); }
  to   { transform: scale(1.08); }
}
.hero__media .hero__slides .hero__slide {
  animation: kenburns 20s ease-in-out infinite alternate;
  /* Only the visible slide animates. Pausing rather than stopping means a slide
     resumes from where it left off instead of snapping back to scale 1 while it
     is still mid-crossfade. */
  animation-play-state: paused;
}
.hero__media .hero__slides .hero__slide.is-active { animation-play-state: running; }
/* Different anchor per slide, so each one drifts its own way. */
.hero__slides .hero__slide:nth-child(1) { transform-origin: 32% 42%; }
.hero__slides .hero__slide:nth-child(2) { transform-origin: 68% 56%; animation-delay: -5s; }
.hero__slides .hero__slide:nth-child(3) { transform-origin: 42% 68%; animation-delay: -10s; }
.hero__slides .hero__slide:nth-child(4) { transform-origin: 64% 36%; animation-delay: -15s; }

.hero__spotlight {
  position: absolute;
  width: 600px; height: 600px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--brand-fill-rgb),.18), transparent 65%);
  transform: translate(-50%, -50%);
  pointer-events: none;
  z-index: 0;
  opacity: 0;
  transition: opacity .4s var(--ease);
}
/* 1000px, not 920px: the homepage h1's static phrase ("The future of mobility
   is") measures 11.03em, so at the 5rem clamp ceiling it needs 883px. The old
   920px cap left an 872px content box, missing by 11px and dropping "is" onto a
   line of its own above the animated word. The extra 80px clears it with room to
   spare. .hero__sub keeps its own 680px measure, so body copy is unaffected. */
.hero__content { max-width: 1000px; text-align: center; margin: 0 auto; }

.hero__title {
  font-size: clamp(2.5rem, 6.2vw, 5rem);
  line-height: 1.04;
  letter-spacing: -0.03em;
  font-weight: 800;
}
.hero--short .hero__title { font-size: clamp(2.2rem, 5vw, 3.6rem); }
.grad-text {
  display: block;
  background: var(--grad-ink);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
.grad-text--inline { display: inline; }
.hero__sub {
  font-size: clamp(1.05rem, 1.8vw, 1.3rem);
  color: var(--muted);
  max-width: 680px;
  margin: 26px auto 0;
}
.hero__sub strong { color: var(--text); }
/* Short heroes are the ones that carry a photo behind the copy (about, rammp).
   Over the brightened image --muted (#606161) measures 4.11:1 against the p01
   of the text band, i.e. under AA. A slightly deeper ink clears it at 5.4:1 and
   still reads as secondary next to the title. Applied to every short hero, not
   only the two with photos, so there is no :has() dependency - a browser that
   failed to match it would land on exactly the failing colour.
   Dark theme keeps --muted (#A8B3BD), which already measures 6.1:1 there. */
.hero--short .hero__sub { color: #4A5052; }
:root[data-theme="dark"] .hero--short .hero__sub { color: var(--muted); }
/* Breadcrumb above a hero title. The link measured 57x19 on a phone, under the
   24px WCAG 2.5.8 minimum. It arguably qualifies for the inline exception,
   sitting in a line of text, but it is still a real navigation control that a
   thumb has to find, so inline-block plus vertical padding grows the hit area
   to 27px without moving the line. */
.crumbs a { display: inline-block; padding: 4px 2px; margin: -4px -2px; }
.hero__actions {
  margin-top: 38px;
  display: flex;
  gap: 14px;
  justify-content: center;
  flex-wrap: wrap;
}
.hero__tagline {
  margin-top: 40px;
  font-family: var(--mono);
  font-size: 0.95rem;
  color: var(--faint);
  min-height: 1.5em;
}
/* The typewriter empties this element between words. As a block with no content
   it generates no line box, so the h1 loses a whole line and everything under it
   jumps (measured: 250px -> 166px, an 84px shift, every cycle). The ::after caret
   always generates an inline box, which holds the line open; min-height is the
   belt-and-braces. Height matches .hero__title's line-height.

   The caret is a pseudo-element rather than border-right on purpose: this is a
   full-width centred block, so a border would draw at the block's right edge and
   park a stray caret far away from the text. ::after sits after the last glyph. */
.type {
  min-height: 1.04em;
}
.type::after {
  content: "";
  display: inline-block;
  width: 2px;
  height: 0.92em;
  margin-left: 4px;
  vertical-align: -0.08em;
  background: var(--brand);
}
/* Reduced motion / single phrase: no animation, so no caret. */
.type.is-static::after { display: none; }
.hero--short .type { min-height: 1.1em; }

.hero__scroll {
  position: absolute;
  bottom: 26px; left: 50%;
  transform: translateX(-50%);
  width: 26px; height: 42px;
  border: 2px solid var(--line-2);
  border-radius: 14px;
  display: flex;
  justify-content: center;
  padding-top: 8px;
  z-index: 1;
}
.hero__scroll span {
  width: 4px; height: 8px;
  background: var(--brand);
  border-radius: 2px;
  animation: scrolldot 1.8s infinite;
}
@keyframes scrolldot {
  0% { transform: translateY(0); opacity: 1; }
  70% { transform: translateY(14px); opacity: 0; }
  100% { opacity: 0; }
}

/* ============ STRIP ============ */
.strip {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 36px 0;
  background: var(--bg-2);
}
.strip__label {
  text-align: center;
  color: var(--muted);
  font-size: 0.92rem;
  margin-bottom: 22px;
}
.strip__logos {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px 38px;
}
.strip__logos span {
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--faint);
  letter-spacing: 0.01em;
  transition: color .25s var(--ease);
}
.strip__logos span:hover { color: var(--text); }

/* ============ MARQUEE (logo / press strips) ============ */
.marquee {
  position: relative;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee__track {
  display: flex;
  gap: 22px;
  width: max-content;
  animation: marquee 42s linear infinite;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
/* Hover pause cannot be reached from the keyboard, so the stop control for
   WCAG 2.2.2 toggles this class instead. */
.marquee.is-paused .marquee__track { animation-play-state: paused; }
@keyframes marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
/* Flex, not grid, for the same reason as .logo-chip: the tile height is
   definite, so a flex item's max-height:100% has something to resolve
   against. Under grid the auto row lets tall logos escape the tile. */
.marquee__item {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 92px;
  width: 168px;
  padding: 16px 22px;
  border-radius: var(--radius-sm);
  background: #fff;
  border: 1px solid var(--line);
  overflow: hidden;
  transition: transform .25s var(--ease), box-shadow .25s var(--ease);
}
.marquee__item:hover { transform: translateY(-4px); box-shadow: 0 16px 34px -18px rgba(var(--brand-fill-rgb),.6); }
.marquee__item img {
  max-height: 100%;
  max-width: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}
/* press variant: text quotes rather than logos */
.marquee--press .marquee__item {
  background: var(--surface);
  width: auto;
  min-width: 240px;
  max-width: 340px;
  height: auto;
  padding: 20px 24px;
  text-align: left;
  /* The base .marquee__item is a centred flex row (so logos can be sized
     against a definite height). Press tiles are text: stack them and pin to
     the top left. */
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
}
.marquee--press .marquee__quote { color: var(--text); font-size: 0.95rem; line-height: 1.45; }
.marquee--press .marquee__src { display: block; margin-top: 10px; font-family: var(--mono); font-size: 0.78rem; color: var(--brand); }

/* ============ SECTIONS ============ */
.section { padding: 110px 0; position: relative; }
.section--alt { background: var(--bg-2); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.section__head { max-width: 760px; margin: 0 auto 56px; text-align: center; }
.section__head--left { margin-left: 0; text-align: left; }
.eyebrow {
  display: inline-block;
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brand);
  margin-bottom: 16px;
}
.section__title {
  font-size: clamp(1.8rem, 3.6vw, 2.8rem);
  line-height: 1.12;
  letter-spacing: -0.02em;
  font-weight: 800;
}
.section__lead {
  margin-top: 18px;
  color: var(--muted);
  font-size: clamp(1rem, 1.4vw, 1.15rem);
}
.section__lead em { color: var(--text); font-style: italic; }

/* ============ CARDS ============ */
.cards { display: grid; gap: 22px; }
.cards--3 { grid-template-columns: repeat(3, 1fr); }
.cards--2 { grid-template-columns: repeat(2, 1fr); }
.cards--4 { grid-template-columns: repeat(4, 1fr); }
.cards--feature { grid-template-columns: repeat(3, 1fr); }
/* A lone card in a multi-column grid otherwise sits in the first cell and
   leaves an obvious hole (e.g. careers with a single open role). */
.cards > :only-child { grid-column: 1 / -1; }

.card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 28px;
  transition: transform .3s var(--ease), border-color .3s var(--ease), background .3s var(--ease);
  overflow: hidden;
}
.card::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--grad-soft);
  opacity: 0;
  transition: opacity .3s var(--ease);
  pointer-events: none;
}
.card:hover { transform: translateY(-5px); border-color: var(--line-2); }
.card:hover::before { opacity: 1; }
.card > * { position: relative; }
.card__icon {
  width: 46px; height: 46px;
  display: grid;
  place-items: center;
  border-radius: 12px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--brand);
  margin-bottom: 18px;
}
.card h3 { font-size: 1.18rem; font-weight: 700; margin-bottom: 10px; letter-spacing: -0.01em; }
.card p { color: var(--muted); font-size: 0.96rem; }
.card__link {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 24px; /* WCAG 2.2 SC 2.5.8: line-height alone lands at ~23.5px */
  margin-top: 16px;
  font-weight: 600; font-size: 0.92rem;
  color: var(--brand);
  transition: gap .2s var(--ease);
}
.card__link:hover { gap: 10px; }
.card--feature .card__icon { color: var(--brand); }
.card--wide { padding: 34px; }
.card--wide h3 { font-size: 1.35rem; }
.card--wide p { font-size: 1.02rem; }
.card--wide em { color: var(--text); font-style: normal; font-weight: 600; }

/* compact white logo chip for partner / institution cards.
   Flex, not grid: the chip has a definite height, so a flex item's
   max-height:100% resolves against it. In a grid the row is auto-sized, the
   percentage has nothing to resolve against, and tall logos spill out. */
.logo-chip {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  height: 110px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 18px 22px;
  margin-bottom: 18px;
  overflow: hidden;
}
.logo-chip img {
  max-height: 100%;
  max-width: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}

/* media card: image/video header + body (products, people, episodes) */
.card--media { padding: 0; display: flex; flex-direction: column; }
.card__media {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}
.card__media img,
.card__media video {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform .5s var(--ease);
}
.card--media:hover .card__media img { transform: scale(1.04); }
.card__media--contain img { object-fit: contain; padding: 24px; background: #fff; }
/* Taller box for portrait photography, so a standing/seated subject is not
   cropped to a letterbox by the default 4:3 media ratio. */
.card__media--portrait { aspect-ratio: 4 / 5; }

/* Headshots. The sources are square or slightly taller (0.87-1.0), so the
   default 4:3 landscape box made `cover` scale to width and slice the top and
   bottom off, cutting foreheads. A portrait box crops the sides instead, and
   the 22% offset keeps the face high in frame for any landscape source. */
.team .card__media { aspect-ratio: 4 / 5; }
.team .card__media img,
#advisors .card__media img { object-position: center 22%; }

/* ---- advisor avatars ----
   Round and small, for two reasons that happen to point the same way.

   The sources are wildly inconsistent - 110px to 1592px, square and portrait,
   different headroom in every one - and a circle at a fixed size absorbs that
   mismatch far better than a shared rectangle, which puts every difference in
   framing right next to its neighbour along a straight edge.

   And the old 4:5 box rendered about 290x363 at 4-up, which upscaled most of
   these files 2-3x; that upscaling was most of the "blurry". At 140px all but
   two sit at or above their native size, so the softness largely resolves
   without replacing a single asset. Width and height are both explicit, so the
   inherited 4:3 aspect-ratio is inert and does not need overriding. */
#advisors .card__media {
  width: 140px;
  height: 140px;
  margin: 30px auto 0;
  border-radius: 50%;
  /* replaces the base rule's border-bottom, which would draw a chord */
  border: 1px solid var(--line);
  background: var(--surface-2);
}
#advisors .card__body { text-align: center; padding: 18px 24px 26px; }
/* Some of these names take two lines and some take one ("Karen Shehade, MBA,
   MHP, PA-C" against "KC McCreery"), which left the LinkedIn link sitting at a
   different height in every card and made a row read as four unrelated boxes.
   Column layout plus margin-top:auto drops the link to the bottom of whichever
   card it is in, so the links line up across the row however the names break. */
#advisors .card__body { display: flex; flex-direction: column; flex: 1; }
#advisors .card__social { margin-top: auto; align-self: center; }
.card__body { padding: 26px; }
.card--media h3 { font-size: 1.3rem; }
.card__role {
  font-family: var(--mono);
  font-size: 0.82rem;
  color: var(--brand);
  margin: 4px 0 12px;
}
.card__list { list-style: none; display: flex; flex-direction: column; gap: 8px; margin: 0 0 16px; }
.card__list li { color: var(--muted); font-size: 0.9rem; padding-left: 18px; position: relative; }
.card__list li::before { content: "›"; position: absolute; left: 0; color: var(--brand); }
.card__social {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 24px; /* WCAG 2.2 SC 2.5.8 target size */
  color: var(--muted); font-size: 0.88rem; font-weight: 600;
  transition: color .2s var(--ease);
}
.card__social:hover { color: var(--brand); }

/* ============ SPLIT (text + visual) ============ */
/* hero variant: a left-aligned, full-width hero holding a split layout */
.hero__content--wide { max-width: var(--container); text-align: left; margin: 0 auto; }
.split__text .hero__title { font-size: clamp(2.1rem, 4.6vw, 3.4rem); }
.split__text .hero__sub { margin: 22px 0 0; max-width: none; }
.split__text .hero__actions { justify-content: flex-start; }
.split { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 56px; align-items: center; }
.split--reverse .split__text { order: 2; }
.split__text .section__title { font-size: clamp(1.7rem, 3.2vw, 2.5rem); }
.split__text .eyebrow { margin-bottom: 14px; }
.split__kicker { margin-top: 22px; color: var(--faint); font-size: 0.96rem; }
.split__visual img,
.split__visual video {
  width: 100%;
  border-radius: var(--radius);
  border: 1px solid var(--line);
}
.ticks { list-style: none; margin-top: 22px; display: flex; flex-direction: column; gap: 12px; }
.ticks li { position: relative; padding-left: 30px; color: var(--muted); }
/* WCAG 2.2 SC 2.5.8: a bare inline link in a tick row is only ~20px tall. */
.ticks li a { display: inline-flex; align-items: center; min-height: 24px; }
.ticks li::before {
  content: "";
  position: absolute;
  left: 0; top: 6px;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--grad-soft);
  border: 1px solid var(--brand);
}
.ticks li::after {
  content: "";
  position: absolute;
  left: 6px; top: 10px;
  width: 6px; height: 3px;
  border-left: 2px solid var(--brand);
  border-bottom: 2px solid var(--brand);
  transform: rotate(-45deg);
}

/* ============ PULLQUOTE ============ */
.pullquote {
  margin: 64px auto 0;
  max-width: 820px;
  font-size: clamp(1.5rem, 3vw, 2.1rem);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.02em;
  padding-left: 26px;
  border-left: 3px solid;
  border-image: var(--grad) 1;
}
.pullquote--center {
  text-align: center;
  border-left: none;
  border-image: none;
  padding-left: 0;
}
.pullquote cite {
  display: block;
  margin-top: 16px;
  font-size: 1.05rem;
  font-weight: 500;
  font-style: normal;
  color: var(--muted);
}

/* ============ STATS ============ */
.stats { padding: 80px 0; background: var(--bg-2); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.stats__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 28px; }
.stat { text-align: center; padding: 0 8px; }
.stat__num {
  font-size: clamp(2.4rem, 5vw, 3.6rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  background: var(--grad-ink);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  line-height: 1;
}
.stat__unit { font-size: 0.55em; }
/* Currency sign as a pseudo-element so it renders at the full figure size and
   inside the same clipped gradient. The counter script rewrites textContent,
   which would blow away a real child node but leaves ::before alone. */
.stat__num--currency::before { content: "$"; }
.stat__label { margin-top: 14px; color: var(--muted); font-size: 0.92rem; }

/* ============ TAGS ============ */
.tag {
  font-family: var(--mono);
  font-size: 0.72rem;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  color: var(--muted);
}
.tag--brand { color: var(--brand); border-color: rgba(var(--brand-fill-rgb),.4); }
.tag--deep { color: var(--brand-deep); border-color: rgba(var(--brand-deep-rgb),.5); }
.tag--soft { color: var(--brand); border-color: rgba(var(--brand-soft-rgb),.6); }

/* ============ PROSE (text-heavy pages) ============ */
/* Body copy here sat on --muted, which clears AA on the off-white page but only
   just, and at 1.05rem on a tinted background it read as something to skim
   rather than something to read. --text is the same colour the headings in this
   block already use. Only about.html's mission block carries .prose, so this is
   not a site-wide restyle. */
.prose { max-width: 720px; margin: 0 auto; color: var(--text); }
/* Opening statement: the size and weight of a lead, still inside the prose
   flow so the paragraphs below continue the thought. */
.prose p.prose__lead {
  font-size: clamp(1.3rem, 2.2vw, 1.65rem);
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: -0.02em;
  margin-bottom: 22px;
}
.prose h2 { color: var(--text); font-size: 1.6rem; font-weight: 800; letter-spacing: -0.02em; margin: 38px 0 14px; }
.prose h3 { color: var(--text); font-size: 1.25rem; font-weight: 700; margin: 28px 0 10px; }
.prose p { margin-bottom: 16px; font-size: 1.05rem; }
.prose a { color: var(--brand); text-decoration: underline; text-underline-offset: 2px; }
.prose ul { margin: 0 0 16px 22px; }
.prose li { margin-bottom: 8px; }

/* inline accent links */
.section__lead a, .card p a, .prose a, .program__role a {
  text-underline-offset: 2px;
  transition: color .2s var(--ease);
}

/* ============ FORMS ============ */
.form { max-width: 640px; margin: 0 auto; display: flex; flex-direction: column; gap: 18px; }
.field { display: flex; flex-direction: column; gap: 8px; }
.field label { font-size: 0.85rem; font-weight: 600; color: var(--muted); font-family: var(--mono); letter-spacing: 0.04em; }
.field input,
.field textarea,
.field select {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  padding: 13px 16px;
  color: var(--text);
  font-family: var(--font);
  font-size: 0.98rem;
  transition: border-color .2s var(--ease), background .2s var(--ease);
}
/* The border shift is the resting/typing affordance. Keyboard focus keeps the
   global :focus-visible outline on top of it: a 1px border colour change alone
   is too weak to serve as the focus indicator (WCAG 2.4.7). */
.field input:focus,
.field textarea:focus,
.field select:focus { border-color: var(--brand); background: var(--surface-2); }
.field input:focus:not(:focus-visible),
.field textarea:focus:not(:focus-visible),
.field select:focus:not(:focus-visible) { outline: none; }
.field textarea { min-height: 140px; resize: vertical; }

/* ============ CTA ============ */
.section--cta { padding: 120px 0; }
.cta {
  position: relative;
  text-align: center;
  max-width: 860px;
  margin: 0 auto;
  padding: 70px 40px;
  border-radius: 28px;
  border: 1px solid var(--line-2);
  background: linear-gradient(180deg, var(--bg-3), var(--bg-2));
  overflow: hidden;
}
.cta__aurora {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(40% 60% at 20% 0%, rgba(var(--brand-fill-rgb),.22), transparent 60%),
    radial-gradient(40% 60% at 80% 10%, rgba(var(--brand-deep-rgb),.26), transparent 60%),
    radial-gradient(50% 60% at 50% 110%, rgba(var(--brand-soft-rgb),.16), transparent 60%);
  animation: drift 16s ease-in-out infinite alternate;
}
.cta > * { position: relative; }
.cta__title {
  font-size: clamp(1.9rem, 4vw, 3rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.1;
  margin-top: 8px;
}
.cta__lead { color: var(--muted); max-width: 600px; margin: 20px auto 0; font-size: 1.05rem; }
.cta__actions { margin-top: 34px; display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }

/* ============ FOOTER ============ */
.footer { border-top: 1px solid var(--line); padding: 64px 0 32px; background: var(--bg-2); }
.footer__inner { display: grid; grid-template-columns: 1.3fr 2fr; gap: 48px; }
.footer__tag { margin-top: 18px; color: var(--faint); font-size: 0.92rem; max-width: 340px; }
.footer__cols { display: grid; grid-template-columns: repeat(2, 1fr); gap: 28px; }
.footer__cols h2 { font-size: 0.82rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint); margin-bottom: 14px; font-family: var(--mono); }
.footer__cols a { display: flex; align-items: center; gap: 7px; color: var(--muted); font-size: 0.92rem; padding: 5px 0; transition: color .2s var(--ease); }
.footer__cols a:hover { color: var(--brand); }
.footer__bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 48px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
  color: var(--faint);
  font-size: 0.85rem;
  flex-wrap: wrap;
  gap: 10px;
}
.footer__bar a {
  color: inherit; text-decoration: underline; text-underline-offset: 2px;
  display: inline-flex; align-items: center; min-height: 24px; /* WCAG 2.2 SC 2.5.8 */
  transition: color .2s var(--ease);
}
.footer__bar a:hover { color: var(--brand); }

/* ============ SCROLL REVEAL ============ */
/* .reveal starts hidden and is normally cleared by scripts/atos.js. On its own
   that would make the script load-bearing: if it 404s, is blocked, or throws
   before the reveal block runs, every .reveal section would stay at opacity:0
   and the page would read as blank rather than merely unanimated.
   The failsafe below is the backstop. Any .reveal still hidden after 3s is
   shown by a pure-CSS animation, so a script failure degrades to a static page.
   atos.js sets .js-reveal on <html> once the observer is actually wired, which
   cancels the failsafe and leaves the real scroll effect intact. Ordering
   matters: the class is set after the observer is attached, never before, or a
   later throw would cancel the backstop without having replaced it. */
.reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
  animation: reveal-failsafe 0s linear 3s forwards;
}
.js-reveal .reveal { animation: none; }
.reveal.is-visible { opacity: 1; transform: none; animation: none; }
@keyframes reveal-failsafe { to { opacity: 1; transform: none; } }
/* stagger children inside grids */
.cards .reveal:nth-child(2), .team .reveal:nth-child(2) { transition-delay: .08s; }
.cards .reveal:nth-child(3), .team .reveal:nth-child(3) { transition-delay: .16s; }
.cards .reveal:nth-child(4), .team .reveal:nth-child(4) { transition-delay: .24s; }
.cards .reveal:nth-child(5) { transition-delay: .16s; }
.cards .reveal:nth-child(6) { transition-delay: .24s; }

/* ============ BRAND HERO ============
   The homepage hero: a navy-to-royal gradient with white type and a yellow
   rotating word. The gradient stops at the royal blue rather than running on
   to the bright #67B6FF, so every stop stays at or above 5.3:1 under white
   copy, and the large yellow word clears AA large text (4.0:1) at the
   lightest end. */
.hero--brand {
  background: linear-gradient(135deg, #07214A 0%, #0F4499 50%, #1A6ACC 100%);
  color: #fff;
}
.hero--brand .hero__title,
.hero--brand .hero__sub,
.hero--brand .hero__sub strong { color: #fff; }
/* No opacity dimming here. At .95 the sub-headline lost ~0.3:1 of contrast for
   no visual gain, which was enough to drop it under 4.5:1 over the brighter
   hero photos. Full white, so it tracks the h1. */
.hero--brand .grad-text {
  background: none;
  -webkit-text-fill-color: #FDE047;
  color: #FDE047;
}
/* On the blue hero the shared .btn--solid fill (--brand-deep) is the same blue
   as the hero itself, so the button loses its boundary entirely. Invert it:
   white plate, navy label. 15.8:1 for the label, and 5.3:1 for the plate
   against the lightest stop of the hero, so both the text and the control's
   edge clear AA. */
.hero--brand .btn--solid { background: #fff; color: #07214A; box-shadow: 0 4px 14px -6px rgba(0,0,0,.4); }
.hero--brand .btn--solid:hover { background: #E8F4FF; color: #07214A; }
.hero--brand .btn--ghost { color: #fff; border-color: rgba(255,255,255,.55); background: rgba(255,255,255,.10); }
.hero--brand .btn--ghost:hover { background: rgba(255,255,255,.2); border-color: #fff; }
.hero--brand .hero__scroll span { border-color: #fff; }
/* the shared hero overlay is a light wash; on the blue hero it must be blue.
   Photo opacity for the slideshow is set on .hero__slides; this covers the
   non-slideshow case (a plain <img> inside a .hero--brand).
   Both themes are spelled out because the generic dark rules above are (0,3,0)
   and would otherwise outrank a bare `.hero--brand` (0,2,0) selector and drop a
   near-black wash onto the blue hero. */
.hero--brand .hero__media video,
.hero--brand .hero__media img { opacity: .85; }
.hero--brand .hero__media::after,
:root[data-theme="dark"] .hero--brand .hero__media::after {
  background: linear-gradient(135deg, rgba(7,33,74,.22), rgba(26,106,204,.14));
}
/* Deeper than the hero's own blue. A scrim can never push the composite below
   its own luminance, so tinting with the hero's lightest stop (#1A6ACC, 5.3:1
   against white) would cap the headline at that ratio no matter how opaque the
   scrim got. #061A3A leaves headroom. */
.hero--brand .hero__media::before,
:root[data-theme="dark"] .hero--brand .hero__media::before {
  background: radial-gradient(ellipse 68% 70% at 50% 50%,
              rgba(6,26,58,.72) 0%,
              rgba(6,26,58,.72) 45%,
              rgba(6,26,58,0) 100%);
}

/* subheading inside a section, sitting under the section title.
   Unused on this site so far; kept because the ported system defines it. */
.section__subhead {
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  text-align: center;
  margin-bottom: 40px;
}
/* team names sit at h4 under the "Leadership Team" h3 */
.card--media h4 { font-size: 1.3rem; font-weight: 700; margin-bottom: 10px; letter-spacing: -0.01em; }


/* ============ VISION CARD ============
   Blue panel: gradient fill, white type. Runs royal to navy, so the lightest
   stop is the same 5.3:1 the hero tops out at. */
.vision-card {
  background: linear-gradient(135deg, #1A6ACC 0%, #07214A 100%);
  color: #fff;
  border-radius: var(--radius);
  padding: 34px;
}
.vision-card h3 { font-size: 1.45rem; margin-bottom: 14px; }
.vision-card p { color: rgba(255,255,255,.92); font-size: 1.02rem; margin-bottom: 22px; }
.vision-card .ticks li { color: #fff; }
.vision-card .ticks li::before { color: #FDE047; }

/* ============ PARTNER MARKS ============
   Partner logos sit directly on the page with no tile behind them, following
   the RAMMP banner. Every mark is black-on-transparent art (.marks--mono), so
   the set reads as one family and simply inverts to white in the dark theme.
   The source logos were ink on an opaque white canvas, which is why they used
   to need a white plate; see the conversion note in the repo history. */
.marks {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 48px 40px;
  align-items: center;
  justify-items: center;
  list-style: none;
  border-top: 1px solid var(--line);
  padding-top: 46px;
}
.mark {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 88px;
  opacity: .85;
  transition: opacity .2s var(--ease), transform .2s var(--ease);
}
/* Every mark file is composited onto the same 3:1 canvas, scaled so its
   geometric mean size matches, so filling the box height renders the whole set
   at one size with the logos optically balanced inside it. */
.mark img { height: 100%; width: 100%; object-fit: contain; }
a.mark:hover { opacity: 1; transform: translateY(-2px); }

/* The mark is the whole identity inside a partner card: the name beside it was
   redundant, so it is now screen-reader only and the logo carries the card. */
.mark--card {
  width: 190px;
  height: 68px;
  justify-content: flex-start;
  margin-bottom: 14px;
}
.card:hover .mark--card { opacity: 1; }

/* lead-institution row: a couple of larger marks, left aligned, no rule above */
/* Lead-institution row. Flex rather than the grid the other mark lists use, so
   the two marks sit on one baseline instead of in fixed columns. A wordmark and
   a round seal never look the same size at equal height, so the seal is given a
   little extra so the pair reads as one weight. */
.marks--lead {
  border-top: 0;
  padding-top: 0;
  margin: 20px 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 24px 64px;
}
/* Size this against the INK, not the box. Every mono mark is drawn on a shared
   600x200 sheet with generous transparent margins, so the dense logo rows sit
   at a consistent optical size. That means `contain` fits the SHEET to the box
   and the visible logo lands far smaller than the box height implies: Pitt's
   ink is 38% x 50% of its sheet, so the old 62px box drew the wordmark at
   70x31 - the reason this row read as tiny despite the box being a reasonable
   size. 96px puts it near 110x50, which is what a lead-institution callout
   wants. Measure the alpha bounding box before changing this; the sheet
   dimensions tell you nothing about how big the logo looks. */
.marks--lead .mark {
  width: auto;
  height: 96px;
  justify-content: center;
  opacity: 1;
}
/* Box height alone cannot fix this. The sheet is 3:1, so a taller box is also a
   wider one, and on a phone the container caps the width long before the ink
   gets big - 38% of 279px is as wide as Pitt's wordmark can ever draw. So scale
   the ink into the margin that is already empty instead. Factors are derived
   from each file's alpha bounding box:
     pitt.png  ink 225x100 in 600x200 -> fills 50% of the height -> x1.8
     herl.png  ink 182x124 in 600x200 -> fills 62%               -> x1.45
   both landing near 90% of the box. transform does not affect layout, so the
   boxes, wrapping and gaps are all unchanged.
   Keyed off the filename deliberately: swap an asset and the rule simply stops
   matching, which shows up as a small logo rather than a clipped one. Re-derive
   with the alpha-bbox scan if a sheet is ever replaced - the 600x200 sheet size
   tells you nothing about how big the logo actually looks. */
.marks--lead img[src$="pitt.png"] { transform: scale(1.8); }
.marks--lead img[src$="herl.png"] { transform: scale(1.45); }
/* the lead card is a centred block: eyebrow over the two marks */
.card--lead { text-align: center; }
.card--lead .eyebrow { margin-bottom: 4px; }
/* The ATDev wordmark on the "Built by" card on the homepage. Deliberately
   outside the .mark--card / .marks--mono pipeline: those invert to white under
   the dark theme, which is right for black line art and wrong for a colour
   logo. */
.card__mark { display: block; height: 46px; width: auto; margin: 18px auto 16px; }
.card--lead .card__mark + p { max-width: 62ch; margin: 0 auto; }

/* black line art reads as white once the page goes dark */
:root[data-theme="dark"] .marks--mono .mark img,
:root[data-theme="dark"] .mark--card img { filter: invert(1); }
:root[data-theme="dark"] .marks--mono .mark,
:root[data-theme="dark"] .mark--card { opacity: .9; }


/* ============ RESPONSIVE ============ */
@media (max-width: 960px) {
  .cards--3, .cards--feature, .cards--4 { grid-template-columns: repeat(2, 1fr); }
  /* 3-up rather than the 2-up above. A content card needs the width for its
     paragraph; an advisor card is a 140px circle and three short lines, and at
     2-up here it is about 400px wide with most of that empty. Full ladder is
     4 / 3 / 2 / rows across the four breakpoints. */
  #advisors .cards--4 { grid-template-columns: repeat(3, 1fr); }
  .split { grid-template-columns: 1fr; gap: 36px; }
  .split--reverse .split__text { order: 0; }
  .footer__inner { grid-template-columns: 1fr; gap: 32px; }
  .stats__grid { grid-template-columns: repeat(2, 1fr); gap: 36px 20px; }
}

@media (max-width: 760px) {
  .nav__menu { display: none; }
  .nav__toggle { display: flex; }
  .nav.is-open .nav__menu {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 18px;
    position: absolute;
    top: 100%; left: 0; right: 0;
    background: var(--nav-bg-solid);
    backdrop-filter: blur(16px);
    border-bottom: 1px solid var(--line);
    padding: 22px 24px 26px;
  }
  .nav.is-open .nav__links {
    flex-direction: column;
    gap: 16px;
  }
  .nav.is-open .nav__cta {
    flex-direction: column;
    align-items: stretch;
  }
  .nav.is-open .nav__cta .btn,
  .nav.is-open .nav__cta .theme-toggle { width: 100%; justify-content: center; }
  .nav.is-open .nav__links a::after { display: none; }
  .section { padding: 80px 0; }
  .cards--3, .cards--feature, .cards--2, .cards--4 { grid-template-columns: 1fr; }
  /* Advisors opt out of the 1-up rule above. That rule is right for content
     cards, which carry a paragraph worth reading at full width; an advisor card
     is a 140px circle and three short lines, so full width leaves it mostly
     empty and turns 13 people into a very long scroll. Staying 2-up keeps the
     page about half as tall and the avatars comfortably sized. */
  #advisors .cards--4 { grid-template-columns: repeat(2, 1fr); gap: 16px; }
  #advisors .card__media { width: 116px; height: 116px; margin-top: 24px; }
  #advisors .card__body { padding: 14px 16px 20px; }
  #advisors .card--media h3 { font-size: 1.05rem; }
  #advisors .card__role { font-size: 0.74rem; }
  #advisors .card__body p { font-size: 0.88rem; }
  /* Leadership stays a grid on mobile rather than dropping to the single
     column the generic .cards--4 rule gives. At 1-up each 4:5 headshot filled
     the full column - roughly 342x428, very nearly a whole phone screen per
     person, four in a row before any credentials. Two columns put the four of
     them on two screens instead of four, and at ~152px the photo is still a
     recognisable portrait rather than a thumbnail.
     .team.cards--4 is (0,2,0) so it outranks the 1-up rule regardless of
     source order. The media goes back to filling its card: with a narrow card
     there is nothing to cap, and a centred, inset photo only reintroduced the
     stub-border problem. */
  .team.cards--4 { grid-template-columns: repeat(2, 1fr); gap: 16px; }
  .team .card__body { padding: 14px 14px 18px; }
  .team .card--media h4 { font-size: 1.02rem; line-height: 1.25; }
  .team .card__role { font-size: 0.74rem; margin: 3px 0 8px; }
  .team .card__list { gap: 6px; margin-bottom: 12px; }
  .team .card__list li { font-size: 0.78rem; padding-left: 13px; }
  /* RAMMP partner tiles: 2-up, not the 1-up the generic .cards rule gives here.
     These cards are logo-led - the partner name is screen-reader only and the
     mark IS the identity - so a full-width card stranded a small logo in a sea
     of empty space. Two columns halve the scroll and, more to the point, give
     the mark a card it is in proportion to. */
  .cards--partners { grid-template-columns: repeat(2, 1fr); gap: 14px; }
  .cards--partners .card { padding: 18px 16px; }
  /* The mobile `.mark { height: 42px }` below is meant for the dense logo rows
     and was shrinking these card marks to 42px too - that is the "too small".
     (0,2,0) outranks it regardless of source order. Centred rather than
     flush-left, which in a narrow card reads as misplaced instead of
     deliberate. */
  .cards--partners .mark--card {
    width: 100%;
    height: 56px;
    justify-content: center;
    margin-bottom: 14px;
  }
  .cards--partners .card p { font-size: 0.84rem; line-height: 1.5; }
  /* At 96px each lead mark is 288px wide (the 3:1 sheet), which only just
     clears the card's content box on a narrow phone. 84px keeps a margin and
     still reads far bigger than the 62px it replaced. The sheet margins supply
     plenty of optical separation once they wrap, so the row gap comes down. */
  .marks--lead .mark { height: 84px; }
  .marks--lead { gap: 4px 28px; }
  .footer__bar { flex-direction: column; align-items: flex-start; }
  .pullquote { font-size: 1.4rem; }
  .marks { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 32px 22px; }
  .mark { height: 42px; }
}

/* ---- advisors on phones: horizontal rows ----
   Below this width a 2-up grid leaves each name about 120px of measure, and
   these are long credentialed names - "Karen Shehade, MBA, MHP, PA-C" breaks
   over four lines, every card ends up a different height, and the grid ragged
   badly. Turning the card on its side gives the text the full column instead,
   and 13 people read as a directory rather than a stack of near-empty boxes.
   Kept as rows rather than a smaller 2-up because shrinking the avatar is the
   wrong trade: the photos are the part that identifies someone. */
@media (max-width: 520px) {
  #advisors .cards--4 { grid-template-columns: 1fr; gap: 12px; }
  #advisors .card--media {
    flex-direction: row;
    align-items: center;
    gap: 16px;
    padding: 14px 16px;
  }
  #advisors .card__media {
    width: 80px;
    height: 80px;
    margin: 0;
    /* flex-basis with no shrink. Left to the default the circle would give up
       width against a long name while its height stayed pinned, quietly
       turning every avatar into an ellipse. */
    flex: 0 0 80px;
  }
  #advisors .card__body {
    text-align: left;
    padding: 0;
    /* min-width:0 is what actually lets the name wrap: a flex item's default
       min-width is auto, so without it a long unbroken name pushes the row
       wider than its column instead of breaking. */
    flex: 1;
    min-width: 0;
  }
  #advisors .card--media h3 { font-size: 1rem; line-height: 1.25; }
  #advisors .card__role { margin: 3px 0 5px; }
  #advisors .card__body p { font-size: 0.85rem; }
  /* Rows are only as tall as their own content, so there is no shared baseline
     to align to here - reset the bottom-push and sit the link under the text. */
  #advisors .card__social { margin-top: 6px; align-self: flex-start; }
}

@media (max-width: 460px) {
  .stats__grid { grid-template-columns: 1fr; }
  .hero__actions .btn, .cta__actions .btn { width: 100%; justify-content: center; }
}

/* ============ REDUCED MOTION ============ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1; transform: none; }
  .hero__aurora, .cta__aurora { animation: none; }
  /* The JS never starts the rotation under reduced motion, but slide 1 ships in
     the markup and would still drift on the CSS animation alone. Kill it here or
     the one guarantee the hero makes is not actually kept. */
  .hero__slide { animation: none; transform: none; }
}
