/* ============================================================
   BETH ANDERSON — main.css
   Design system + shared styles for every page.

   HOW THIS FILE IS ORGANIZED (search for the numbers):
   01. Design tokens (colors, type, spacing)
   02. Reset + base
   03. Typography helpers
   04. Layout utilities
   05. Header + navigation
   06. Mobile menu
   07. Buttons + text links
   08. Home hero
   09. Marquee strip
   10. Intro / editorial sections
   11. Index list (quick links)
   12. Interior page hero
   13. Resume tables
   14. Gallery + lightbox
   15. Media embeds
   16. Forms
   17. Footer
   18. Reveal animations
   19. Responsive + reduced motion

   ✏️ To change the site's colors or fonts, edit section 01 only.
   ============================================================ */

/* ------------------------------------------------------------
   01. DESIGN TOKENS
   ------------------------------------------------------------ */
:root {
  /* Color — calibrated to Beth's headshot (slate-blue backdrop,
     berry top, chestnut hair). House rule: never straight black or
     straight white anywhere. Keep contrast ratios ≥ 4.5:1. */
  --bone: #f5f0e8;        /* main background — warm ivory */
  --bone-2: #ece4da;      /* alternate section background — warm */
  --mist: #e7ebed;        /* alternate section background — cool blue-gray */
  --ink: #372a28;         /* primary text — warm cocoa (never pure black) */
  --ink-soft: #6b5955;    /* secondary text */
  --espresso: #2a1e21;    /* dark sections + footer — espresso-plum */
  --espresso-2: #342629;  /* dark section alt */
  --rose: #9e3a52;        /* accent — berry, matched to her top */
  /* Sampled straight out of the portrait headshot: the average of the LIT
     areas of her burgundy top (the shadowed folds average far darker and are
     not representative). Used for the hero name on phones, where the name
     sits on the pale blue backdrop instead of over the dark scrim.
     NOTE: --rose above is too light for that job — it only reaches 2.7:1
     against the backdrop, where this reaches 5.9:1. */
  --shirt-berry: #7f1730;
  --rose-deep: #7f2c40;   /* accent hover */
  --rose-light: #c25a72;  /* berry for use on dark/photo backgrounds */
  --slate: #97acb8;       /* dusty blue from the headshot backdrop */
  --slate-deep: #566a77;  /* slate dark enough for small labels on bone */
  --bone-on-dark: #f3ece2;
  --line: rgba(35, 27, 28, 0.16);
  --line-on-dark: rgba(243, 236, 226, 0.22);
  --scrim: rgba(42, 30, 33, 0.86);   /* espresso at depth — gallery hover caption */

  /* Type — Fraunces carries display AND paragraphs (Beth's pick);
     Archivo is reserved for small caps labels, nav, and buttons.
     The hero NAME has its own face: Playfair (her current pick, F3) —
     she also likes Fraunces for it, so that stays the fallback. */
  --font-display: "Fraunces", "Georgia", serif;
  --font-name: "Playfair Display", "Fraunces", "Georgia", serif;
  --font-text: "Fraunces", "Georgia", serif;
  --font-body: "Archivo", "Helvetica Neue", Arial, sans-serif;

  /* Hero name color — oat (C3 on the studio ramp), Beth's pick from
     the warm-ivory-to-champagne range. */
  --name-color: #e0d0ba;

  /* Fluid type scale */
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: clamp(1rem, 0.95rem + 0.2vw, 1.125rem);
  --text-lg: clamp(1.15rem, 1rem + 0.5vw, 1.4rem);
  --text-xl: clamp(1.6rem, 1.2rem + 1.4vw, 2.4rem);
  --text-2xl: clamp(2.2rem, 1.6rem + 2.6vw, 3.6rem);
  --text-hero: clamp(3.2rem, 1.4rem + 9vw, 8.75rem);

  /* Spacing + misc */
  --space-section: clamp(4.5rem, 3rem + 6vw, 9rem);
  --gutter: clamp(1.25rem, 4vw, 3rem);
  --container: 74rem;
  --header-h: 4.75rem;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ------------------------------------------------------------
   02. RESET + BASE
   ------------------------------------------------------------ */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  scroll-behavior: smooth;
}

body {
  font-family: var(--font-text);
  font-size: var(--text-base);
  line-height: 1.65;
  color: var(--ink);
  background: var(--bone);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

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

img {
  height: auto;
}

a {
  color: inherit;
}

::selection {
  background: var(--rose);
  color: var(--bone);
}

:focus-visible {
  outline: 2px solid var(--rose);
  outline-offset: 3px;
}

.skip-link {
  position: absolute;
  top: -100%;
  left: 1rem;
  z-index: 200;
  padding: 0.6rem 1rem;
  background: var(--ink);
  color: var(--bone);
  font-size: var(--text-sm);
  text-decoration: none;
}

.skip-link:focus {
  top: 1rem;
}

/* ------------------------------------------------------------
   03. TYPOGRAPHY HELPERS
   ------------------------------------------------------------ */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 480;
  line-height: 1.08;
  letter-spacing: -0.01em;
}

/* Display classes work on any element, not just headings */
.display-xl,
.display-lg,
.display-md {
  font-family: var(--font-display);
  font-weight: 480;
  line-height: 1.12;
  letter-spacing: -0.01em;
}

.display-xl { font-size: var(--text-hero); }
.display-lg { font-size: var(--text-2xl); }
.display-md { font-size: var(--text-xl); }

.italic {
  font-style: italic;
  font-weight: 420;
}

/* An exclamation mark that follows an italic word. Set in the same italic so
   it leans with the word instead of standing upright against it, with a hair
   of space so it isn't jammed into the last letter. */
.excl {
  font-style: italic;
  font-weight: 420;
  margin-left: 0.09em;
}

/* Small letterspaced caps label — used for eyebrows, nav, taglines */
.eyebrow {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.eyebrow--rose { color: var(--rose); }
.eyebrow--slate { color: var(--slate-deep); }

.lede {
  font-size: var(--text-lg);
  line-height: 1.55;
  color: var(--ink-soft);
}

.measure {
  max-width: 38em;
}

/* ------------------------------------------------------------
   04. LAYOUT UTILITIES
   ------------------------------------------------------------ */
.container {
  width: min(100% - 2 * var(--gutter), var(--container));
  margin-inline: auto;
}

.section {
  padding-block: var(--space-section);
}

.section--alt { background: var(--bone-2); }

/* Cool alternate — the baby-blue/gray from the headshot backdrop */
.section--mist { background: var(--mist); }

.section--dark {
  background: var(--espresso);
  color: var(--bone-on-dark);
}

.section--dark .eyebrow { color: var(--rose); }
.section--dark .lede { color: rgba(241, 234, 223, 0.75); }

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem 2rem;
  margin-bottom: clamp(2rem, 4vw, 3.5rem);
}

.rule {
  border: 0;
  border-top: 1px solid var(--line);
}

/* Offset-frame image — editorial trick: thin frame shifted behind photo */
.framed {
  position: relative;
}

.framed img {
  position: relative;
  z-index: 1;
}

/* Two equal photos in the space a single framed photo used to fill. The
   offset rose outline from .framed wraps the pair, not each photo, so the
   pair still reads as one block. Both images are cropped to the same 4:5
   so they stay the same size whatever their source dimensions. */
.framed-pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(0.6rem, 1.4vw, 1rem);
}

.framed-pair img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
}

/* Photos stacked down a column beside a long text column. The stack stretches
   to the full height of the row and splits it into equal rows, so the last
   photo always finishes level with the last line of text no matter how wide
   the window is or how much copy there is. Each photo is cropped to whatever
   shape that leaves, which is why object-fit: cover matters here.
   The aspect-ratio is only a fallback for when the stack is NOT stretched —
   on phones, where the columns collapse and there is no text to match. */
.framed-stack {
  display: grid;
  /* Roomier than it looks like it needs to be, because each photo now carries
     its own rose frame offset 7px DOWN — at the original 1rem gap the frame
     nearly touched the next picture. This leaves it a clear band to sit in
     without the column turning gappy. */
  gap: clamp(1.1rem, 1.9vw, 1.6rem);
  /* auto rows, not equal fractions — so a photo opted out of the shared crop
     can be taller than the rest instead of forcing every row to its height */
  grid-auto-rows: auto;
}

/* Wrapper around a stacked photo, so a caption can sit over it the way the
   gallery captions do. Carries no look of its own. */
.stack-photo {
  position: relative;
  display: block;
  margin: 0;
  overflow: hidden;
}

/* When a stacked photo carries its own offset rose frame, it must NOT clip:
   .framed::after is drawn 14px outside the photo box, so `overflow: hidden`
   above swallows all of it except the sliver overlapping the picture, and the
   frame reads as a stray hairline instead of a square.
   Safe to drop the clipping here — the hover caption is hidden with opacity
   and only slides 0.5rem from INSIDE the box, so it never depended on it. */
/* ---- A framed photo in the About stack ----------------------------------
   THE FIGURE IS DELIBERATELY TALLER THAN ITS PICTURE ON DESKTOP. The stack's
   rows are stretched so the photo column runs to the same depth as the
   biography beside it (see about.css), while the images keep their own crops —
   so each figure carries a strip of empty space beneath its photo: 21px at
   1280, 42px at 1600. Do not "fix" that; the depth match depends on it.

   The catch is that the frame and the hover caption were both positioned
   against the FIGURE, so both sat in that empty strip instead of on the photo.
   The fix is to lay the figure out as a single grid cell the height of the
   image, and put the picture, the caption and the frame all in it. Any spare
   figure height then falls below the cell, where nothing is anchored. */
.stack-photo.framed {
  overflow: visible; /* the frame is drawn outside the photo box */
  display: grid;
  align-content: start; /* the row is the image's height, not the figure's */
}

.stack-photo.framed > img,
.stack-photo.framed > figcaption,
.stack-photo.framed::after {
  grid-area: 1 / 1;
}

/* static, not absolute: it now belongs to the grid cell (the picture) rather
   than to the figure, so it can never hang below the photo */
.stack-photo.framed > figcaption {
  position: static;
  align-self: end;
}

/* Same, and tighter than the site's usual 14px offset (Beth's call) — five
   frames down one column read as fussy that far off the pictures. The contact
   page and the home pair keep 14px; this is scoped to the stack. */
.stack-photo.framed::after {
  position: static;
  transform: translate(7px, 7px);
}

.framed-stack img {
  /* block, NOT the default inline — an inline image leaves ~6px of line-box
     descender space beneath it, which made the figure taller than the picture.
     Harmless while the figure clipped, but the hover caption sits on the
     figure's bottom edge, so it hung below the photo once clipping came off
     for the frames. Block makes figure height == image height exactly. */
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

/* Opt a photo out of the shared crop so it is shown whole, at its own
   proportions. Use it for shots that lose too much to a 3:2 crop — a tall
   portrait, or anything where the top and bottom of the frame matter. */
.framed-stack img.photo--full {
  aspect-ratio: auto;
  height: auto;
  object-fit: contain;
}

/* A middle setting between the shared 3:2 and the uncropped .photo--full:
   still cropped, but tall enough to keep more of the top and bottom of the
   frame — a sign behind the subject, a face near the edge. */
.framed-stack img.photo--tall {
  aspect-ratio: 1 / 1;
}

/* Move the crop window down the frame, for shots where the subject sits below
   the middle and the default centre crop keeps too much empty space above.
   Not scoped to a section — works on the gallery and the About stack alike,
   since both crop with object-fit: cover. Three steps, so a photo can be
   nudged as much or as little as it needs. */
.photo--focus-low {
  object-position: center 58%;
}

/* Trims noticeable empty space above the subject's head. */
.photo--focus-lower {
  object-position: center 70%;
}

/* Furthest down: keeps the very bottom of the frame — a foot, a hemline. */
.photo--focus-lowest {
  object-position: center 82%;
}

/* Note on why the photos keep a fixed 3:2 rather than stretching to the text:
   at five photos, dividing the text height between them squeezed each one to
   about 2.7:1 on a wide screen — a letterbox slot that would cut the head and
   feet off a portrait. Holding the crop steady instead lets the column run
   past the text, and .split's align-items: center then leaves an equal band
   of space above and below the text. */

.framed::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translate(14px, 14px);
  border: 1px solid var(--rose);
  z-index: 0;
  pointer-events: none;
}

/* ------------------------------------------------------------
   05. HEADER + NAVIGATION
   ------------------------------------------------------------ */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  height: var(--header-h);
  display: flex;
  align-items: center;
  transition: background 0.35s var(--ease), box-shadow 0.35s var(--ease);
}

.site-header.is-scrolled {
  background: rgba(245, 240, 232, 0.92);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  box-shadow: 0 1px 0 var(--line);
}

/* Home page only: the header sits over the hero photo, so its text is
   light until the page scrolls (the hero's top scrim guarantees contrast) */
.site-header--overlay:not(.is-scrolled) {
  color: var(--bone-on-dark);
}

.site-header .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
}

.wordmark {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: clamp(1.2rem, 2.5vw, 2.2rem);
}

.site-nav a {
  position: relative;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
  padding-block: 0.35rem;
}

/* Underline slides in on hover; stays on current page */
.site-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.35s var(--ease);
}

.site-nav a:hover::after,
.site-nav a[aria-current="page"]::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* ------------------------------------------------------------
   06. MOBILE MENU
   ------------------------------------------------------------ */
.menu-toggle {
  display: none;
  z-index: 120;
  background: none;
  border: 0;
  color: inherit; /* buttons don't inherit color by default */
  cursor: pointer;
  /* 2.75rem = 44px, the smallest comfortable touch target on a phone; the
     button used to be 32x29 and was the most-tapped control on the site.
     The bars stay 2rem wide and flush right (align-items: flex-end), so the
     extra area grows leftward/downward and NOTHING moves visually. */
  padding: 0;
  width: 2.75rem;
  min-height: 2.75rem;
  flex-direction: column;
  justify-content: center;
  align-items: flex-end;
}

.menu-toggle span {
  display: block;
  width: 2rem; /* the bars keep their old width, not the button's */
  height: 2px;
  background: currentColor;
  transition: transform 0.3s var(--ease), opacity 0.3s;
}

.menu-toggle span + span {
  margin-top: 6px;
}

body.menu-open .menu-toggle span:first-child {
  transform: translateY(4px) rotate(45deg);
}

body.menu-open .menu-toggle span:last-child {
  transform: translateY(-4px) rotate(-45deg);
}

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 110;
  display: grid;
  place-content: center;
  gap: 0.5rem;
  background: var(--espresso);
  color: var(--bone-on-dark);
  text-align: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.4s var(--ease), visibility 0.4s;
}

body.menu-open .mobile-menu {
  opacity: 1;
  visibility: visible;
}

.mobile-menu a {
  font-family: var(--font-display);
  font-size: clamp(2.2rem, 9vw, 3.4rem);
  text-decoration: none;
  line-height: 1.3;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease), color 0.2s;
}

.mobile-menu a:hover { color: var(--rose); }

body.menu-open .mobile-menu a {
  opacity: 1;
  transform: none;
}

body.menu-open .mobile-menu a:nth-child(1) { transition-delay: 0.08s; }
body.menu-open .mobile-menu a:nth-child(2) { transition-delay: 0.14s; }
body.menu-open .mobile-menu a:nth-child(3) { transition-delay: 0.2s; }
body.menu-open .mobile-menu a:nth-child(4) { transition-delay: 0.26s; }
body.menu-open .mobile-menu a:nth-child(5) { transition-delay: 0.32s; }

body.menu-open {
  overflow: hidden;
}

/* While the menu is open, lift the header above the overlay so the
   wordmark and close button stay visible, and recolor them for the
   dark background */
body.menu-open .site-header {
  z-index: 120;
  background: transparent;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  color: var(--bone-on-dark);
}

/* ------------------------------------------------------------
   07. BUTTONS + TEXT LINKS
   ------------------------------------------------------------ */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.9rem 1.8rem;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
  border: 1px solid var(--ink);
  color: var(--ink);
  background: transparent;
  cursor: pointer;
  transition: background 0.3s var(--ease), color 0.3s var(--ease),
    border-color 0.3s var(--ease);
}

.btn:hover {
  background: var(--ink);
  color: var(--bone);
}

.btn--solid {
  background: var(--ink);
  color: var(--bone);
}

.btn--solid:hover {
  background: var(--rose-deep);
  border-color: var(--rose-deep);
}

.section--dark .btn {
  border-color: var(--bone-on-dark);
  color: var(--bone-on-dark);
}

.section--dark .btn:hover {
  background: var(--bone-on-dark);
  color: var(--espresso);
}

/* Arrow text link */
.arrow-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--rose);
}

.arrow-link .arrow {
  transition: transform 0.3s var(--ease);
}

.arrow-link:hover .arrow {
  transform: translateX(6px);
}

/* ------------------------------------------------------------
   08. HOME HERO — full-bleed photo, name anchored bottom-left
   ------------------------------------------------------------ */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
}

/* The hero photo is wrapped in <picture> so phones get a portrait crop.
   display: contents keeps the wrapper from generating a box of its own, so
   the <img> stays the direct child of .hero exactly as it was before. */
.hero picture {
  display: contents;
}

.hero-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* ✏️ EDIT: if a new hero photo's face sits elsewhere, nudge the
     focal point (x% y%) so the face stays in frame on every screen.
     This one is for the LANDSCAPE photo (desktop); the portrait photo
     phones get has its own focal point in section 19. */
  object-position: 45% 30%;
}

/* Soft gradients top + bottom so the header and name read over any photo */
.hero-scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(
      to bottom,
      rgba(26, 16, 19, 0.48) 0%,
      rgba(26, 16, 19, 0) 24%
    ),
    linear-gradient(
      to top,
      rgba(26, 16, 19, 0.74) 0%,
      rgba(26, 16, 19, 0.32) 36%,
      rgba(26, 16, 19, 0) 62%
    );
}

/* Content sits bottom-RIGHT (her placement pick, E) in a 36rem column */
.hero-content {
  position: relative;
  z-index: 2;
  color: var(--bone-on-dark);
  padding-block: clamp(3rem, 9vh, 6rem);
  max-width: 36rem;
  margin-left: auto;
  margin-right: max(var(--gutter), (100% - var(--container)) / 2);
  text-align: right;
}

.hero-content .eyebrow {
  color: rgba(243, 236, 226, 0.78);
}

/* ✏️ EDIT: "Musical Theatre Performer" — desktop only (below 901px the
   billing line replaces it). It is already flush to the right gutter, so the
   only way to keep it off Beth's face is to make the LINE shorter, which
   moves its left edge right.

   Measured against the actual edge of her hair in the hero photo, row by row:
   at the house 0.32em tracking and 12px it ran 287px wide and OVERLAPPED her
   hair by 29px at a 1024px window, with only 29px to spare at 1920. Tighter
   tracking and a hair's-breadth smaller type bring it to ~232px, which clears
   her at every width. If the wording ever gets longer, re-check this. */
.hero-content > .eyebrow:not(.hero-tagline) {
  font-size: 0.6875rem;
  letter-spacing: 0.2em;
}

.hero-name {
  font-family: var(--font-name);
  font-size: var(--text-hero);
  font-weight: 460;
  line-height: 0.98;
  letter-spacing: -0.02em;
  color: var(--name-color);
  margin: 1rem 0 1.4rem;
}

.hero-name .line-2 {
  display: block;
  font-style: italic;
  font-weight: 400;
  color: var(--name-color);
  /* Stacked flush — Beth prefers the lines aligned, not offset */
  margin-left: 0;
}

.hero-tagline {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 1.2rem;
  margin-bottom: 2.2rem;
}

.hero-tagline::before,
.hero-tagline::after {
  content: "";
  height: 1px;
  width: clamp(1.5rem, 4vw, 3.5rem);
  background: var(--line-on-dark);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 1rem;
}

/* Review badge under the hero buttons — links to #praise */
.hero-badge {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.3rem;
  margin-top: 1.9rem;
  text-decoration: none;
  color: rgba(243, 236, 226, 0.88);
}

.hero-badge .badge-line {
  display: inline-flex;
  align-items: baseline;
  gap: 0.7rem;
}

/* Tiny "it's clickable" hint — informative, never attention-grabbing */
.hero-badge .badge-cta {
  font-family: var(--font-body);
  font-size: 0.65rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(243, 236, 226, 0.42);
  transition: color 0.3s var(--ease);
}

.hero-badge:hover .badge-cta {
  color: rgba(243, 236, 226, 0.7);
}

.hero-badge .quote {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--text-lg);
  transition: color 0.3s var(--ease);
}

.hero-badge .src {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(243, 236, 226, 0.62);
}

.hero-badge:hover .quote {
  color: var(--name-color);
}

/* Hero buttons sit on the photo — bone outlines, invert on hover */
.hero .btn {
  border-color: var(--bone-on-dark);
  color: var(--bone-on-dark);
  background: transparent;
}

.hero .btn:hover {
  background: var(--bone-on-dark);
  color: var(--espresso);
}

.hero-scroll {
  position: absolute;
  bottom: 1.8rem;
  left: var(--gutter); /* content now sits right — cue moves left */
  z-index: 3;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  letter-spacing: 0.3em;
  text-transform: uppercase;
  text-decoration: none;
  color: rgba(243, 236, 226, 0.75);
}

.hero-scroll::after {
  content: "";
  width: 1px;
  height: 2.4rem;
  background: rgba(243, 236, 226, 0.75);
  animation: scroll-pulse 2.2s var(--ease) infinite;
}

@keyframes scroll-pulse {
  0% { transform: scaleY(0); transform-origin: top; }
  45% { transform: scaleY(1); transform-origin: top; }
  55% { transform: scaleY(1); transform-origin: bottom; }
  100% { transform: scaleY(0); transform-origin: bottom; }
}

/* Subtle film-grain overlay on the hero */
.grain::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  opacity: 0.5;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ------------------------------------------------------------
   09. MARQUEE STRIP
   ------------------------------------------------------------ */
.marquee {
  border-block: 1px solid var(--line);
  padding-block: 1.1rem;
  overflow: hidden;
  white-space: nowrap;
}

.marquee-track {
  display: inline-flex;
  animation: marquee 38s linear infinite;
}

.marquee-track span {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--text-lg);
  color: var(--ink-soft);
  padding-right: 1.2rem;
}

.marquee-track .sep {
  color: var(--rose);
}

/* Scroll by exactly one of the six copies, then snap back. Because the five
   remaining copies are always wider than the screen, the strip never runs out
   of text and the reset is invisible — the loop reads as continuous.
   If you change the number of copies in index.html, change this to
   -100% divided by that number. */
@keyframes marquee {
  to { transform: translateX(-16.6667%); }
}

/* ------------------------------------------------------------
   10. INTRO / EDITORIAL SECTIONS
   ------------------------------------------------------------ */
.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2.5rem, 6vw, 5.5rem);
  align-items: center;
}

.split--offset {
  align-items: start;
}

.pull-quote {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: var(--text-xl);
  line-height: 1.25;
  color: var(--ink);
  margin-block: 1.2rem 1.6rem;
}

.stack > * + * {
  margin-top: 1.1rem;
}

.stack .btn,
.stack .arrow-link {
  margin-top: 2rem;
}

/* Both are inline, so a button and an arrow link inside a .stack land on the
   same line with almost nothing between them (the thank-you page does this).
   Give the link room to breathe beside the button. */
.stack .btn + .arrow-link {
  margin-left: 1.5rem;
}

/* The greeting under the home mission statement. Still an eyebrow — small
   caps, letterspaced — but set larger so it holds its own beneath the big
   italic quote instead of reading as a caption. */
.intro-welcome {
  font-size: var(--text-base);
  letter-spacing: 0.26em;
  color: var(--rose);
  margin-top: 1.6rem;
}

/* Home intro. The mission statement spans the full width above the two
   columns — it keeps its place at the top of the section but reads centred
   rather than pinned to the left edge. */
/* Small label naming the italic line beneath it. Centred to sit on the same
   axis, and close to the quote so the two read as one unit rather than as a
   heading with a gap under it. */
.intro-mission-label {
  text-align: center;
  margin-bottom: 0.9rem;
}

.intro-mission {
  text-align: center;
  max-width: 34ch;
  margin-inline: auto;
  margin-bottom: clamp(2.2rem, 4vw, 3.4rem);
}

/* ✏️ EDIT: the home page shows only the OPENING of the mission statement —
   the full sentence lives in the About biography (paragraph 3). This ellipsis
   is what signals the quote carries on; tinting it rose stops it reading as a
   stray typo and ties it to the rose label above. The onward link is the
   existing "Read my full story" at the foot of the column below, so there is
   deliberately no second link to About here. */
.mission-more {
  color: var(--rose);
  letter-spacing: 0.05em; /* a little air before the closing quote mark */
}

/* With the statement lifted out, the left column is just the greeting, the
   bio and the link — so the photos centre against it cleanly. */
#intro .split {
  align-items: center;
}

/* On desktop the photos take the larger share. The text column gains nothing
   from extra width — .measure caps a readable line at 38em — so handing the
   surplus to the pictures makes them noticeably bigger for free. */
@media (min-width: 901px) {
  #intro .split {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.45fr);
  }
}

#intro .framed-pair img {
  aspect-ratio: 3 / 4;
}

/* Praise / review block (home) */
.praise {
  max-width: 46rem;
  margin-inline: auto;
  text-align: center;
}

.praise-quote {
  font-size: var(--text-xl);
  margin-block: 1.4rem 1.8rem;
}

/* The full review, smaller, under the featured line */
.praise-full {
  color: var(--ink-soft);
  margin-bottom: 1.8rem;
  margin-inline: auto;
}

.praise-source {
  display: grid;
  gap: 0.15rem;
  justify-items: center;
}

.praise-source .name {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

.praise-source .publication {
  font-style: italic;
  color: var(--slate-deep);
  font-size: var(--text-sm);
}

/* Link back up to the short bio. .praise is centred text, but arrow-link is
   inline-flex, so it needs its own centring. */
.praise-link {
  margin-top: 2rem;
}

/* Facts list (About page sidebar) */
.facts {
  list-style: none;
}

.facts li {
  display: flex;
  justify-content: space-between;
  gap: 1.5rem;
  padding-block: 0.85rem;
  border-bottom: 1px solid var(--line);
  font-size: var(--text-sm);
}

.facts .label {
  font-family: var(--font-body);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-size: var(--text-xs);
  color: var(--slate-deep);
  flex-shrink: 0;
}

.facts .value {
  text-align: right;
  /* Caps how wide any one value can run, so a long entry (the degree +
     minors line) wraps into a compact two-line block instead of stretching
     far past the short values above and below it. The ch cap keeps the
     wrap point steady as the window resizes; the 60% keeps the value off
     the label on narrow screens. Short values are unaffected. */
  max-width: min(34ch, 60%);
}

/* ------------------------------------------------------------
   11. INDEX LIST (quick links, table-of-contents treatment)
   ------------------------------------------------------------ */
.index-list {
  list-style: none;
  border-top: 1px solid var(--line);
}

.index-list a {
  display: grid;
  grid-template-columns: 3.5rem 1fr auto;
  align-items: center;
  gap: 1.5rem;
  padding: 1.6rem 0.5rem;
  border-bottom: 1px solid var(--line);
  text-decoration: none;
  transition: background 0.3s var(--ease), padding 0.3s var(--ease);
}

.index-list .num {
  font-family: var(--font-display);
  font-style: italic;
  color: var(--rose);
  font-size: var(--text-base);
}

.index-list .label {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  line-height: 1.1;
}

.index-list .arrow {
  font-size: var(--text-lg);
  transition: transform 0.3s var(--ease);
}

.index-list a:hover {
  background: var(--bone-2);
  padding-inline: 1.2rem 0.8rem;
}

.index-list a:hover .arrow {
  transform: translateX(6px);
}

/* ------------------------------------------------------------
   12. INTERIOR PAGE HERO
   ------------------------------------------------------------ */
.page-hero {
  padding-top: calc(var(--header-h) + clamp(3rem, 8vw, 6rem));
  padding-bottom: clamp(2.5rem, 5vw, 4.5rem);
}

.page-hero h1 {
  font-size: var(--text-2xl);
  margin-top: 0.9rem;
}

/* Every interior page headline gets one rosewood italic accent word —
   mirrors the italic surname on the home hero. */
.page-hero h1 em {
  font-style: italic;
  color: var(--rose);
}

.page-hero .lede {
  margin-top: 1.2rem;
}

/* ------------------------------------------------------------
   13. RESUME TABLES
   ------------------------------------------------------------ */
.resume-section {
  margin-bottom: clamp(2.8rem, 5vw, 4.5rem);
}

.resume-section h2 {
  font-size: var(--text-xl);
  font-style: italic; /* Beth loves the italic display headings — use them */
  margin-bottom: 1.4rem;
}

.credits {
  width: 100%;
  border-collapse: collapse;
  border-top: 1px solid var(--line);
}

.credits th,
.credits td {
  text-align: left;
  vertical-align: top;
  padding: 0.95rem 1rem 0.95rem 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--text-sm);
}

.credits th {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.credits td:first-child {
  font-family: var(--font-display);
  font-size: var(--text-base);
}

.credits .role {
  font-style: italic;
  color: var(--ink-soft);
}

.skills-list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

.skills-list li {
  padding: 0.45rem 1rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

/* ------------------------------------------------------------
   14. GALLERY + LIGHTBOX
   ------------------------------------------------------------ */
.gallery {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(0.8rem, 2vw, 1.6rem);
}

.gallery a {
  display: block;
  overflow: hidden;
  position: relative;
}

/* Caption that fades up over a gallery photo. Hidden until the photo is
   hovered or keyboard-focused; on touch screens (no hover) it stays visible,
   so the information is never locked behind a gesture that doesn't exist.
   aria-hidden in the markup keeps screen readers on the fuller alt text. */
.gallery-caption {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  padding: 2.4rem 0.9rem 0.9rem;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-align: center;
  color: var(--bone-on-dark);
  /* Three stops rather than two: the scrim reaches useful darkness by the time
     it is behind the text, instead of still fading in. A single
     scrim-to-transparent ramp left captions unreadable over pale photos. */
  background: linear-gradient(to top, var(--scrim) 0%, rgba(42, 30, 33, 0.62) 55%, transparent 100%);
  text-shadow: 0 1px 3px rgba(42, 30, 33, 0.55);
  pointer-events: none;
  /* .framed img sets z-index: 1, so without this the photo paints over the
     caption and it never appears in the About page stack. */
  z-index: 2;
}

.gallery-caption em {
  font-family: var(--font-display);
  font-style: italic;
  text-transform: none;
  letter-spacing: 0.04em;
  font-size: 1.15em;
}

/* For a caption that is a sentence rather than a label. Small caps and wide
   tracking are fine for "Grease · Marty" but punishing to read across three
   lines, so this sets in normal case at reading size. */
.gallery-caption--long {
  text-transform: none;
  letter-spacing: 0.01em;
  font-family: var(--font-text);
  font-size: var(--text-sm);
  line-height: 1.5;
  padding-top: 3rem;
}

@media (hover: hover) {
  .gallery-caption {
    opacity: 0;
    transform: translateY(0.5rem);
    transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
  }

  .gallery a:hover .gallery-caption,
  .gallery a:focus-visible .gallery-caption,
  .stack-photo:hover .gallery-caption {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .gallery-caption {
    transition-duration: 0.01ms;
    transform: none;
  }
}

.gallery img,
.gallery svg {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  transition: transform 0.6s var(--ease);
}

.gallery a:hover img,
.gallery a:hover svg {
  transform: scale(1.04);
}

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 150;
  display: none;
  place-items: center;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(33, 27, 22, 0.94);
}

.lightbox.is-open {
  display: grid;
}

.lightbox img {
  max-height: 85svh;
  max-width: 100%;
  object-fit: contain;
}

.lightbox-close {
  position: absolute;
  top: 1.2rem;
  right: 1.6rem;
  background: none;
  border: 0;
  color: var(--bone-on-dark);
  font-size: 2rem;
  line-height: 1;
  cursor: pointer;
}

.lightbox-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: 0;
  color: var(--bone-on-dark);
  font-size: 2.4rem;
  cursor: pointer;
  padding: 1rem;
}

.lightbox-nav.prev { left: 0.5rem; }
.lightbox-nav.next { right: 0.5rem; }

/* ------------------------------------------------------------
   15. MEDIA EMBEDS
   ------------------------------------------------------------ */
.reel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 26rem), 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem);
}

.reel {
  display: grid;
  gap: 0.9rem;
}

.reel-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--espresso);
  overflow: hidden;
}

.reel-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Placeholder state before a real video is embedded */
.reel-frame.is-placeholder {
  display: grid;
  place-content: center;
  gap: 0.8rem;
  justify-items: center;
  color: var(--bone-on-dark);
}

.reel-frame.is-placeholder .play-badge {
  width: 3.6rem;
  height: 3.6rem;
  border: 1px solid var(--line-on-dark);
  border-radius: 999px;
  display: grid;
  place-content: center;
  font-size: 1rem;
}

/* Sign-off line above the closing link on the reels page. Bigger than a
   normal eyebrow so it reads as a message rather than a label, with room
   above it so it separates from the last reel's description. */
.reels-signoff {
  margin-top: clamp(2.5rem, 6vw, 4.5rem);
  font-size: var(--text-lg);
  letter-spacing: 0.14em;
  color: var(--ink);
}

.reel h3 {
  font-size: var(--text-lg);
}

.reel .note {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

/* ------------------------------------------------------------
   16. FORMS
   ------------------------------------------------------------ */
.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.4rem;
}

.form-grid .full {
  grid-column: 1 / -1;
}

.field label {
  display: block;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 0.5rem;
}

.field input,
.field textarea {
  width: 100%;
  padding: 0.85rem 1rem;
  font: inherit;
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--line);
  transition: border-color 0.3s var(--ease);
}

.field input:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--rose);
}

.field textarea {
  min-height: 10rem;
  resize: vertical;
}

/* ------------------------------------------------------------
   17. FOOTER
   ------------------------------------------------------------ */
.site-footer {
  background: var(--espresso);
  color: var(--bone-on-dark);
  /* extra bottom padding leaves room for the verse tooltip, which opens
     downward from the reference in the meta row */
  padding-block: var(--space-section) 5rem;
  /* Backstop against a horizontal scrollbar. Both footer tooltips are
     absolutely positioned and sit outside the flow, but they still count
     toward the page's scroll width even while hidden — on narrow screens
     that put a sideways scroll on every page. clip (not hidden) leaves the
     vertical axis alone, so the verse still opens down into the padding. */
  overflow-x: clip;
}

.footer-cta {
  text-align: center;
  margin-bottom: clamp(3rem, 6vw, 5rem);
}

.footer-cta .display-lg {
  margin-block: 0.8rem 2rem;
}

.footer-cta .display-lg em {
  color: var(--rose);
}

.footer-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
  padding-top: 1.8rem;
  border-top: 1px solid var(--line-on-dark);
  font-size: var(--text-sm);
  color: rgba(241, 234, 223, 0.65);
}

/* The scripture reference reveals the verse beneath it on hover, or on
   keyboard focus — the reference is focusable so it isn't mouse-only. */
.footer-verse {
  position: relative;
}

.verse-ref {
  cursor: help;
  border-bottom: 1px dotted var(--line-on-dark);
}

.verse-text {
  position: absolute;
  top: calc(100% + 0.6rem);
  left: 50%;
  transform: translateX(-50%) translateY(-0.3rem);
  width: max-content;
  max-width: min(24rem, 80vw);
  font-size: var(--text-xs);
  font-style: italic;
  line-height: 1.55;
  text-align: center;
  color: rgba(241, 234, 223, 0.8);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
}

.footer-verse:hover .verse-text,
.footer-verse:focus-within .verse-text {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .verse-text { transition-duration: 0.01ms; transform: translateX(-50%); }
}

.footer-social {
  display: flex;
  /* The links below are now 2.75rem boxes, which carry most of the spacing
     themselves. 0.5rem + the 1.4rem of padding inside the two neighbouring
     boxes = the same 1.9rem of daylight between icons as the old
     1.6rem gap + 0.15rem padding. The row looks identical. */
  gap: 0.5rem;
  list-style: none;
}

/* Icons, not words. The contact page already used this treatment for the
   same two links; the footer now matches it everywhere. */
/* The box is 2.75rem (44px) so the icons are comfortably tappable on a
   phone — three 26px targets this close together were easy to miss. The
   icon itself is unchanged and centred, so nothing looks different. */
.footer-social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  text-decoration: none;
  transition: color 0.2s;
}

/* Actors Access has no public icon of its own, so this is a generic
   casting-profile mark — a headshot beside resume lines — drawn to match the
   other two icons rather than imitating their logo. */

.footer-aa {
  position: relative;
}

/* Names the icon on hover or keyboard focus, since the mark alone doesn't
   say "Actors Access" the way the Instagram and YouTube ones do. It opens
   UPWARD — the verse tooltip already uses the space below the footer row. */
/* Anchored to the icon's RIGHT edge, not centred on it. Actors Access is the
   last icon in the row, so a centred tooltip — 'ACTORS ACCESS PROFILE' is
   ~190px of nowrap text — hung off the right of the viewport and put a
   horizontal scrollbar on every page between roughly 700px and 1000px wide.
   Opening leftward from the icon it always has room.

   It is also hidden outright where there is no hover: on a phone it cannot be
   triggered, and at ~335px it is wider than the space either side of the icon,
   so leaving it in the layout only put the scrollbar back. The link keeps its
   aria-label, so screen readers still announce what the icon is. */
.icon-tip {
  display: none;
  position: absolute;
  bottom: calc(100% + 0.55rem);
  right: 0;
  transform: translateY(0.3rem);
  width: max-content;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(241, 234, 223, 0.85);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}

@media (hover: hover) {
  .icon-tip { display: block; }
}

/* Hover, plus KEYBOARD focus only. :focus-within was wrong: clicking the icon
   opens Actors Access in a new tab and leaves the link holding focus, so
   coming back to the page you found the tooltip stuck open until you clicked
   somewhere else. :focus-visible does not match a mouse click, so the label
   now behaves the way it reads — it appears while you are pointing at the
   icon, and for anyone tabbing to it. */
.footer-aa:hover .icon-tip,
.footer-aa:has(a:focus-visible) .icon-tip {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .icon-tip { transition-duration: 0.01ms; transform: none; }
}

.footer-social svg {
  width: 1.35rem;
  height: 1.35rem;
  transition: color 0.2s, transform 0.3s var(--ease);
}

.footer-social a:hover svg,
.footer-social a:focus-visible svg {
  color: var(--rose-light);
  transform: translateY(-2px);
}

/* Quiet verse line, centred in the footer meta row. Deliberately carries no
   styling of its own — it inherits .footer-meta so it matches the copyright
   line exactly in font, size, and colour. */

/* Credit tables — used on the resume page and the About page, so these
   live here rather than in a page stylesheet. */
/* Keep all credit columns readable: on narrow screens the table
   scrolls inside its own box. tabindex on the wrapper lets keyboard
   users scroll it too. */
/* On a phone the four credit columns are twice the width of the screen
   (704px of table in a 350px box), and a bare scrollbox gives no sign that
   anything is out there — half of Beth's credits were effectively invisible
   to anyone reading on their phone.

   Four background layers make the edges fade so it reads as scrollable:
   the two "cover" gradients are attached `local`, so they travel WITH the
   table and sit over whichever end you are currently at; the two shadows are
   attached `scroll`, so they stay pinned to the visible edges. The result is
   a soft shadow on whichever side still has content beyond it, and none once
   you reach that end. No JS, and it simply doesn't paint on browsers that
   ignore background-attachment.

   Painted in --bone because every credit table on the site sits on it
   (verified on both resume.html and about.html). If a table is ever moved
   onto a different background, these two colours have to change with it. */
.table-scroll {
  overflow-x: auto;
  background:
    linear-gradient(to right, var(--bone) 30%, rgba(245, 240, 232, 0)) left center,
    linear-gradient(to left, var(--bone) 30%, rgba(245, 240, 232, 0)) right center,
    radial-gradient(farthest-side at 0% 50%, rgba(55, 42, 40, 0.22), rgba(55, 42, 40, 0)) left center,
    radial-gradient(farthest-side at 100% 50%, rgba(55, 42, 40, 0.22), rgba(55, 42, 40, 0)) right center;
  background-repeat: no-repeat;
  background-size: 3rem 100%, 3rem 100%, 1.15rem 100%, 1.15rem 100%;
  background-attachment: local, local, scroll, scroll;
}

.table-scroll .credits {
  min-width: 44rem; /* four columns need more room than three */
}

/* Section heading with a second line beside it: the title sits left, the
   italic line sits right, both on the same baseline. Wraps to two rows on
   narrow screens rather than squashing. */
.resume-section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.3rem 1.5rem;
  margin-bottom: 1.4rem;
}

/* .resume-section h2 carries the spacing normally — inside this row the flex
   gap does it instead. */
.resume-section-head h2 {
  margin-bottom: 0;
}

/* Smaller than the heading it sits beside, so it reads as a subtitle. */
.resume-subhead {
  margin: 0;
  font-size: var(--text-lg);
  text-align: right;
  color: var(--ink-soft);
}

/* The "Resident Company Member" line above the regional table */
.resume-highlight {
  font-style: italic;
  color: var(--rose);
  margin-bottom: 1.2rem;
}

/* ------------------------------------------------------------
   18. REVEAL ANIMATIONS
   ------------------------------------------------------------ */
.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.9s var(--ease), transform 0.9s var(--ease);
}

.reveal.is-visible {
  opacity: 1;
  transform: none;
}

.reveal[data-delay="1"] { transition-delay: 0.12s; }
.reveal[data-delay="2"] { transition-delay: 0.24s; }
.reveal[data-delay="3"] { transition-delay: 0.36s; }

/* ------------------------------------------------------------
   19. RESPONSIVE + REDUCED MOTION
   ------------------------------------------------------------ */
@media (max-width: 900px) {
  .site-nav { display: none; }
  /* flex, not block — it centres the bars inside the 44px touch target */
  .menu-toggle { display: flex; }

  /* ---- Home hero, small screens only (Beth's call, 2026-08-03) ----
     The three buttons come out and everything left moves up into the clear
     blue backdrop in the top-right corner, instead of sitting at the bottom
     across her hair. Desktop keeps the buttons and the bottom-right block —
     none of this applies above 900px. Phone visitors still reach Resume,
     Headshot and Reels through the menu. */
  .hero {
    align-items: flex-start;
  }

  .hero-actions {
    display: none;
  }

  .hero-content {
    /* flex column purely so the billing line can be reordered above the
       name below; stretch alignment keeps the children full width, so
       text-align: right still does the aligning exactly as before */
    display: flex;
    flex-direction: column;
    /* clears the fixed header, then sits as high as it can */
    padding-top: calc(var(--header-h) + 0.2rem);
    padding-bottom: 0;
    /* Extra inset from the screen edge. The block is right-aligned, so its
       right edge always lands on the gutter no matter how big the type is —
       and once the name became one long line, a bare 20px gutter made it
       read as though it ran off the screen. This pulls it in to ~34px. */
    padding-right: 0.9rem;
  }

  /* ✏️ EDIT: on phones "Musical Theatre Performer" comes out and the
     Dancer · Singer · Actor line takes its place above the name (Beth's
     call). Same element as the desktop billing line, just moved with
     `order` — no duplicated words to keep in sync. The :not() matters:
     .hero-tagline also carries .eyebrow, so a bare .eyebrow would hide it. */
  .hero-content > .eyebrow:not(.hero-tagline) {
    display: none;
  }

  .hero-tagline {
    order: -1;
    margin: 0 0 0.8vh;
    gap: 0.8rem;
  }

  /* The flanking rules are dropped on phones: they added ~90px of width to
     the billing line, which made the block sprawl across the screen instead
     of reading as one cluster in the corner. */
  .hero-tagline::before,
  .hero-tagline::after {
    display: none;
  }

  /* THE GAPS AND THE NAME ARE SIZED IN vh ON PURPOSE — do not convert them
     back to rem. Her face sits at a fixed FRACTION of the screen height
     (hair starts at 28.6% of it, eyes at 43.6%), so on a short phone the
     face rides up while rem-sized text stays put and lands on it. Sizing in
     vh makes the block shrink with the screen and keeps the clearance.

     These numbers are TUNED, not guessed: they are the largest that still
     fit the whole block — billing, name and review badge — in the clear
     backdrop ABOVE her hair, at every screen from 320x568 up. Enlarging the
     name or the gaps pushes the badge onto her head again. */

  /* ✏️ EDIT: on phones the name runs on ONE line — "Beth Anderson" — instead
     of stacking. Stacked, two lines forced the type down to ~36px to fit
     above her head; on one line it fits at ~53px, so the name reads far
     bigger AND the block is shorter. "Anderson" keeps its italic. */
  .hero-name .line-2 {
    display: inline;
    /* "Anderson" hard-codes --name-color in section 08, so without this it
       stays oat while "Beth" turns berry. Inherit instead. */
    color: inherit;
  }

  /* Width is the binding constraint now, not height: "Beth Anderson" renders
     6.125x the font size wide, and the column is the screen minus gutters,
     so ~13.5vw is the point where it would start wrapping (measured, down to
     320px) — the value below sits under that on purpose, for visible margin.
     The 9vh cap stops a sideways phone — where vw is huge but there is no
     height — from blowing the name up. If it EVER wraps back to two lines
     the block gets ~50px taller and lands on her face, so keep the 13.5. */
  .hero-name {
    /* 12.2vw leaves visible slack on BOTH sides rather than filling the
       column edge to edge — at 13.5vw the name technically fitted, but ran
       so close to the screen that it read as cut off. 9vh keeps a sideways
       phone sane; 5.6rem stops it outgrowing the 36rem text column on a big
       tablet. */
    font-size: min(12.2vw, 9vh, 5.6rem);
    margin: 0 0 0.9vh;
    white-space: nowrap;
    /* ✏️ EDIT: the berry of her top, on phones only (Beth's pick).
       Desktop keeps the oat --name-color, where the name sits over the
       dark bottom scrim and a light colour is what reads. */
    color: var(--shirt-berry);
  }

  /* ---- OAT TEXT ON A PALE BACKDROP: IT NEEDS THE SHADOW TO SURVIVE ----
     Beth wants the oat/cream of the desktop hero on everything except the
     name. On its own that colour manages only ~1.5:1 against the pale blue
     backdrop up here — which is exactly why she said the review was hard to
     read. Two things make it work without changing the colour:

       1. a soft dark shadow, so each line carries its own contrast with it;
       2. the two faintest lines brought up toward full opacity (they were
          0.62 and 0.42 — fine over the dark scrim at the bottom of the photo
          on desktop, far too weak over pale blue).

     DO NOT "fix" this instead by darkening the scrim. A scrim heavy enough
     to carry cream text would drop the berry NAME from 4.3:1 to about
     1.7:1 — it would bury the one thing she likes most. The pale backdrop is
     what the berry needs; the shadow is what the cream needs. */
  .hero-content > .eyebrow,
  .hero-badge {
    color: var(--bone-on-dark);
  }

  .hero-badge .src {
    color: var(--bone-on-dark);
  }

  .hero-badge .badge-cta {
    color: rgba(243, 236, 226, 0.86);
  }

  /* KEEP THE BLUR TIGHT. The wide halo is what makes oat read as grey: at
     these small sizes a 14px glow bleeds across the thin strokes themselves
     and the eye mixes the two into a dull grey. A short, low-alpha shadow
     sits just OUTSIDE the letterforms, so it still lifts them off the pale
     backdrop but the colour stays oat. If it ever looks grey again, cut the
     second radius before touching the colours. */
  .hero-content > .eyebrow,
  .hero-badge .quote,
  .hero-badge .src,
  .hero-badge .badge-cta {
    text-shadow:
      0 1px 2px rgba(26, 16, 19, 0.42),
      0 0 6px rgba(26, 16, 19, 0.26);
  }

  .hero-badge {
    margin-top: 0.9vh;
    gap: 0.1rem;
  }

  /* Badge text scaled down to match the smaller name, so the three lines
     read as one tight group rather than three unrelated sizes. */
  .hero-badge .quote {
    font-size: 1rem;
  }

  .hero-badge .src {
    font-size: 0.58rem;
  }

  .hero-badge .badge-cta {
    font-size: 0.55rem;
  }

  /* ✏️ EDIT: focal point for the PORTRAIT hero photo (phones + portrait
     tablets). The 85% is doing real work: on a phone the photo is ~172px
     wider than the screen, and taking most of that off the LEFT pushes Beth
     to the left of the frame, which is what clears the right-hand column
     where the name and buttons sit. Lower it and the text lands on her face
     again. On a portrait tablet the photo fits the width exactly, so there
     is no horizontal slack and only the 25% applies — it trims the crop from
     the top so her face stays high. */
  .hero-bg {
    object-position: 85% 25%;
  }

  .hero-scroll { display: none; }

  .split {
    grid-template-columns: 1fr;
  }

  .gallery {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .form-grid {
    grid-template-columns: 1fr;
  }
}

/* ---- TABLETS: mobile's PLACEMENT, desktop's COLOURS (Beth's call) ----
   The block keeps everything the mobile rules did about where the text sits
   — top-right, no buttons, billing line above the name, name on one line —
   and puts the desktop treatment back on top of it: oat name, the original
   cream opacities, no text-shadow, and the rules either side of the billing
   line.

   Gated on HEIGHT as well as width on purpose. A phone held sideways is
   ~844px wide, which is "tablet" by width alone; the min-height keeps it on
   the phone treatment where it belongs. */
@media (min-width: 601px) and (max-width: 900px) and (min-height: 700px) {
  .hero-name,
  .hero-name .line-2 {
    color: var(--name-color);
  }

  .hero-content > .eyebrow {
    color: rgba(243, 236, 226, 0.78);
  }

  .hero-badge {
    color: rgba(243, 236, 226, 0.88);
  }

  .hero-badge .src {
    color: rgba(243, 236, 226, 0.62);
  }

  .hero-badge .badge-cta {
    color: rgba(243, 236, 226, 0.42);
  }

  .hero-content > .eyebrow,
  .hero-badge .quote,
  .hero-badge .src,
  .hero-badge .badge-cta {
    text-shadow: none;
  }

  /* the hairlines either side of Dancer · Singer · Actor come back */
  .hero-tagline {
    gap: 1.2rem;
  }

  .hero-tagline::before,
  .hero-tagline::after {
    display: block;
  }

  /* THE SCRIM IS WHAT MAKES THE DESKTOP COLOURS POSSIBLE HERE — it is not
     decoration. Desktop's oat/cream works because desktop's text sits at the
     BOTTOM of the photo over a 0.74 scrim. Put those same colours on the
     PALE BLUE at the top and they measure 1.2–2.4:1: the name barely shows
     and "click for the full review" is invisible. Deepening the top scrim
     over the text band restores the same relationship desktop has, and takes
     every line back over 4.5:1.

     This is only safe on TABLET, where the name is oat. Do NOT copy it to
     the phone block — there the name is berry, and a scrim this heavy would
     drop it to ~1.7:1 and bury it. Phones use a text-shadow instead. */
  .hero-scrim {
    background:
      linear-gradient(
        to bottom,
        rgba(26, 16, 19, 0.68) 0%,
        rgba(26, 16, 19, 0.58) 24%,
        rgba(26, 16, 19, 0) 46%
      ),
      linear-gradient(
        to top,
        rgba(26, 16, 19, 0.74) 0%,
        rgba(26, 16, 19, 0.32) 36%,
        rgba(26, 16, 19, 0) 62%
      );
  }
}

/* Short screens — iPhone SE, small Androids, and any phone held sideways.
   Above, the hero text is kept clear of Beth's face by shrinking with the
   viewport, but below roughly 700px tall the maths runs out: the clean
   backdrop above her head is only ~107px once the header is subtracted,
   which is barely her name. So the review badge steps aside here rather
   than sitting across her eyes. NOTHING IS LOST — the same review appears
   in full in the Praise section immediately below the hero. */
@media (max-width: 900px) and (max-height: 700px) {
  .hero-badge {
    display: none;
  }
}

@media (max-width: 520px) {
  .index-list a {
    grid-template-columns: 2.2rem 1fr auto;
    gap: 0.9rem;
  }
}

/* Signpost on the About page — see the comment in about.html. Shown at 900px
   and under, which is exactly where the biography stacks BELOW the five
   photos; above that the writing sits beside them and there is nothing to
   miss. (It started phones-only; Beth extended it to tablets once it was
   pointed out that an iPad stacks the same way.) Hidden by default so it can
   never appear on the layouts that don't need it, including if this
   stylesheet is ever served stale against new html. */
.scroll-note {
  display: none;
}

@media (max-width: 900px) {
  .scroll-note {
    display: block;
    margin-top: 1.6rem;
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--rose);
  }
}

/* ---- FOOTER ON PHONES (Beth's layout, 2026-08-03) ----
   Copyright on the left, the social icons in the RIGHT corner where the
   Romans 11:36 reference used to sit, and the reference with the verse
   quoted straight after it on its own row underneath.

   The verse is ordinary text down here, not a hover tooltip. That is the
   point of the change and it also retires a bug: as a tooltip it was
   centred on the reference, so once this row wrapped it hung ~90px past the
   footer and `.site-footer`'s `overflow-x: clip` sliced the verse
   mid-sentence. Nothing is positioned any more, so nothing can be clipped.
   (Keep that `overflow-x: clip` — it is what stops the tooltips putting a
   horizontal scrollbar on every page. Desktop still uses the tooltip.)

   This block sits AFTER the `prefers-reduced-motion` rule above on purpose:
   both set `transform`, and the later one has to win. */
@media (max-width: 600px) {
  /* the copyright (151px) and the icon row (148px) only share a line if the
     column gap gives way — at the desktop 2rem they wrap apart below 410px */
  .footer-meta {
    column-gap: 1rem;
  }

  .footer-social {
    order: 2;
  }

  /* .footer-verse stays a normal block so its two spans flow as one run of
     text — the verse, then "Romans 11:36" cited immediately after the closing
     quote mark, the way a citation should read. The HTML already has them in
     that order (verse first); do NOT reorder them with flex here, because
     flex items are block-level and would drop the citation onto its own
     line. `order` and `flex-basis` below apply to this element as a CHILD of
     .footer-meta, which is the flex container — that is what puts the whole
     verse on its own row under the copyright and icons. */
  .footer-verse {
    order: 3;
    flex-basis: 100%;
  }

  .verse-text {
    position: static;
    display: inline;
    width: auto;
    max-width: none;
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }

  /* it is no longer a hover target, so drop the affordances that said it was */
  .verse-ref {
    cursor: default;
    border-bottom: 0;
    /* Blend into the quotation so the verse and its citation read as one
       run of text. They already share Fraunces at weight 400; these are the
       three things that were breaking it — the reference was 14px upright at
       0.65 opacity against the quote's 12px italic at 0.8. */
    font-size: var(--text-xs);
    font-style: italic;
    color: rgba(241, 234, 223, 0.8);
  }
}

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

  .marquee-track { animation: none; }

  .hero-scroll::after { animation: none; transform: none; }

  .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }

  * {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}
