:root {
  /* Dark system. Accents sampled from the reference photo; every pair below
     is measured against the page background for WCAG AA. */
  --bg: #0E0E0D;          /* near-black page, softer than pure black for reading */
  --surface: #262624;     /* raised panels and cards: lifted clearly off the page */
  --ink: #DCEA8C;         /* body prose: lime, softened just enough to read at length */
  --muted: #A3B77E;       /* secondary text, sage-lime */
  --accent: #ECFF1A;      /* lime, primary accent, full saturation */
  --accent-2: #00C2C1;    /* teal, links and interactive states, 8.7:1 */
  --accent-3: #E93E43;    /* coral, retired from the pages (kept for reference) */
  --on-accent: #0E0E0D;   /* text placed on an accent fill */
  --line: #3A3A35;        /* hairlines: header, footer, dividers */
  --line-strong: #6B6B62;  /* card outlines: 3.6:1 on the page, clears the 3:1 WCAG
                              minimum for non-text boundaries so cards read as cards
                              without needing hover (which phones do not have) */
  --step-0: clamp(1rem, 0.95rem + 0.3vw, 1.15rem);
  --step-1: clamp(1.3rem, 1.1rem + 1vw, 1.9rem);
  --step-2: clamp(1.9rem, 1.4rem + 2.2vw, 3.2rem);
  --step-3: clamp(2.6rem, 1.6rem + 4.5vw, 5rem);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: "Archivo", system-ui, sans-serif;
  font-size: var(--step-0);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}
/* The teal 'electricity' field sits fixed behind the whole site so it fills
   every open area (header, footer, page margins, the gaps between panels). A
   light scrim takes the harsh edge off. Content never sits directly on it:
   text lives on the opaque .panel surfaces below, which preserves the AA
   contrast the palette was built for. */
body::before {
  content: ""; position: fixed; inset: 0; z-index: -2;
  background: url("/assets/img/site-bg.jpg") center / cover no-repeat, var(--bg);
}
body::after {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  /* scrim over the electricity field. 0.58 shows it at ~42% intensity, about
     30% subtler than the original 0.4 (60%), per feedback it read as too much. */
  background: rgba(14, 14, 13, 0.58);
}
main { max-width: 1100px; margin: 0 auto; padding: 4rem 1.5rem 6rem; }

/* Panels: the opaque dark cards the content floats on. Solid --bg keeps every
   text/background pair exactly as measured, while the electricity glows in the
   margins and the gaps between them. A hairline teal-tinted edge and soft
   shadow tie them to the field. */
.panel {
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: 16px;
  box-shadow: 0 0 0 1px rgba(0, 194, 193, 0.12), 0 24px 50px -24px rgba(0, 0, 0, 0.9);
}
/* content pages: the main column becomes one panel floating on the field */
body:not(.home) main {
  padding: clamp(1.75rem, 4vw, 3.25rem);
  margin-top: 2rem; margin-bottom: 3rem;
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: 16px;
  box-shadow: 0 0 0 1px rgba(0, 194, 193, 0.12), 0 24px 50px -24px rgba(0, 0, 0, 0.9);
}
/* header and footer are readable chrome: solid dark so their small text stays
   AA, with the field showing in the page margins beside them */
.site-header, .site-footer { background: var(--bg); }
/* home: each block below the hero is its own panel, the field glowing in the
   generous gaps between them */
body.home .proof,
body.home .pillars,
body.home .home-cta {
  padding: clamp(1.75rem, 3.5vw, 2.75rem);
  border-radius: 16px;
  background: var(--bg);
  border: 1px solid var(--line-strong);
  box-shadow: 0 0 0 1px rgba(0, 194, 193, 0.12), 0 24px 50px -24px rgba(0, 0, 0, 0.9);
}
h1, h2, h3 { line-height: 1.05; letter-spacing: -0.02em; margin: 0 0 1.2rem; }
h1 { font-size: var(--step-3); font-weight: 900; text-transform: uppercase; }
/* page headings (About, Projects, Experience, AI Demo, Outside of Work, Contact)
   in teal. The home hero name is nested deeper, so it keeps its own treatment. */
main > h1 { color: var(--accent-2); }
/* cool two-tone headings: h1 and h2 teal (size separates them), h3 lime. Coral
   (--accent-3) is retired from the pages. */
h2 { font-size: var(--step-2); font-weight: 800; margin-top: 3rem; color: var(--accent-2); }
h3 { font-size: var(--step-1); font-weight: 700; margin-top: 2rem; color: var(--accent); }
p { max-width: 68ch; }
a { color: var(--ink); text-decoration-color: var(--accent-2); text-decoration-thickness: 2px; text-underline-offset: 3px; }
a:hover { color: var(--accent-2); }
img { max-width: 100%; height: auto; display: block; }

/* Visible keyboard focus. Deliberately designed rather than left to the browser. */
:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}
/* Skip link: hidden until focused, then drops into the top-left corner */
.skip-link {
  position: absolute; top: -120%; left: 1rem; z-index: 200;
  background: var(--accent); color: var(--on-accent);
  padding: 0.7rem 1.2rem; font-weight: 800; text-decoration: none;
  border-radius: 0 0 6px 6px;
}
.skip-link:focus { top: 0; }

.site-header {
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  max-width: 1100px; margin: 0 auto; padding: 1.4rem 1.5rem;
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
}
.brand { font-weight: 800; text-decoration: none; letter-spacing: -0.01em; color: var(--accent-2); }
.site-header nav { display: flex; gap: 1.4rem; flex-wrap: wrap; }
.site-header nav a {
  text-decoration: none; font-size: 0.9rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.08em;
  position: relative;
}
/* current page: lime label plus the underline motif used across the site.
   Uses ::before so it never clashes with the AI Demo sparkle on ::after. */
.site-header nav a[aria-current="page"] { color: var(--accent); }
.site-header nav a[aria-current="page"]::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: -0.45rem;
  height: 2px; background: var(--accent);
}
/* subtle sparkle on the AI Demo menu item */
.nav-sparkle::after {
  content: "\2726";
  color: var(--accent);
  display: inline-block;
  margin-left: 0.35em;
  font-size: 0.85em;
  animation: sparkle 2.6s ease-in-out infinite;
}
@keyframes sparkle {
  0%, 100% { opacity: 0.35; transform: scale(0.75) rotate(0deg); }
  50% { opacity: 1; transform: scale(1.15) rotate(25deg); }
}
.site-footer {
  border-top: 1px solid var(--line);
  max-width: 1100px; margin: 0 auto; padding: 2rem 1.5rem 3rem;
  color: var(--muted); font-size: 0.9rem;
}
.lede { font-size: var(--step-1); font-weight: 600; line-height: 1.4; max-width: 30ch; }
.muted { color: var(--muted); }
.accent { color: var(--accent); }
/* Ask AI sits in its own panel so it reads as a deliberate feature, not a footer band */
.ask-ai { background: transparent; padding: 0 1.5rem 4rem; }
.ask-ai-inner {
  max-width: 1100px; margin: 0 auto; padding: 2.6rem 2rem 2.8rem;
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: 14px;
}
.ask-ai h2 { margin-top: 0; }
.ask-ai-buttons { display: flex; gap: 0.8rem; flex-wrap: wrap; margin-top: 1.5rem; }
.ask-ai-buttons a, .ask-ai-buttons button {
  font: inherit; font-weight: 700; cursor: pointer;
  padding: 0.75rem 1.6rem; border-radius: 999px;
  border: 2px solid var(--ink); background: transparent; color: var(--ink);
  text-decoration: none; transition: background 0.15s, color 0.15s;
  display: inline-flex; align-items: center; gap: 0.5em;
}
.ask-ai-buttons .icon { width: 1.2em; height: 1.2em; }
.ask-ai-buttons a:hover, .ask-ai-buttons button:hover { background: var(--ink); color: var(--bg); }

.kicker {
  text-transform: uppercase; letter-spacing: 0.18em; font-size: 0.8rem;
  font-weight: 700; color: var(--accent); margin: 0 0 1rem;
  white-space: nowrap;
}
/* on narrow screens let the kicker wrap naturally at a readable size */
@media (max-width: 640px) {
  .kicker { white-space: normal; text-wrap: balance; letter-spacing: 0.1em; font-size: 0.72rem; }
}
/* the hero shows the same full-strength electricity field as the rest of the
   site (it blends into the fixed body background rather than being a separate
   banner). Local scrims sit only behind the name/kicker at the top and the
   tagline at the bottom, so those stay readable while the field blazes around
   the laptop. Measured against the brightest filaments: coral name clears the
   3:1 large-text minimum, lime/teal clear it comfortably. */
.hero {
  position: relative; isolation: isolate;
  padding: clamp(1.5rem, 4vw, 3rem) clamp(1.25rem, 4vw, 3rem);
}
.hero::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(135% 62% at 50% 24%, rgba(14, 14, 13, 0.84) 0%, rgba(14, 14, 13, 0.42) 46%, transparent 74%),
    linear-gradient(0deg, rgba(14, 14, 13, 0.82) 0%, rgba(14, 14, 13, 0.3) 16%, transparent 30%);
}
.hero h1 {
  font-size: clamp(2.8rem, 10vw, 7.3rem); margin: 0 0 2rem;
  position: relative; z-index: 2;
}
/* SCOTT and MARSHALL both teal for a cooler, single-tone hero name, with teal
   underlines to match (--rule below). */
.h1-right > span { color: var(--accent-2); }
.h1-outline {
  /* SCOTT stays outlined for good: a teal stroke with an unfilled interior, as a
     deliberate counterpoint to the solid teal MARSHALL. The interior takes the
     page colour so it reads as a clean hollow letterform against the hero. */
  color: var(--bg);
  -webkit-text-stroke: 0.022em var(--accent-2);
}
.hero-links { display: flex; gap: 1.6rem; flex-wrap: wrap; margin-top: 2rem; font-weight: 700; }
/* the laptop clip is the hero centrepiece; its own near-black backdrop blends
   into the scrim so it reads as sitting inside the network, and a faint teal
   ring lifts it off the page. Screen stays blank now; Scott's portrait is added
   to it later. */
.hero-media {
  position: relative;
  width: min(100%, 720px); margin: clamp(1.5rem, 3vw, 2.25rem) auto 0;
  border-radius: 12px; overflow: hidden;
  box-shadow: 0 0 0 1px rgba(0, 194, 193, 0.28), 0 26px 55px -22px rgba(0, 0, 0, 0.85);
}
.hero-laptop {
  display: block; width: 100%; height: auto; aspect-ratio: 16 / 9;
  object-fit: cover; background: var(--bg);
}
/* Scott's portrait sits on the laptop screen. Position measured against the
   clip's final (face-on) frame so it lands exactly on the glowing panel. It
   stays hidden while the lid opens, then focuses in once the video ends (wired
   in main.js), so it resolves onto the screen rather than popping in. */
.hero-screen {
  position: absolute; left: 26.8%; top: 18%; width: 47.4%; height: 51.5%;
  overflow: hidden;
  opacity: 0; filter: blur(14px) brightness(1.7); transform: scale(1.04);
  transition: opacity 2s ease, filter 2s ease, transform 2s ease;
}
.hero-screen img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hero-screen.is-on { opacity: 1; filter: blur(0) brightness(1); transform: scale(1); }
@media (prefers-reduced-motion: reduce) {
  .hero-screen { transition: none; }
}
.h1-left > span, .h1-right > span {
  position: relative; display: inline-block;
  --rule: var(--accent-2);   /* teal underline: fully single-tone cool name */
}
/* the trail is left behind the racing head, with a glow that settles */
.h1-left > span::after, .h1-right > span::after {
  content: ""; position: absolute; bottom: -0.04em; height: 0.06em;
  background: var(--rule);
  box-shadow: 0 0 10px 1px var(--rule);
  animation: draw-underline 0.9s ease-in-out 2.6s both,
             trail-glow 1.1s ease-out 3.5s both;
}
.h1-left > span::after { left: 0; width: 100%; transform-origin: left; }
.h1-right > span::after { right: 0; width: 100%; transform-origin: right; }
/* the head: a bright comet of light that races along the trail and bursts at the photo */
.h1-left > span::before, .h1-right > span::before {
  content: ""; position: absolute; bottom: -0.07em;
  width: 0.9em; height: 0.11em; border-radius: 999px;
  background: #fff;
  box-shadow: 0 0 8px 2px var(--rule), 0 0 20px 5px var(--rule);
  opacity: 0; pointer-events: none;
}
.h1-left > span::before { left: 0; animation: comet-left 0.95s ease-in-out 2.6s both; }
.h1-right > span::before { right: 0; animation: comet-right 0.95s ease-in-out 2.6s both; }
@keyframes draw-underline {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}
@keyframes trail-glow {
  from { box-shadow: 0 0 14px 2px var(--rule); }
  to { box-shadow: 0 0 0 0 transparent; }
}
@keyframes comet-left {
  0% { left: 0; opacity: 0; transform: scale(0.5); }
  12% { opacity: 1; }
  82% { left: calc(100% - 0.9em); opacity: 1; transform: scale(1); }
  100% { left: calc(100% - 0.45em); opacity: 0; transform: scale(2.4); }
}
@keyframes comet-right {
  0% { right: 0; opacity: 0; transform: scale(0.5); }
  12% { opacity: 1; }
  82% { right: calc(100% - 0.9em); opacity: 1; transform: scale(1); }
  100% { right: calc(100% - 0.45em); opacity: 0; transform: scale(2.4); }
}
/* Mobile: pull the whole hero up so the full laptop clears the first screen on
   load. The desktop build trims main's top padding, but mobile kept 4rem, which
   left a big dead gap under the (tall, wrapped) nav. Trim that and the stacked
   margins so kicker, name and the laptop window sit higher. */
@media (max-width: 800px) {
  body.home main { padding-top: 1.25rem; }
  .site-header { padding-top: 1rem; padding-bottom: 1rem; }
  .hero { padding-top: 0.5rem; }
  .hero .kicker { margin-bottom: 0.6rem; }
  .hero h1 { margin-bottom: 0.9rem; }
  .hero-media { margin-top: 0.9rem; }
}
@media (min-width: 801px) {
  body.home main { padding-top: 1rem; }
  /* the home page uses more screen width so SCOTT MARSHALL can run large */
  body.home .site-header,
  body.home main,
  body.home .ask-ai-inner,
  body.home .site-footer { max-width: 1280px; }
  /* the name sits centred above the laptop, the whole hero reads as one banner.
     the hero fills the first screen and centres its content so the kicker, name,
     full laptop clip and tagline are all visible on load without scrolling */
  .hero {
    text-align: center;
    display: flex; flex-direction: column; justify-content: center;
    min-height: calc(100svh - 84px);
    padding-top: 1.25rem; padding-bottom: 1.25rem;
  }
  .hero .kicker { margin-bottom: clamp(0.6rem, 1.6vh, 1.25rem); }
  .hero-grid { display: flex; flex-direction: column; align-items: center; }
  .hero-name {
    display: flex; justify-content: center; align-items: baseline;
    flex-wrap: wrap; gap: clamp(1rem, 3vw, 2.5rem); margin: 0;
  }
  .h1-word { position: relative; z-index: 2; }
  .h1-word > span { font-size: clamp(2.8rem, 6vw, 5rem); line-height: 1; letter-spacing: -0.03em; }
  /* size the clip by viewport height so it always fits; width follows the 16:9
     ratio and never exceeds 760px (height 420 => 747 wide) */
  .hero-media {
    width: auto; height: min(40vh, 400px); aspect-ratio: 16 / 9;
    margin: clamp(0.8rem, 2vh, 1.6rem) auto 0;
  }
  .hero-text { margin-top: clamp(0.75rem, 1.6vh, 1.4rem); }
  .hero-text .hero-links { justify-content: center; margin-top: 1rem; }
  .hero-text .lede {
    font-size: clamp(1rem, 1.3vw, 1.2rem); text-wrap: balance;
    max-width: 62ch; margin: 0 auto;
  }
}

.icon { width: 1.15em; height: 1.15em; flex-shrink: 0; }
.icon-link { display: inline-flex; align-items: center; gap: 0.45em; }
.contact-value { display: flex; align-items: center; gap: 0.5em; }

/* --- page transition: brief fade between pages so the site feels like one product --- */
.page-fade {
  position: fixed; inset: 0; background: var(--bg);
  z-index: 150; pointer-events: none; opacity: 0;
}
.js .page-fade { animation: page-in 0.4s ease-out both; }
.js .page-fade.is-leaving { animation: page-out 0.3s ease-in both; }
@keyframes page-in { from { opacity: 1; } to { opacity: 0; } }
@keyframes page-out { from { opacity: 0; } to { opacity: 1; } }

/* --- sticky availability CTA, appears once you scroll past the opening --- */
.sticky-cta {
  position: fixed; right: 1.25rem; bottom: 1.25rem; z-index: 90;
  background: var(--surface); border: 1px solid var(--accent); color: var(--accent);
  padding: 0.7rem 1.25rem; border-radius: 999px;
  font-size: 0.82rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; text-decoration: none;
  opacity: 0; transform: translateY(12px); pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s ease, background 0.2s ease, color 0.2s ease;
}
.sticky-cta.is-shown { opacity: 1; transform: none; pointer-events: auto; }
.sticky-cta:hover { background: var(--accent); color: var(--on-accent); }

/* --- AI demo: the embed loads on request, so the page never shows the host's
       sleep or error screens to a visitor who has just arrived --- */
.demo-panel {
  margin-top: 2.5rem; padding: 2rem 1.75rem;
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: 14px;
}
.demo-panel .section-label { margin-bottom: 0.75rem; }
.demo-note { color: var(--muted); font-size: 0.9rem; margin: 0 0 1.4rem; max-width: 52ch; }
.demo-actions { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; margin: 0; }
.demo-btn {
  font: inherit; font-weight: 800; cursor: pointer;
  background: var(--accent); color: var(--on-accent);
  border: 2px solid var(--accent); border-radius: 999px;
  padding: 0.8rem 1.7rem;
  transition: background 0.2s ease, color 0.2s ease;
}
.demo-btn:hover { background: transparent; color: var(--accent); }
.demo-link { font-weight: 700; color: var(--accent-2); text-decoration: none; }
.demo-link:hover { text-decoration: underline; }
.demo-panel iframe {
  width: 100%; height: 900px; border: 0; border-radius: 10px; display: block;
}

/* --- pull quote: breaks up long prose with an editorial moment --- */
.pull-quote {
  margin: 2.5rem 0; padding: 0 0 0 1.5rem;
  border-left: 3px solid var(--accent-2);
  font-size: var(--step-1); font-weight: 600; line-height: 1.4;
  color: var(--accent-2); max-width: 30ch;
}

/* --- career timeline: lime spine with a marker per role --- */
.timeline { list-style: none; margin: 2rem 0 0; padding: 0 0 0 2rem; position: relative; }
.timeline::before {
  content: ""; position: absolute; left: 0; top: 0.4rem; bottom: 0.4rem;
  width: 2px; background: var(--accent);
}
.timeline > li { position: relative; padding-bottom: 2.25rem; }
.timeline > li:last-child { padding-bottom: 0; }
.timeline > li::before {
  content: ""; position: absolute; left: calc(-2rem - 5px); top: 0.55rem;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--bg); border: 2px solid var(--accent);
}
.timeline-when {
  display: block; font-size: 0.75rem; letter-spacing: 0.14em;
  text-transform: uppercase; font-weight: 700; color: var(--accent-2);
}
.timeline h3 { margin: 0.35rem 0 0.4rem; font-size: var(--step-1); }
.timeline p { margin: 0; color: var(--muted); }

/* --- tag rows: capability and certification pills --- */
.tag-row { list-style: none; display: flex; flex-wrap: wrap; gap: 0.6rem; padding: 0; margin: 1.5rem 0 0; }
.tag-row li {
  border: 1px solid var(--line-strong); border-radius: 999px;
  padding: 0.45rem 1rem; font-size: 0.85rem; font-weight: 600;
  color: var(--ink); background: var(--surface); margin: 0; max-width: none;
}
.tag-row-accent li { border-color: var(--accent-2); color: var(--accent-2); }

/* --- home page: proof band, pillars, closing CTA --- */
.section-label {
  font-size: 0.8rem; letter-spacing: 0.16em; text-transform: uppercase;
  font-weight: 700; color: var(--accent-2); margin: 0 0 1.6rem;
}
.proof { margin-top: 4.5rem; }
.proof-grid {
  list-style: none; padding: 0; margin: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 1.75rem;
}
/* six stats read best as an even 3 x 2 on desktop, rather than 5 plus an orphan */
@media (min-width: 801px) {
  .proof-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.proof-grid li { border-top: 2px solid var(--accent); padding-top: 0.9rem; }
.proof-grid b {
  display: block; font-size: clamp(2.2rem, 5vw, 3.4rem); font-weight: 900;
  line-height: 1; letter-spacing: -0.03em; color: var(--accent);
}
.proof-grid span {
  display: block; margin-top: 0.55rem; font-size: 0.88rem;
  color: var(--muted); max-width: 26ch; line-height: 1.5;
}
.pillars { margin-top: 5.5rem; }
.pillar-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.25rem; margin-top: 2rem;
}
.pillar {
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: 10px;
  padding: 1.6rem 1.5rem 1.7rem;
  transition: border-color 0.25s ease, transform 0.25s ease;
}
.pillar:hover { border-color: var(--accent); transform: translateY(-4px); }
.pillar h3 { margin-top: 0; font-size: var(--step-1); color: var(--accent-2); }
.pillar p { font-size: 0.94rem; }
.pillar a { font-weight: 700; text-decoration: none; color: var(--accent-2); }
.pillar a:hover { text-decoration: underline; }
.home-cta { margin-top: 5.5rem; border-top: 1px solid var(--line); padding-top: 2.5rem; }
.home-cta .lede { max-width: 46ch; }

.case {
  border-top: 2px solid var(--ink); padding: 2rem 1rem 2.5rem; margin-top: 2.5rem;
  transition: transform 0.3s ease, border-color 0.25s ease;
}
.case:hover { transform: translateY(-5px); border-top-color: var(--accent); }
.case-stat { font-size: var(--step-3); font-weight: 900; color: var(--accent); margin: 0; line-height: 1; }
.case h2 { margin-top: 0.5rem; }
ul { padding-left: 1.2rem; }
li { margin-bottom: 0.6rem; max-width: 68ch; }

/* Outside of Work: same dark system, but a lifted surface and a teal accent in the
   content area so it reads as a change of register from the professional pages.
   Header and footer chrome keep the lime accent for site-wide consistency. */
body.personal { --bg: #131312; }
body.personal .lede { max-width: none; }

.hobby { margin-top: 3.5rem; }
.gallery { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1rem; margin-top: 1.5rem; }
/* four-photo galleries (Porsche) lay out as a 2x2 grid instead of 3+1 */
@media (min-width: 600px) {
  .gallery:has(img:nth-child(4)) { grid-template-columns: repeat(2, 1fr); }
}
.gallery img, .gallery video { width: 100%; height: 100%; object-fit: cover; border-radius: 6px; aspect-ratio: 4 / 3; }

.contact-links { display: grid; gap: 1rem; margin-top: 2.5rem; max-width: 640px; }
.contact-card {
  display: flex; flex-direction: column; gap: 0.3rem;
  border: 2px solid var(--ink); border-radius: 6px; padding: 1.4rem 1.6rem;
  text-decoration: none;
  transition: border-color 0.2s ease, background 0.2s ease, transform 0.2s ease;
}
/* hover lifts the card and turns it teal, rather than filling it with lime,
   which would swallow the label text sitting on top */
.contact-card:hover {
  border-color: var(--accent-2);
  background: var(--surface);
  transform: translateY(-3px);
}
.contact-card:hover .contact-value { color: var(--accent-2); }
.contact-label { text-transform: uppercase; letter-spacing: 0.12em; font-size: 0.75rem; font-weight: 700; color: var(--accent); }
.contact-value { font-size: var(--step-1); font-weight: 800; overflow-wrap: anywhere; }

/* scroll reveal: content fades and rises into view as you scroll. The hero is
   excluded because it runs its own entrance animation on load. */
.js main > *:not(.hero) {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}
.js main > h1 { transform: translateY(32px); }
.js main > *.is-visible { opacity: 1; transform: none; }
/* keep card hover snappy even with the reveal transition on the same element */
.js main > .case {
  transition: opacity 0.6s ease, transform 0.3s ease, border-color 0.25s ease;
}
/* bold entrance: the big stat scales and fades in with a slight overshoot
   the moment its card reveals (works for numbers and text stats alike) */
.js main > .case.is-visible .case-stat {
  animation: stat-pop 0.6s cubic-bezier(0.2, 0.9, 0.3, 1) both;
  transform-origin: left center;
}
@keyframes stat-pop {
  0% { opacity: 0; transform: scale(0.4) translateY(6px); }
  62% { opacity: 1; transform: scale(1.08); }
  100% { opacity: 1; transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .js main > * { opacity: 1 !important; transform: none !important; }
  .case:hover { transform: none; }
}
