/* ==========================================================================
   Mikayla Eppert — Portfolio (v6)

   Design system, refined for breathing room and editorial calm:
   - Spacing rhythm (8/16/24/32/48/64/96px) communicates relationship —
     closely related elements sit close together, major section transitions
     get generous room. See the --space-* scale below.
   - A soft, consistent radius hierarchy (structural containers > cards >
     compact controls > pills) replaces the previous sharp/mixed corners.
   - Separation comes from whitespace and subtle surface-color alternation
     between sections first, hairline borders only where truly useful —
     not repeated boxes and rules everywhere.
   - Off-white background, grayscale text, two-tone accent system: coral for
     primary emphasis, mint for secondary accents.
   - Fraunces (headings) + Inter (body) — Inter holds up at small sizes far
     better than a serif does, Fraunces keeps headings distinctive.
   ========================================================================== */

:root {
  --bg: #FAF9F6;
  --surface: #F1EFE9;

  /* grayscale text ramp */
  --ink: #262624;
  --ink-soft: rgba(38, 38, 36, 0.64);
  --ink-faint: rgba(38, 38, 36, 0.46);
  --divider: rgba(38, 38, 36, 0.10);

  /* coral — primary accent */
  --coral: #D8BFB4;
  --coral-dark: #A98275;
  --coral-light: #F2A38C;
  --coral-tint: #E6D4CC;

  /* mint — secondary accent */
  --mint: #C4D3C5;
  --mint-dark: #718B78;
  --mint-light: #A9D4C4;
  --mint-tint: #DDE8DE;

  --font-heading: "Fraunces", Georgia, serif;
  --font-body: "Inter", system-ui, -apple-system, sans-serif;

  /* Spacing scale — communicates relationship, not just "amount of gap".
     1–2: text/icon, tightly related elements. 3–4: related content,
     component spacing. 5–6: subsection/component-group spacing.
     7: major section transitions. 8: reserved for exceptional emphasis. */
  --space-1: 8px;
  --space-2: 16px;
  --space-3: 24px;
  --space-4: 32px;
  --space-5: 48px;
  --space-6: 64px;
  --space-7: 96px;
  --space-8: 128px;

  /* Radius hierarchy: large structural containers get the softest, most
     generous rounding; cards a step down; compact controls smaller still;
     pills only where the shape is semantically a pill (tags, some buttons). */
  --radius-lg: 26px;
  --radius-md: 16px;
  --radius-sm: 10px;
  --radius-pill: 999px;

  --shadow-sm: 0 1px 3px rgba(38, 38, 36, 0.07);
  --shadow-md: 0 6px 20px rgba(38, 38, 36, 0.10);
  --shadow-lg: 0 20px 48px rgba(38, 38, 36, 0.14);

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --header-h: 64px;

  /* Width of Experience's timeline date column (see .exp-dates-col). */
  --exp-dates-col-w: 56px;
}

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-heading);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.012em;
  margin: 0;
  color: var(--ink);
}
h1 { font-size: clamp(32px, 4.4vw, 42px); }
h2 { font-size: clamp(24px, 3vw, 30px); }
h3 { font-size: 18px; }
p { margin: 0 0 var(--space-2); }
a { color: var(--coral-dark); text-underline-offset: 3px; transition: color 0.15s var(--ease); }
a:hover { color: var(--coral-dark); opacity: 0.75; }
img { display: block; max-width: 100%; }
ul { margin: 0; padding: 0; list-style: none; }
button { font: inherit; }

:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--coral-dark);
  outline-offset: 3px;
  border-radius: 4px;
}
::selection { background: var(--coral-tint); color: var(--coral-dark); }

.visually-hidden {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.wrap {
  width: 100%;
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 var(--space-4);
}
/* Narrower measure for prose-heavy sections (Research, Experience), so
   paragraph and list-item text never runs the full page width. */
.wrap-narrow { max-width: 780px; }

.eyebrow {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--coral-dark);
  margin: 0 0 var(--space-2);
}

.plate {
  border: 5px solid var(--bg);
  outline: 1px solid var(--divider);
  box-shadow: var(--shadow-md);
}

/* ── reveal-on-scroll ─────────────────────────────────────────────────── */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
}
.reveal.is-visible { opacity: 1; transform: none; }

/* ── header / nav ─────────────────────────────────────────────────────── */
.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 20;
  background: rgba(250, 249, 246, 0.88);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--divider);
}
.nav-wrap {
  max-width: 1080px;
  margin: 0 auto;
  height: var(--header-h);
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: 0 var(--space-4);
}
/* At the top of the page the brand mark reads as a plain wordmark, no
   container — it doesn't need to announce itself as a button when About
   (which it links to) is already the first thing on screen. Once the user
   scrolls (site.js toggles .is-scrolled on .site-header), it gains a
   pill container so it reads as an obvious "back to top" control instead
   of blending into the header like a static heading. The pill's box
   (padding/border/radius) is present at all times so the transition
   animates smoothly with no layout shift — only its background, border,
   and shadow are invisible until scrolled. */
.nav-brand {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 18px;
  color: var(--ink);
  margin-right: auto;
  margin-left: calc(var(--space-2) * -1);
  text-decoration: none;
  padding: 8px var(--space-2);
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  background: transparent;
  transition: color 0.15s var(--ease), background 0.25s var(--ease), border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.nav-brand:hover { color: var(--coral-dark); }
.site-header.is-scrolled .nav-brand {
  background: var(--surface);
  border-color: var(--divider);
  box-shadow: var(--shadow-sm);
}
.nav { display: flex; align-items: center; gap: var(--space-3); }
.nav a { color: var(--ink-soft); text-decoration: none; font-size: 14px; font-weight: 500; transition: color 0.15s var(--ease); }
.nav a:hover, .nav a.is-current { color: var(--coral-dark); }
.nav .btn { text-decoration: none; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  cursor: pointer;
  text-decoration: none;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 14px;
  line-height: 1.2;
  color: var(--ink);
  background: transparent;
  border: 1px solid transparent;
  padding: 11px 22px;
  border-radius: var(--radius-pill);
  transition: background 0.18s var(--ease), color 0.18s var(--ease), box-shadow 0.18s var(--ease), transform 0.18s var(--ease);
}
.btn-primary { color: #fff; background: var(--coral-dark); border-color: var(--coral-dark); }
.btn-primary:hover { background: var(--coral-dark); border-color: var(--coral-dark); filter: brightness(0.92); transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.btn-primary:active { transform: none; box-shadow: none; }
.btn-block { width: 100%; margin-top: var(--space-1); }

.menu-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  /* 44px minimum touch target (WCAG 2.5.5) around the 20px icon, without
     changing the icon's own visual size. */
  width: 44px;
  height: 44px;
  margin-right: calc(var(--space-1) * -1);
  color: var(--ink);
  cursor: pointer;
}

/* A thin coral-tint circle around the icon signals "this is a clickable
   link" at a glance, rather than relying on the bare glyph reading as
   interactive. 40px keeps it a comfortable tap target without the pill
   looking oversized next to the text it sits beside. */
.icon-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--coral-tint);
  color: var(--coral-dark);
  background: transparent;
  transition: background 0.15s var(--ease), border-color 0.15s var(--ease), transform 0.15s var(--ease);
}
.icon-link:hover, .icon-link:focus-visible {
  background: var(--coral-tint);
  border-color: var(--coral-dark);
  transform: translateY(-1px);
}

.header-spacer { height: var(--header-h); }

/* ── section rhythm ───────────────────────────────────────────────────── */
main { display: block; }
.section { padding: var(--space-7) 0; }
/* Soft-fade the surface/bg handoff instead of a hard color cutoff, so the
   section boundary reads as a gentle gradient rather than a visible seam
   — no border/divider line added, matching the site's existing rule that
   separation comes from whitespace and color, not hairlines. */
.section-highlights,
.section-skills {
  background: linear-gradient(
    to bottom,
    var(--bg),
    var(--surface) var(--space-6),
    var(--surface) calc(100% - var(--space-6)),
    var(--bg)
  );
}
.section-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  flex-wrap: wrap;
}
/* Styled as a real button (matching .btn's pill/padding/weight conventions)
   in the mint accent rather than coral, so it reads as its own secondary
   action distinct from the coral primary buttons elsewhere on the page. */
.section-heading .bibliography-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 13px;
  font-weight: 600;
  color: #fff;
  background: var(--mint-dark);
  border-radius: var(--radius-pill);
  padding: 8px 16px;
  text-decoration: none;
  transition: filter 0.18s var(--ease), transform 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.section-heading .bibliography-link:hover {
  filter: brightness(0.92);
  transform: translateY(-1px);
  box-shadow: var(--shadow-sm);
}
.section-heading .bibliography-link .external-link-icon { flex: none; }
.section-hint { font-size: 13.5px; color: var(--ink-faint); margin: 6px 0 0; flex-basis: 100%; }

/* ── intro / about (the site's opening section — no separate Hero) ──────── */
.section-intro {
  /* Tighter than the standard section rhythm: About sits directly under the
     header (no Hero above it to create separation) and should feel
     efficiently composed rather than padded like a mid-page section. */
  padding-top: var(--space-5);
  padding-bottom: var(--space-6);
}
.intro-grid {
  display: grid;
  grid-template-columns: 1.5fr 1fr;
  gap: var(--space-6);
  align-items: start;
}
.about-name-row { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
/* Scoped-up from the global h1 scale: About's name is the site's sole
   identity statement now that there's no separate Hero, so it carries more
   visual weight here than the shared h1 rule (used nowhere else) provides. */
.section-intro h1 { font-size: clamp(38px, 5.2vw, 54px); }
.tagline {
  font-size: 17px;
  font-style: italic;
  color: var(--coral-dark);
  margin-top: var(--space-2);
}
.bio-text {
  font-size: 16px;
  line-height: 1.7;
  color: var(--ink-soft);
  max-width: 60ch;
}
.tagline + .bio-text { margin-top: var(--space-4); }
.bio-text + .bio-text { margin-top: var(--space-2); }
.location {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mint-dark);
  margin-top: var(--space-4);
}

/* Photo: an organic (asymmetric-radius) frame with a soft tinted shape
   sitting behind it, so the photo reads as integrated into the section's
   visual language rather than a rectangular headshot dropped into a grid
   cell. Colors and radius scale reuse existing tokens. */
.intro-photo {
  position: relative;
  display: flex;
  justify-content: center;
  padding-top: var(--space-2);
}
.intro-photo::before {
  content: "";
  position: absolute;
  inset: 10px;
  background: linear-gradient(135deg, var(--coral-tint), var(--mint-tint));
  border-radius: 58% 42% 63% 37% / 45% 57% 43% 55%;
  z-index: 0;
}
.intro-photo img {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 300px;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 58% 42% 63% 37% / 45% 57% 43% 55%;
}

/* Education: each degree is its own organic container (.edu-card), laid out
   side-by-side on desktop with comparable visual weight. Radii are built
   entirely from the existing radius tokens (paired asymmetrically per card)
   rather than new one-off values, so the shapes feel organic without
   introducing a separate visual system. */
.about-education {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-top: var(--space-4);
}
.edu-card {
  flex: 1 1 220px;
  background: #fff;
  padding: var(--space-3) var(--space-4);
  border-top: 3px solid var(--coral);
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.2s var(--ease), transform 0.2s var(--ease);
  border-radius: var(--radius-lg) var(--radius-sm) var(--radius-lg) var(--radius-sm);
}
.edu-card:nth-child(2n) {
  border-top-color: var(--mint);
  border-radius: var(--radius-sm) var(--radius-lg) var(--radius-sm) var(--radius-lg);
}
.edu-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
.edu-card__institution { display: block; font-family: var(--font-heading); font-weight: 600; font-size: 14.5px; }
.edu-card__degree { color: var(--ink-faint); font-size: 13.5px; margin-top: 3px; }

/* Latest Lab Notes teaser: bottom-right of About, linking out to the
   dedicated Lab Notes page. Reuses the edu-card organic-card treatment
   (paired-asymmetric radius, top accent, white bg) for the container and
   the Highlights kicker/title typography for its two text lines, rather
   than introducing new visual language. */
.about-latest-note-row { display: flex; justify-content: flex-end; margin-top: var(--space-3); }
.about-latest-note {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 18px;
  background: #fff;
  border-top: 3px solid var(--coral);
  border-radius: var(--radius-lg) var(--radius-sm) var(--radius-lg) var(--radius-sm);
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  transition: box-shadow 0.2s var(--ease), transform 0.2s var(--ease);
}
.about-latest-note:hover, .about-latest-note:focus-visible { box-shadow: var(--shadow-md); transform: translateY(-2px); }
.about-latest-note .highlight-kicker { color: var(--coral-dark); }

/* ── highlights ───────────────────────────────────────────────────────── */
/* Compact, section-level padding — Highlights is a quick proof strip
   between About and Research, not a full content section, so it doesn't
   need the standard section rhythm's generous top/bottom space. */
.section-highlights { padding-top: var(--space-2); padding-bottom: var(--space-2); }
/* Native horizontal scroll: cards keep their intrinsic width and the row
   scrolls (mouse-wheel, trackpad, or touch swipe) once they no longer fit,
   rather than wrapping to multiple rows or shrinking to fit. */
.highlights-scroll {
  display: flex;
  gap: var(--space-3);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: var(--space-1);
  scrollbar-width: thin;
  scrollbar-color: var(--ink-faint) transparent;
}
.highlights-scroll::-webkit-scrollbar { height: 6px; }
.highlights-scroll::-webkit-scrollbar-track { background: transparent; }
.highlights-scroll::-webkit-scrollbar-thumb { background: var(--divider); border-radius: var(--radius-pill); }
.highlight-card {
  flex: none;
  width: 220px;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-3);
  border-radius: var(--radius-md);
  border-top: 3px solid var(--mint);
  background: #fff;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.2s var(--ease), transform 0.2s var(--ease);
}
.highlight-card:hover { box-shadow: var(--shadow-md); transform: translateY(-3px); }
.highlight-kicker { font-size: 10.5px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--coral-dark); }
.highlight-title { font-family: var(--font-heading); font-weight: 600; font-size: 15.5px; margin-top: 2px; }
.highlight-body { font-size: 12.5px; color: var(--ink-soft); margin: 4px 0 0; }
.highlight-meta { font-size: 12px; font-weight: 700; color: var(--ink); margin-top: 2px; }

/* ── research ─────────────────────────────────────────────────────────── */
.pub-list { display: flex; flex-direction: column; }
/* Same highlight technique as .expand-row__summary (Experience): padding
   plus an equal negative margin lets the hover/focus background bleed
   slightly past the row's own content without shifting surrounding layout. */
.pub-row {
  position: relative;
  padding: var(--space-2) var(--space-1);
  margin: 0 calc(var(--space-1) * -1);
  border-radius: var(--radius-sm);
  border-bottom: 1px solid var(--divider);
  transition: background 0.18s var(--ease);
}
.pub-row:last-child { border-bottom: none; }
.pub-row:hover, .pub-row:focus-within { background: var(--surface); }
.pub-title { font-family: var(--font-heading); font-weight: 600; font-size: 16px; line-height: 1.3; }
.pub-title-link { color: var(--ink); text-decoration: none; }
.pub-title-link:hover { color: var(--coral-dark); }
.pub-meta { font-size: 13px; color: var(--ink-faint); margin-top: 3px; }
/* Collapsed by default; hovering or focusing within the row (mouse or
   keyboard) reveals it. Touch/no-hover devices show it directly instead —
   there's no reliable hover gesture to hide it behind. Always present in
   the DOM either way, so screen readers see it regardless of visual state. */
.pub-description {
  font-size: 13.5px;
  color: var(--ink-soft);
  line-height: 1.5;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  margin-top: 0;
  transition: max-height 0.3s var(--ease), opacity 0.25s var(--ease), margin-top 0.25s var(--ease);
}
.pub-row:hover .pub-description,
.pub-row:focus-within .pub-description {
  max-height: 120px;
  opacity: 1;
  margin-top: var(--space-1);
}
@media (hover: none), (pointer: coarse) {
  .pub-description { max-height: none; opacity: 1; overflow: visible; margin-top: var(--space-1); }
}

/* ── skills ───────────────────────────────────────────────────────────── */
.skills-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-3);
}
.skill-card {
  background: #fff;
  border-radius: var(--radius-md);
  padding: var(--space-4);
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.2s var(--ease), transform 0.2s var(--ease);
}
.skill-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
.skill-card__title { color: var(--coral-dark); margin-bottom: var(--space-2); }
.skills-list { font-size: 14px; color: var(--ink-soft); line-height: 1.9; }

/* ── experience ───────────────────────────────────────────────────────── */
/* v2-style dot timeline: a dates column and a dot column sit to the left of
   each role's content, connected by a vertical rule — reproducing v2's
   Experience structure with v6's own tokens (colors/spacing/radius) rather
   than its raw values. */
.experience-list { display: flex; flex-direction: column; position: relative; }
.experience-list::before {
  content: "";
  position: absolute;
  left: calc(var(--exp-dates-col-w) + var(--space-2) + 9px);
  top: 8px;
  bottom: 8px;
  width: 1px;
  background: var(--divider);
}
.expand-row {
  display: grid;
  grid-template-columns: var(--exp-dates-col-w) 18px 1fr;
  gap: var(--space-2);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--divider);
}
.expand-row:last-child { border-bottom: none; }
.exp-dates-col {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  text-align: right;
  padding-top: 3px;
  position: relative;
  z-index: 1;
}
.exp-dot-col { display: flex; justify-content: center; position: relative; z-index: 1; }
.exp-dot {
  width: 9px;
  height: 9px;
  margin-top: 6px;
  border-radius: 50%;
  background: var(--coral);
  box-shadow: 0 0 0 3px var(--bg);
}
/* The hover/expanded highlight lives on .exp-content — the shared wrapper
   around both .expand-row__summary (title/org/tags) and
   .expand-row__detail (bullets) — rather than on the summary alone, so the
   whole entry reads as one card instead of a background appearing only
   behind part of it. Keyed off .is-expanded (the same state class that
   drives the detail reveal) rather than a raw :hover, so the background
   stays put for as long as the row is expanded — including once the
   cursor moves down into the bullets — instead of vanishing the moment the
   pointer leaves the summary's own box. Padding/inset reuses the same
   --space-1 value the summary used to use on its own, just applied one
   level up so it now insets the whole merged block evenly. */
.exp-content {
  min-width: 0;
  padding: var(--space-1);
  margin: calc(var(--space-1) * -1);
  border-radius: var(--radius-sm);
  position: relative;
  transition: background 0.18s var(--ease);
}
.expand-row.is-expanded .exp-content { background: var(--surface); }
.expand-row__summary { cursor: pointer; }
/* The "+" affordance now lives on .exp-content (the highlighted card)
   rather than .expand-row__summary, so it stays pinned to the card's own
   top-right corner now that the card's padding/background moved up a
   level — same top/right inset as before, just relative to the new
   background box instead of the old, smaller one. */
.exp-content::after {
  content: "+";
  position: absolute;
  top: var(--space-1);
  right: var(--space-1);
  font-family: var(--font-heading);
  font-size: 18px;
  line-height: 1;
  color: var(--coral);
  opacity: 0.6;
  transition: transform 0.2s var(--ease), opacity 0.15s var(--ease);
}
.expand-row.is-expanded .exp-content::after { transform: rotate(45deg); opacity: 0.9; }

.exp-headline { font-size: 16px; padding-right: 28px; }
.exp-dates { color: var(--ink-faint); font-variant-numeric: tabular-nums; font-weight: 400; }
.exp-summary { font-size: 14px; color: var(--ink-soft); font-style: italic; margin-top: 3px; }
/* Small "N Roles" cue on grouped timeline entries — same pill language as
   .tag, just coral-toned to read as a structural marker rather than a
   skill tag, and restrained enough not to outweigh the role title itself. */
.role-badge {
  display: inline-flex;
  align-items: center;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--coral-dark);
  background: var(--coral-tint);
  border-radius: var(--radius-pill);
  padding: 2px 9px;
  margin-left: 2px;
  vertical-align: middle;
}

/* "Concurrent Roles" groups the three part-time jobs into one timeline
   entry, but each sub-role keeps its own title/org/dates/summary/tags/
   bullets in a clearly separated block, so they read as distinct roles
   rather than one blended list. */
.exp-bullets--subgroups { padding-left: 0; list-style: none; }
.exp-subgroup { padding-top: var(--space-3); border-top: 1px dashed var(--divider); }
.exp-subgroup:first-child { padding-top: 0; border-top: none; }
.exp-subgroup + .exp-subgroup { margin-top: var(--space-3); }
.exp-subgroup-head { font-size: 14.5px; }
.exp-subgroup-summary { font-size: 13.5px; color: var(--ink-soft); font-style: italic; margin-top: 2px; }
.exp-subgroup .tag-row { margin-top: var(--space-2); }
.exp-subgroup .exp-bullets { margin-top: var(--space-2); }

.tag-row {
  display: flex;
  gap: 6px;
  margin-top: var(--space-2);
  overflow-x: auto;
  padding-bottom: 2px;
  /* Widened from 24px so the "more to scroll" fade reads clearly rather
     than looking like a mid-word clip, now that Experience's content
     column is narrower (date column takes up some of the row's width). */
  mask-image: linear-gradient(to right, black calc(100% - 36px), transparent 100%);
  -webkit-mask-image: linear-gradient(to right, black calc(100% - 36px), transparent 100%);
  /* The mask-image fade above is the sole "more tags to scroll" cue —
     suppress the native scrollbar so it doesn't also appear as a visible
     bar under the tags (still fully scrollable via trackpad/wheel/touch). */
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.tag-row::-webkit-scrollbar { display: none; }
.tag {
  display: inline-flex;
  align-items: center;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.01em;
  padding: 5px 13px;
  border-radius: var(--radius-pill);
  flex: none;
  white-space: nowrap;
}
.tag-neutral { background: var(--mint-tint); color: var(--mint-dark); }

/* Auto-height reveal via grid-template-rows (0fr/1fr) rather than a fixed
   max-height — animates to the detail's real height with no magic number,
   which matters now that "Concurrent Roles" can expand to several hundred
   pixels of grouped sub-role content that a fixed cap would clip. */
.expand-row__detail {
  display: grid;
  grid-template-rows: 0fr;
  overflow: hidden;
  transition: grid-template-rows 0.32s var(--ease);
}
.expand-row.is-expanded .expand-row__detail { grid-template-rows: 1fr; }
.expand-row__detail > * { overflow: hidden; min-height: 0; }
.exp-bullets {
  margin: var(--space-2) 0 var(--space-1);
  padding-left: 20px;
  list-style: disc;
  font-size: 14px;
  color: var(--ink-soft);
  line-height: 1.7;
}
.exp-bullets li { margin-bottom: 5px; }
/* Understated context line under a part-time role's bullets — e.g. "This
   role was completed part-time, concurrent with my UT Southwestern role."
   Sits outside .exp-bullets on purpose (see noteHtml in scripts/build.js)
   so it reads as a footnote about the role, not another accomplishment. */
.exp-note {
  font-size: 12.5px;
  color: var(--ink-faint);
  font-style: italic;
  margin: 0;
}

/* ── lab notes (shared typography, used on the dedicated lab-notes.html
   page's article rows — the homepage no longer has an on-page Lab Notes
   section/grid) ───────────────────────────────────────────────────────── */
.note-title-link { font-size: 14.5px; font-weight: 600; color: var(--ink); }
.note-tagline { font-size: 12.5px; color: var(--ink-faint); margin-top: 3px; }
.note-outlet { color: var(--mint-dark); font-weight: 600; }

/* ── contact ──────────────────────────────────────────────────────────── */
.contact-grid { display: grid; grid-template-columns: 1fr 1.2fr; gap: var(--space-6); align-items: start; }
.contact-intro p { font-size: 15px; color: var(--ink-soft); max-width: 42ch; }
.contact-intro .icon-link { margin-top: var(--space-2); }

.contact-form { display: flex; flex-direction: column; gap: var(--space-3); }
.field > label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 6px;
  color: var(--ink-soft);
}
.input {
  width: 100%;
  min-height: 44px;
  padding: 11px 16px;
  font: inherit;
  font-size: 15px;
  color: var(--ink);
  caret-color: var(--coral);
  background: #fff;
  border: 1px solid var(--divider);
  /* --radius-md (cards' own radius) rather than the compact-control radius
     used for pills/small chips — the form is the section's focal element,
     so it reads a step softer/more considered than a plain input. */
  border-radius: var(--radius-md);
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.input:hover { border-color: var(--ink-faint); }
.input:focus-visible { border-color: var(--coral-dark); outline-offset: 0; box-shadow: 0 0 0 3px var(--coral-tint); }
textarea.input { min-height: 120px; resize: vertical; }

/* ── footer ───────────────────────────────────────────────────────────── */
.site-footer { text-align: center; font-size: 13px; color: var(--ink-faint); padding: var(--space-5) 0; }
.site-footer a { color: inherit; }
.site-footer a:hover { color: var(--coral-dark); }
.footer-inner { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--space-1); }
.footer-dot { color: var(--ink-faint); }
/* Rounded hover/focus target keeps the footer's secondary link in the
   site's organic-shape language without giving it the visual weight of
   main nav — a plain text link stays visually secondary by design. */
.footer-link { padding: 3px 10px; border-radius: var(--radius-pill); text-decoration: none; transition: background 0.15s var(--ease), color 0.15s var(--ease); }
.footer-link:hover, .footer-link:focus-visible { background: var(--coral-tint); }

/* ── lab notes (dedicated page) ──────────────────────────────────────── */
/* Simplified header for secondary pages: brand wordmark only, no nav list
   (nav's hrefs are same-page anchors that don't apply off index.html), so
   .menu-toggle/#nav are intentionally omitted rather than pointed at
   cross-page hashes. */
.section-labnotes-page {
  padding-top: var(--space-6);
  padding-bottom: var(--space-7);
}
/* Back-to-main-site control: a small rounded tab in the header, distinct
   from the brand wordmark, so it reads as a deliberate wayfinding control
   rather than a browser back button. Scoped to this class only (not
   .nav-wrap) so index.html's shared header markup/behavior is untouched. */
.labnotes-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-soft);
  text-decoration: none;
  padding: 7px 14px;
  border: 1px solid var(--divider);
  border-radius: var(--radius-pill);
  background: var(--surface);
  transition: background 0.15s var(--ease), color 0.15s var(--ease), border-color 0.15s var(--ease);
}
.labnotes-back:hover, .labnotes-back:focus-visible {
  color: var(--coral-dark);
  border-color: var(--coral);
  background: var(--coral-tint);
}
.labnotes-back-arrow { font-size: 14px; line-height: 1; transition: transform 0.15s var(--ease); }
.labnotes-back:hover .labnotes-back-arrow { transform: translateX(-2px); }

/* Article gallery: each card is an organic container (same paired-
   asymmetric-radius + alternating coral/mint top-accent convention as
   .edu-card/.labnotes-intro-card), thumbnail-above-text, laid out in a
   responsive grid (4 desktop / 2 tablet / 1 mobile — see responsive
   section). Reuses the homepage's own .note-title-link/.note-outlet/
   .note-tagline typography so the dedicated page reads as the same design
   system rather than a new one. */
.section-labnotes-list { padding-top: 0; padding-bottom: var(--space-7); }
.notes-gallery { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-4); }
.note-gallery-card {
  display: flex;
  flex-direction: column;
  background: #fff;
  text-decoration: none;
  color: inherit;
  border-top: 3px solid var(--coral);
  border-radius: var(--radius-lg) var(--radius-sm) var(--radius-lg) var(--radius-sm);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  transition: box-shadow 0.2s var(--ease), transform 0.2s var(--ease);
}
.note-gallery-card:nth-child(2n) {
  border-top-color: var(--mint);
  border-radius: var(--radius-sm) var(--radius-lg) var(--radius-sm) var(--radius-lg);
}
.note-gallery-card:hover, .note-gallery-card:focus-visible { box-shadow: var(--shadow-md); transform: translateY(-2px); }
.note-gallery-card:hover .note-title-link { color: var(--coral-dark); }
.note-thumb-gallery {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}
.note-gallery-card .note-row__text { padding: var(--space-3); }
.note-gallery-card .note-title-link { display: block; font-size: 16px; }
.note-gallery-card .note-outlet { display: block; font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; margin-top: 6px; }
.note-gallery-card .note-tagline { font-size: 13.5px; line-height: 1.55; margin-top: 6px; }
.section-labnotes-page h1 { font-size: clamp(38px, 5.2vw, 54px); }
/* Centered organic introductory panel — same paired-asymmetric-radius +
   top-accent treatment as .edu-card, now holding the page heading too
   (rather than sitting above the card) so it reads as one composed panel. */
.labnotes-intro-card {
  background: #fff;
  padding: var(--space-5) var(--space-6);
  border-top: 3px solid var(--coral);
  border-radius: var(--radius-lg) var(--radius-sm) var(--radius-lg) var(--radius-sm);
  box-shadow: var(--shadow-sm);
  text-align: center;
}
.labnotes-intro-card h1 { margin-bottom: var(--space-3); }
.labnotes-intro-card p { font-size: 16px; line-height: 1.7; color: var(--ink-soft); margin: 0; }
.labnotes-intro-card p + p { margin-top: var(--space-2); }
.labnotes-intro-card a { font-weight: 600; }

/* ── thank-you page ───────────────────────────────────────────────────── */
/* Dedicated, simplified confirmation state for the Netlify Forms redirect
   target — reuses site tokens/button conventions rather than introducing a
   new visual language. Self-contained fade-in (no IntersectionObserver;
   the content is already in view on load). */
.confirm-page {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--space-4);
  animation: confirm-in 0.6s var(--ease) both;
}
@keyframes confirm-in {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: none; }
}
.confirm-badge {
  width: 72px;
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--mint-dark);
  background: var(--mint-tint);
  border-radius: var(--radius-lg) var(--radius-sm) var(--radius-lg) var(--radius-sm);
  box-shadow: var(--shadow-sm);
  margin-bottom: var(--space-3);
}
.confirm-page .eyebrow { margin-bottom: var(--space-1); }
.confirm-page h1 { margin-bottom: var(--space-2); }
.confirm-copy { max-width: 40ch; color: var(--ink-soft); margin-bottom: var(--space-4); }
.confirm-page .btn { text-decoration: none; }

/* ── ambient background ──────────────────────────────────────────────────
   A subtle, slow-drifting atmospheric layer sitting behind all page
   content on every page. Structurally: a position:fixed, full-viewport
   container with z-index:-1, inserted as the first child of <body>. Because
   most sections here have no background-color of their own (only body's
   own solid --bg, plus .section-highlights/.section-skills's --surface),
   this layer paints above body's background but below all normal in-flow
   content — visible wherever a section has no opaque background, naturally
   masked wherever one does. No section backgrounds are changed to achieve
   this; it falls out of the existing architecture.
   Shapes reuse the same asymmetric border-radius "blob" technique as
   .intro-photo, and a single shared image (see images/ambient/) sampled at
   different positions/scales per shape via background-position/-size, so
   no extra image copies are needed. Movement animates transform only
   (GPU-friendly); randomized starting values are set once at page init by
   initAmbientBackground() in js/site.js and never touched again. */
.ambient-bg {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}
.ambient-shape {
  position: absolute;
  width: 46vw;
  height: 46vw;
  max-width: 620px;
  max-height: 620px;
  opacity: 0.5;
  filter: blur(14px);
  background-image: url("../images/ambient/ambient-source.jpg");
  background-repeat: no-repeat;
  will-change: transform;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}
/* Six hand-tuned variants: distinct blob silhouette, start position, and
   drift timing/path per shape so the six don't read as identical/looping
   in sync. background-position/-size/animation-delay are further
   randomized once at init by JS; these are the static fallbacks. */
.ambient-shape-1 { top: -8%;  left: -6%;  border-radius: 58% 42% 63% 37% / 45% 57% 43% 55%; animation-name: ambient-drift-a; animation-duration: 59s; }
.ambient-shape-2 { top: 8%;   right: -10%; border-radius: 42% 58% 37% 63% / 55% 45% 57% 43%; animation-name: ambient-drift-b; animation-duration: 74s; }
.ambient-shape-3 { top: 42%;  left: 22%;  border-radius: 63% 37% 55% 45% / 42% 58% 40% 60%; animation-name: ambient-drift-c; animation-duration: 67s; }
.ambient-shape-4 { bottom: -10%; left: -8%; border-radius: 37% 63% 45% 55% / 58% 42% 55% 45%; animation-name: ambient-drift-a; animation-duration: 81s; }
.ambient-shape-5 { bottom: 4%; right: -6%; border-radius: 55% 45% 58% 42% / 37% 63% 45% 55%; animation-name: ambient-drift-b; animation-duration: 52s; }
.ambient-shape-6 { top: 30%;  right: 18%; border-radius: 45% 55% 42% 58% / 63% 37% 58% 42%; animation-name: ambient-drift-c; animation-duration: 86s; }

@keyframes ambient-drift-a {
  0%   { transform: translate(0, 0) scale(1) rotate(0deg); }
  25%  { transform: translate(6vw, 4vh) scale(1.06) rotate(4deg); }
  50%  { transform: translate(2vw, 9vh) scale(0.96) rotate(-3deg); }
  75%  { transform: translate(-5vw, 3vh) scale(1.04) rotate(2deg); }
  100% { transform: translate(0, 0) scale(1) rotate(0deg); }
}
@keyframes ambient-drift-b {
  0%   { transform: translate(0, 0) scale(1) rotate(0deg); }
  30%  { transform: translate(-7vw, 5vh) scale(0.95) rotate(-4deg); }
  60%  { transform: translate(-3vw, -6vh) scale(1.07) rotate(3deg); }
  85%  { transform: translate(4vw, -2vh) scale(0.98) rotate(-2deg); }
  100% { transform: translate(0, 0) scale(1) rotate(0deg); }
}
@keyframes ambient-drift-c {
  0%   { transform: translate(0, 0) scale(1) rotate(0deg); }
  20%  { transform: translate(4vw, -5vh) scale(1.05) rotate(3deg); }
  55%  { transform: translate(-6vw, -2vh) scale(0.94) rotate(-5deg); }
  80%  { transform: translate(-2vw, 6vh) scale(1.03) rotate(2deg); }
  100% { transform: translate(0, 0) scale(1) rotate(0deg); }
}

/* ── responsive ───────────────────────────────────────────────────────── */
@media (max-width: 980px) {
  .intro-grid { grid-template-columns: 1fr; gap: var(--space-4); }
  /* Once About stacks to one column, .intro-photo would otherwise stretch
     to the full section width — constrain it to the image's own scale so
     the organic shape behind it stays proportionate instead of smearing
     into a flat oval. */
  .intro-photo-col { order: -1; max-width: 260px; margin: 0 auto; }
  .intro-photo img { max-width: 220px; }
  .contact-grid { grid-template-columns: 1fr; gap: var(--space-4); }
  .notes-gallery { grid-template-columns: repeat(2, 1fr); }

  /* Ambient background: drop to 4 shapes and a slightly smaller scale on
     tablet so the effect doesn't overwhelm a narrower viewport. */
  .ambient-shape { width: 56vw; height: 56vw; }
  .ambient-shape-5, .ambient-shape-6 { display: none; }
}

@media (max-width: 760px) {
  .nav { display: none; }
  .nav.is-open {
    display: flex;
    position: fixed;
    top: var(--header-h);
    left: 0; right: 0;
    background: var(--bg);
    border-bottom: 1px solid var(--divider);
    flex-direction: column;
    align-items: flex-start;
    padding: var(--space-3) var(--space-4);
    gap: var(--space-3);
    z-index: 19;
  }
  .nav .nav-resume { display: none; }
  .menu-toggle { display: inline-flex; margin-left: auto; }

  .section { padding: var(--space-5) 0; }
  .section-intro { padding-top: var(--space-4); }
  .skills-grid { grid-template-columns: 1fr; }
  h1 { font-size: 30px; }
  .bio-text, .tagline { max-width: none; }

  /* Lab Notes gallery: single column on mobile, full-width comfortable
     thumbnails. */
  .notes-gallery { grid-template-columns: 1fr; }
  .labnotes-intro-card { padding: var(--space-4); }

  /* Ambient background: drop to 3 shapes and a smaller scale on mobile. */
  .ambient-shape { width: 72vw; height: 72vw; filter: blur(10px); }
  .ambient-shape-4 { display: none; }
}

/* ── motion / accessibility ──────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .expand-row__detail { transition: none; }
  .exp-content { transition: none; }
  .exp-content::after { transition: none; }
  .pub-row, .pub-description { transition: none; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .confirm-page { animation: none; opacity: 1; transform: none; }
  .labnotes-back, .labnotes-back-arrow { transition: none; }
  .labnotes-back:hover .labnotes-back-arrow { transform: none; }
  .note-gallery-card { transition: none; }
  .note-gallery-card:hover { transform: none; }
  .icon-link { transition: none; }
  .icon-link:hover { transform: none; }
  .nav-brand { transition: none; }
  .ambient-shape { animation: none; }
  * { scroll-behavior: auto !important; }
}
