
/* --font-body/--font-heading (below, in :root) named Lato/Catamaran but
   neither was ever actually loaded -- no @font-face, no Google Fonts
   <link>, anywhere in the codebase. Every visitor without those installed
   as a local system font was silently falling through to the rest of the
   stack (-apple-system/Segoe UI/Roboto/Arial). Self-hosted here, matching
   how the other custom fonts on this page are already delivered, and
   split latin/latin-ext per subset the same way Google's own stylesheet
   does. Catamaran ships from Google Fonts as a single variable file
   covering its whole weight range, so the 400 and 700 rules below
   deliberately point at the same file per subset -- that's correct, not
   a duplication bug. */
@font-face {
  font-family: "Lato";
  src: url("/assets/fonts/Lato-Regular-Latin.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Lato";
  src: url("/assets/fonts/Lato-Regular-LatinExt.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Lato";
  src: url("/assets/fonts/Lato-Bold-Latin.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Lato";
  src: url("/assets/fonts/Lato-Bold-LatinExt.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Catamaran";
  src: url("/assets/fonts/Catamaran-Latin.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Catamaran";
  src: url("/assets/fonts/Catamaran-LatinExt.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Beyond Wonderland";
  src: url("/assets/fonts/BeyondWonderland.ttf") format("truetype");
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Birmingham";
  src: url("/assets/fonts/Birmingham.ttf") format("truetype");
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Birmingham Titling";
  src: url("/assets/fonts/BirminghamTitling.ttf") format("truetype");
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

:root {
  --container-width: 72rem;
  --gutter: clamp(1rem, 2vw, 1.5rem);
  --section-space: clamp(2.5rem, 5vw, 5rem);
  --radius-sm: 0;
  --radius-md: 0;
  --radius-lg: 0;
  --shadow-soft: none;
  --border-subtle: 1px solid var(--border-color);
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  overscroll-behavior-y: none;
  /* Disabling scroll anchoring for the whole document, not just the
     header: overflow-anchor:none on the header itself only stops the
     browser from picking something *inside* the header as the anchor it
     tracks — it doesn't stop the header's own size change from *causing*
     a compensating scroll adjustment elsewhere on the page. That
     adjustment re-crosses our shrink/grow threshold and re-triggers the
     shift, which is the real feedback loop (confirmed via a screen
     recording showing scrollY itself oscillating, not just the class). */
  overflow-anchor: none;
}

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--color-text);
  background:
    radial-gradient(circle at top, rgba(255, 255, 255, 0.75), transparent 38%),
    linear-gradient(180deg, var(--color-page-top), var(--color-page-bottom));
}

img {
  max-width: 100%;
  display: block;
}

a {
  color: inherit;
}

.container {
  width: min(100% - 2 * var(--gutter), var(--container-width));
  margin: 0 auto;
}

.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 10;
  background: transparent;
  border-bottom: 1px solid transparent;
  /* backdrop-filter is deliberately NOT in this transition: animating a
     live blur radius on a fixed header, at the same time its own height
     is changing (.header-inner's padding, below) and while a video plays
     underneath, produced a smeary "splash" artifact. Toggling the blur
     instantly while still fading background-color/border-color keeps the
     fade smooth without that interaction.
     Kept quick and eased out (120ms) rather than matching the slower
     220ms height change: the two used to visibly overlap — a still-tinted,
     still-growing bar reads as its own distinct "flash" — so the fade now
     finishes early and gets out of the way instead of dragging alongside
     the height change. */
  transition: background-color 80ms ease-out, border-color 80ms ease-out;
  /* The header's own size change (padding/logo scale on scroll) is a real
     layout shift near the top of the page. Without this, the browser's
     scroll-anchoring feature can "helpfully" nudge scrollY to compensate,
     which re-crosses our threshold and re-triggers the shift — a feedback
     loop between our JS and the browser's own compensation, seen as a
     rapid pulsing once scroll settles near the threshold. */
  overflow-anchor: none;
}

/* Header floats transparent over the hero until scrolled — at that point
   it picks up the same blurred, opaque surface it always used to have. */
.site-header.is-scrolled {
  backdrop-filter: blur(18px);
  background: color-mix(in srgb, var(--color-surface) 82%, transparent);
  border-bottom: var(--border-subtle);
}

/* Since .site-header is no longer in normal document flow (position: fixed,
   not sticky), the page's first section — always a hero — now starts at
   the very top of the viewport and runs underneath the transparent header,
   which is the point: a full-bleed hero with the nav floating over it. */

.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  padding: 1rem 0;
}

.footer-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  padding: 1rem 0;
  text-align: center;
}

.header-inner {
  padding: 1.6rem 0 2.0rem;
  transition: padding 220ms ease;
}

.site-header.is-scrolled .header-inner {
  padding: 0.35rem 0;
}

.site-brand {
  font-family: var(--font-heading);
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
}

.site-brand {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  color: #fff;
  transition: color 220ms ease;
}

.site-header.is-scrolled .site-brand {
  color: var(--color-text);
}

.brand-logo-swap {
  position: relative;
  display: block;
  height: 2.75rem;
  transform-origin: right center;
  transform: scale(2.1);
  transition: transform 220ms ease;
}

.site-header.is-scrolled .brand-logo-swap {
  transform: scale(1);
}

.brand-logo {
  display: block;
  height: 100%;
  width: auto;
}

/* Two pixel-identical logo files (same alpha mask, dark vs. white fill)
   cross-fade instead of swapping src — the light one is the resting
   (top-of-page) state, the dark one takes over once scrolled. */
.brand-logo-light {
  opacity: 1;
  transition: opacity 220ms ease;
}

.site-header.is-scrolled .brand-logo-light {
  opacity: 0;
}

.brand-logo-dark {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 220ms ease;
}

.site-header.is-scrolled .brand-logo-dark {
  opacity: 1;
}

.site-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.site-nav a {
  text-decoration: none;
  color: var(--color-muted);
}

.site-nav a:hover {
  color: var(--color-text);
}

.site-header .site-nav a {
  color: rgba(255, 255, 255, 0.85);
  transition: color 220ms ease;
}

.site-header .site-nav a:hover {
  color: #fff;
}

.site-header.is-scrolled .site-nav a {
  color: var(--color-muted);
}

.site-header.is-scrolled .site-nav a:hover {
  color: var(--color-text);
}

.nav-item.has-dropdown {
  position: relative;
}

.nav-item.has-dropdown > a {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

/* fill: currentColor (not a separate color rule) so the arrow tracks
   whatever color the "Services" link itself has at any moment — white at
   the top of the page, dark once scrolled, accent on hover — automatically,
   the same way the rest of the arrow motif flips with the header state. */
.nav-caret {
  width: 0.75rem;
  height: 0.75rem;
}

.nav-caret path {
  fill: currentColor;
}

.nav-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 20;
  margin: 0.5rem 0 0;
  padding: 0.5rem;
  min-width: 14rem;
  list-style: none;
  background: var(--color-surface);
  border: var(--border-subtle);
  box-shadow: var(--shadow-soft);
  opacity: 0;
  visibility: hidden;
  transform: translateY(0.25rem);
  transition: opacity 160ms ease, transform 160ms ease, visibility 160ms ease;
}

.nav-item.has-dropdown:hover .nav-dropdown,
.nav-item.has-dropdown:focus-within .nav-dropdown {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.nav-dropdown li + li {
  margin-top: 0.15rem;
}

.nav-dropdown a {
  display: block;
  padding: 0.5rem 0.6rem;
  white-space: nowrap;
  text-decoration: none;
  color: var(--color-muted);
}

.nav-dropdown a:hover {
  color: var(--color-text);
  background: var(--color-strong-surface);
}

/* The dropdown panel itself is always an opaque white surface, regardless
   of whether the header is transparent or not — so its links stay dark
   in every header state, unlike the top-level nav links. */
.site-header .nav-dropdown a {
  color: var(--color-muted);
}

.site-header .nav-dropdown a:hover {
  color: var(--color-text);
}

.site-footer {
  padding: 1rem 0 3rem;
}

.footer-social {
  display: flex;
  gap: 1.25rem;
}

.footer-social a {
  display: inline-flex;
  color: var(--color-muted);
  transition: color 180ms ease;
}

.footer-social a:hover {
  color: var(--color-text);
}

.footer-social svg {
  width: auto;
  height: 1.15rem;
}

.footer-copyright {
  margin: 0;
  color: var(--color-muted);
  font-size: 0.85rem;
}

.footer-tagline {
  margin: 0.1rem 0 0;
  color: var(--color-muted);
  opacity: 0.7;
  font-size: 0.85rem;
}

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

/* .site-header is position: fixed and floats over the page (see its own
   comment), so an in-page anchor jump — nav links, "Get a Quote" CTAs —
   lands with the target's true top hidden under it unless compensated.
   Scoped to sections with an id, since those are exactly the ones used as
   scroll targets (about/events/film-tv/services). Also applied to
   .scroll-target for anchor targets that aren't the section itself
   (gallery, contact form) and to .faq-item so an opened accordion question
   snaps to the same offset below the header instead of tucking under it. */
.section[id],
.scroll-target,
.faq-item {
  scroll-margin-top: 7rem;
}

/* The homepage contact block is the final in-page target. Giving it at
   least a viewport of space prevents the browser's maximum scroll position
   from clamping the #contact form heading while the gallery is still
   visible above it. */
.home-contact-section {
  min-height: calc(100vh - 7rem);
}

.eyebrow {
  margin: 0 0 1rem;
  color: var(--color-accent);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.section-title,
.display-title {
  margin: 0;
  font-family: var(--font-heading);
  line-height: 0.95;
  letter-spacing: -0.04em;
}

.section-title {
  font-size: clamp(2.2rem, 5vw, 4rem);
}

/* Homepage hero overrides this with its own font-family and size (see
   .gradient-masthead .display-title, higher specificity via two classes),
   so this is effectively the subpage hero title size only. Sized down
   ~15% per client feedback that it read too large. */
.display-title {
  font-size: clamp(2.6rem, 6.8vw, 5.5rem);
}

.lede,
.section-copy {
  color: var(--color-muted);
  font-size: clamp(1rem, 1.8vw, 1.15rem);
  line-height: 1.7;
}

.button-row {
  margin-top: 2.75rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 3rem;
  padding: 0.8rem 1.25rem;
  border-radius: 999px;
  border: 0;
  text-decoration: none;
  font-weight: 700;
  transition: transform 180ms ease, background-color 180ms ease, border-color 180ms ease;
}

.button:hover {
  transform: translateY(-1px);
}

.button-primary {
  background: var(--color-text);
  color: var(--color-surface);
}

.button-secondary {
  background: var(--color-strong-surface);
  color: var(--color-text);
}

/* Only on buttons that navigate to a different page (internal links,
   handled at the markup level) — a button that just scrolls the current
   page doesn't get one. Grey to match the service-card arrow, rather than
   currentColor, per Adam's direction. */
.button-arrow {
  width: 0.85rem;
  height: 0.85rem;
  margin-left: 0.25rem;
  flex-shrink: 0;
}

.button-arrow path {
  fill: var(--color-muted);
}

/* Icon-only "back" nudge that sits in the button row next to the hero's
   CTA, replacing the old descriptive "Home"/"Services" text link that
   used to sit above the title. */
.hero-back-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.16);
  border: 1px solid rgba(255, 255, 255, 0.4);
  transition: background-color 180ms ease, transform 180ms ease;
}

.hero-back-link:hover {
  background: rgba(255, 255, 255, 0.28);
  transform: translateY(-1px);
}

.hero-back-link svg {
  width: 1.1rem;
  height: 1.1rem;
  transform: rotate(-90deg);
}

.hero-back-link path {
  fill: #fff;
}

.surface-card {
  background: var(--color-surface);
  border: var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
}

@media (max-width: 760px) {
  .header-inner {
    align-items: flex-start;
    flex-direction: column;
  }

  .site-nav {
    width: 100%;
    justify-content: center;
  }

  .brand-logo-swap {
    margin-left: 1.5rem;
  }
}

/* The enlarged, left-growing logo needs room to its left to grow into.
   Above 76rem (--container-width plus its gutters on both sides) the
   container is capped and centered, so its edge sits well clear of the
   viewport edge and the full scale(2.1) fits comfortably. Below that, the
   container's margin shrinks down to just the gutter (as little as 1rem),
   which isn't enough room for the full-size scale — it was overflowing
   past the actual browser edge. Dial the scale back (not all the way to
   1) so the logo still reads as enlarged, just within what actually fits
   down to 761px, where the mobile breakpoint below takes over.
   No !important here (unlike the mobile breakpoint below): this has to
   stay overridable by .site-header.is-scrolled, or the shrink-on-scroll
   effect stops working entirely in this width range. */
@media (max-width: 76rem) {
  .brand-logo-swap {
    transform: scale(1.3);
    margin-left: 2rem;
  }
}


:root {
  --font-body: "Lato", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-heading: "Catamaran", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --color-page-top: #ffffff;
  --color-page-bottom: #f7f7f9;
  --color-surface: #ffffff;
  --color-strong-surface: #fdeef5;
  --color-text: #1c1a1f;
  --color-muted: #6b6570;
  --color-accent: #ee0979;
  --color-accent-2: #ff6a00;
  --border-color: rgba(28, 26, 31, 0.08);
  --border-color-strong: rgba(28, 26, 31, 0.18);
}



.hero-grid,
.split-grid,
.section-heading,
.cta-band,
.spotlight-grid,
.signup-band {
  display: grid;
  gap: 2rem;
}

.hero-grid,
.split-grid {
  grid-template-columns: repeat(12, minmax(0, 1fr));
  align-items: start;
}

.hero-copy {
  grid-column: span 7;
}

.hero-copy .lede {
  max-width: 40rem;
  margin: 1.5rem 0 2rem;
}

.hero-panel {
  grid-column: 9 / span 4;
  padding: 1.5rem;
  margin-top: 1rem;
}

.hero-panel-kicker,
.feature-index {
  margin: 0 0 0.75rem;
  color: var(--color-accent);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.hero-panel-title {
  margin: 0 0 1rem;
  font-family: var(--font-heading);
  font-size: 1.35rem;
}

.hero-panel-list,
.bullet-list {
  margin: 1.25rem 0 0;
  padding-left: 1.2rem;
  color: var(--color-muted);
  line-height: 1.7;
}

.section-heading {
  grid-template-columns: 1.4fr 1fr;
  align-items: start;
  margin-bottom: 2rem;
}

.feature-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.25rem;
}

.spotlight-grid {
  grid-template-columns: repeat(12, minmax(0, 1fr));
  align-items: center;
}

.spotlight-media,
.spotlight-copy {
  grid-column: span 6;
}

.spotlight-media {
  order: 2;
}

.spotlight-copy {
  order: 1;
}

.spotlight-media-left .spotlight-media {
  order: 1;
}

.spotlight-media-left .spotlight-copy {
  order: 2;
}

.media-placeholder {
  min-height: 25rem;
  border: var(--border-subtle);
  border-radius: var(--radius-lg);
  background:
    radial-gradient(circle at top left, rgba(255, 255, 255, 0.6), transparent 35%),
    linear-gradient(135deg, var(--color-strong-surface), var(--color-surface));
  display: grid;
  place-items: end start;
  padding: 1.5rem;
  box-shadow: var(--shadow-soft);
}

.media-placeholder span {
  display: inline-block;
  padding: 0.55rem 0.8rem;
  border-radius: 0;
  background: rgba(255, 255, 255, 0.72);
  color: var(--color-text);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.logo-wall {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  align-items: center;
  justify-items: start;
  gap: 2rem 1.5rem;
  margin-top: 2.5rem;
}

.clients-thanks {
  margin: 2.5rem 0 0;
  font-family: var(--font-heading);
  font-size: 1.4rem;
  color: var(--color-text);
  text-align: right;
}

.logo-wall img {
  max-width: 100%;
  max-height: 4rem;
  width: auto;
  filter: grayscale(1);
  opacity: 0.6;
  transition: opacity 180ms ease;
}

.logo-wall img:hover {
  opacity: 1;
}

@media (max-width: 960px) {
  .logo-wall {
    grid-template-columns: repeat(4, 1fr);
  }
}

@media (max-width: 480px) {
  .logo-wall {
    grid-template-columns: repeat(3, 1fr);
  }
}

.feature-card {
  display: flex;
  flex-direction: column;
  padding: 1.5rem;
  position: relative;
  /* Clips .feature-card-media's negative margin (below) to the card's own
     rounded corners, so a full-bleed top image reads as part of the card
     rather than a rectangle poking out past it. */
  overflow: hidden;
  transition: transform 180ms ease, box-shadow 180ms ease;
}

.feature-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-soft);
}

.feature-card-media {
  /* Escapes the card's own padding on three sides so the image runs
     edge-to-edge at the top, instead of floating inset within it. */
  margin: -1.5rem -1.5rem 1.25rem;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  position: relative;
}

/* A flat scrim over the whole photo, not just a band behind the text --
   darkens every service photo by the same uniform amount regardless of its
   own brightness, so white text reads reliably wherever it sits rather than
   only where a band happens to be. */
.feature-card-media::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: rgba(8, 8, 10, 0.35);
  transition: opacity 220ms ease;
}

/* Lets the true, untinted photo show through on hover -- the title's own
   text-shadow (below) is what keeps it legible once the scrim fades. */
.feature-card:hover .feature-card-media::after {
  opacity: 0;
}

/* .feature-card .feature-card-media h3, not just .feature-card-media h3 --
   equal specificity to .feature-card h3 (below) would otherwise let source
   order decide which margin wins, the same fragile trap as the gallery
   nav-arrow bug earlier. This wins outright regardless of ordering. */
.feature-card .feature-card-media h3 {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  z-index: 2;
  margin: 0;
  padding: 0.75rem 1.25rem;
  color: #fff;
  /* The full-image scrim above already does the legibility work; a text
     shadow is just a little extra insurance right at the letterforms. */
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}

.feature-card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Same hover-zoom treatment as the gallery thumbnails (.thumbnail-item
     img) -- an established "this is clickable" cue on this site already,
     not a new interaction pattern. */
  transition: transform 220ms ease;
}

.feature-card:hover .feature-card-media img {
  transform: scale(1.05);
}

/* Makes the whole card clickable through the one real link inside it
   (the "Learn more" text), instead of nesting a second anchor around the
   card — nested anchors aren't valid HTML. The pseudo-element expands to
   cover the card's full area while the link's own text stays as-is. */
.feature-card .preview-link::after {
  content: "";
  position: absolute;
  inset: 0;
  /* Explicitly above the image scrim (z-index: 1) and overlaid title
     (z-index: 2) -- without this it had no z-index of its own, so once the
     image area gained stacked children of its own, the cursor (and click
     target) over the photo itself no longer reliably resolved to this
     whole-card overlay. */
  z-index: 3;
  cursor: pointer;
}

.feature-card h3 {
  margin: 0 0 0.75rem;
  font-family: var(--font-heading);
  font-size: 1.4rem;
}

.feature-card p {
  margin: 0;
  color: var(--color-muted);
  line-height: 1.7;
}

.split-grid > :first-child {
  grid-column: span 5;
}

.split-body {
  grid-column: 7 / span 5;
}

.preview-list {
  display: grid;
  gap: 1.5rem;
}

.preview-row,
.promo-card {
  display: grid;
  grid-template-columns: minmax(0, 18rem) minmax(0, 1fr);
  gap: 1.25rem;
  align-items: stretch;
}

.preview-row {
  padding-bottom: 1.5rem;
  border-bottom: var(--border-subtle);
}

.preview-media,
.promo-media {
  min-height: 14rem;
}

.preview-copy,
.promo-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.preview-copy h3,
.promo-copy h3 {
  margin: 0 0 0.75rem;
  font-family: var(--font-heading);
  font-size: 1.7rem;
}

.preview-copy p,
.promo-copy p {
  color: var(--color-muted);
  line-height: 1.7;
}

.preview-link {
  font-weight: 700;
  text-decoration: none;
}

.feature-card .preview-link {
  display: flex;
  justify-content: flex-end;
  margin-top: auto;
  padding-top: 1rem;
}

.feature-card .preview-link svg {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  background: color-mix(in srgb, var(--color-text) 10%, transparent);
  padding: 0.6rem;
  box-sizing: border-box;
  transition: background 180ms ease;
}

.feature-card:hover .preview-link svg {
  background: color-mix(in srgb, var(--color-text) 16%, transparent);
}

.feature-card .preview-link path {
  fill: var(--color-muted);
  transition: fill 180ms ease;
}

/* Reacts to hovering anywhere on the card, not just the arrow itself,
   since the whole card is the click target (see .feature-card .preview-link
   ::after above). */
.feature-card:hover .preview-link path {
  fill: var(--color-accent);
}

.promo-pair,
.contact-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.25rem;
}

.carousel-shell {
  --carousel-media-height: clamp(18rem, 42vw, 26rem);
  position: relative;
  overflow: hidden;
  padding: 1.5rem 1.5rem 3.75rem;
}

.carousel-viewport {
  position: relative;
}

.carousel-track {
  position: relative;
  overflow: hidden;
}

.carousel-slide {
  display: grid;
  gap: 1.25rem;
  margin: 0;
}

.carousel-slide-link {
  display: block;
  color: inherit;
  text-decoration: none;
}

.carousel-item {
  position: relative;
  display: none;
  float: left;
  width: 100%;
  margin-right: -100%;
  backface-visibility: hidden;
  transition: transform 0.6s ease-in-out;
}

.carousel-item.active,
.carousel-item-next,
.carousel-item-prev {
  display: block;
}

.carousel-item-next:not(.carousel-item-start),
.active.carousel-item-end {
  transform: translateX(100%);
}

.carousel-item-prev:not(.carousel-item-end),
.active.carousel-item-start {
  transform: translateX(-100%);
}

.carousel-fade .carousel-item {
  opacity: 0;
  transition-property: opacity;
  transform: none;
}

.carousel-fade .carousel-item.active,
.carousel-fade .carousel-item-next.carousel-item-start,
.carousel-fade .carousel-item-prev.carousel-item-end {
  z-index: 1;
  opacity: 1;
}

.carousel-fade .active.carousel-item-start,
.carousel-fade .active.carousel-item-end {
  z-index: 0;
  opacity: 0;
}

#quotes-carousel .carousel-track {
  display: grid;
  align-items: center;
}

/* Keep every quote in the same grid cell so the tallest sets the height. */
#quotes-carousel .carousel-item {
  display: block;
  grid-area: 1 / 1;
  min-width: 0;
  float: none;
  margin-right: 0;
  visibility: hidden;
}

#quotes-carousel .carousel-item.active,
#quotes-carousel .carousel-item-next,
#quotes-carousel .carousel-item-prev {
  visibility: visible;
}

#quotes-carousel .quote-text {
  display: block;
  -webkit-line-clamp: unset;
  overflow: visible;
}

.carousel-media {
  margin: 0;
  min-height: var(--carousel-media-height);
  height: var(--carousel-media-height);
}

.carousel-media img,
.carousel-media.media-placeholder {
  width: 100%;
  min-height: var(--carousel-media-height);
  height: var(--carousel-media-height);
  object-fit: var(--carousel-image-fit, cover);
  border-radius: var(--radius-md);
}

.codette-carousel-caption {
  max-width: 38rem;
  min-height: 3.5rem;
  margin: 0 auto;
  text-align: center;
}

.codette-carousel-caption p {
  margin: 0;
  color: var(--color-muted);
  line-height: 1.7;
}

.carousel-indicator,
.codette-carousel-control {
  border: 0;
  padding: 0;
  cursor: pointer;
  /* Without this, a tap can get consumed by the browser's double-tap-to-zoom
     gesture detection instead of registering as a click -- on mobile this
     shows up as needing several taps before one finally lands. This base
     class backs every carousel/gallery nav control on the site. */
  touch-action: manipulation;
}

.codette-carousel-control {
  position: absolute;
  top: calc(var(--carousel-media-height) / 2);
  transform: translateY(-50%);
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  background: color-mix(in srgb, var(--color-text) 88%, transparent);
  color: var(--color-surface);
  display: grid;
  place-items: center;
  z-index: 2;
  opacity: 1;
}

.carousel-control-prev.codette-carousel-control {
  left: 1rem;
}

.carousel-control-next.codette-carousel-control {
  right: 1rem;
}

.codette-carousel-control:focus,
.codette-carousel-control:active {
  color: var(--color-surface);
}

.codette-carousel-control:hover {
  color: var(--color-accent);
}

.codette-carousel-control-icon {
  width: 0.9rem;
  height: 0.9rem;
}

.codette-carousel-control-icon path {
  fill: currentColor;
}

.codette-carousel-control-icon-prev {
  transform: rotate(180deg);
}

.codette-carousel-indicators {
  position: absolute;
  left: 50%;
  bottom: 1rem;
  transform: translateX(-50%);
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
}

.carousel-indicator {
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--color-text) 18%, transparent);
  opacity: 1;
}

.carousel-indicator.active,
.carousel-indicator.is-active {
  background: var(--color-accent);
}

.thumbnail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: 1.25rem;
}

.thumbnail-item {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  padding: 0;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--color-strong-surface);
  cursor: pointer;
}

.thumbnail-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 220ms ease;
}

.thumbnail-item:hover img,
.thumbnail-item:focus-visible img {
  transform: scale(1.05);
}

/* Bootstrap's JS bundle is loaded (see gallery.blade.php's @push('scripts')),
   but not its CSS -- Codette already hand-recreates the carousel rules above
   this point, themed to match. This is that same treatment for the Modal
   component Bootstrap's JS expects (.show/.fade toggling, backdrop
   injection, body.modal-open), used here for the first time for the gallery
   lightbox: a real, battle-tested Modal + Carousel pairing instead of a
   hand-rolled <dialog> (which had its own z-index stacking and touch-target
   bugs that this sidesteps entirely by not reimplementing what Bootstrap
   already solved). */
.modal {
  position: fixed;
  inset: 0;
  z-index: 1055;
  display: none;
  outline: 0;
}

.modal.show {
  display: block;
}

.modal.fade .modal-dialog {
  transition: transform 0.3s ease-out;
  transform: translate(0, -50px);
}

.modal.show .modal-dialog {
  transform: none;
}

.modal-dialog {
  position: relative;
  width: auto;
  margin: 0.5rem;
  pointer-events: none;
}

.modal-dialog.modal-fullscreen {
  width: 100vw;
  max-width: none;
  height: 100%;
  margin: 0;
}

.modal-content {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  pointer-events: auto;
  background: transparent;
  outline: 0;
}

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1050;
  background: rgba(8, 8, 10, 0.9);
}

.modal-backdrop.fade {
  opacity: 0;
  transition: opacity 0.15s linear;
}

.modal-backdrop.show {
  opacity: 1;
}

body.modal-open {
  overflow: hidden;
}

.gallery-modal-carousel,
.gallery-modal-carousel .carousel-inner,
.gallery-modal-carousel .carousel-item {
  height: 100%;
}

.gallery-modal-figure {
  /* No grid-template-rows splitting image/caption into separate areas
     anymore -- that reserved a whole row for the caption whether or not it
     was showing, shrinking the image's share of the viewport below what the
     homepage carousel gets (which has no such reservation and simply lets
     the page scroll past it if needed). The caption is instead an overlay
     (below) so the image gets the full box. */
  position: relative;
  margin: 0;
  width: 100%;
  height: 100%;
  /* Trimmed from clamp(1.5rem, 5vw, 4rem) -- that alone was costing up to
     8rem of combined vertical space against a fixed viewport height, on top
     of the caption row above. An apex-viewing lightbox should spend that
     space on the photo. */
  padding: clamp(0.5rem, 2vw, 1.5rem);
  color: #f5f5f7;
  text-align: center;
  /* Nothing in here is meant to be selected -- without this, clicking the
     nav buttons a little off-center (easy to do while clicking through
     several photos in a row) can land on the caption text instead and
     trigger the browser's native double-click-to-select instead of
     advancing the image. */
  user-select: none;
  -webkit-user-select: none;
}

.gallery-modal-figure img {
  display: block;
  /* width/height:100% + object-fit:contain, not width/height:auto +
     max-width/max-height:100% -- the auto+max-* combo renders the image at
     its native pixel size and never scales UP past that, so on any viewport
     bigger than the source photo's own resolution the "full-screen" lightbox
     was actually showing it smaller than the hero/carousel elsewhere, which
     fills its box via object-fit:cover regardless of native size. This still
     shows the whole photo (no cropping, unlike cover) but lets it grow to
     fill the available space the same way. */
  width: 100%;
  height: 100%;
  min-height: 0;
  margin: 0 auto;
  object-fit: contain;
  border-radius: var(--radius-md);
}

.gallery-modal-caption {
  /* A sibling of .gallery-modal-carousel inside .modal-content (already
     position:relative), not nested in .gallery-modal-figure -- living
     outside .carousel-inner is what lets it cross-fade in place instead of
     sliding with the image (see gallery.blade.php's slide.bs.carousel
     listener). */
  position: absolute;
  left: 0;
  right: 0;
  bottom: clamp(0.5rem, 2vw, 1.5rem);
  z-index: 2;
  margin: 0;
  /* Full-bleed band, no side gutter -- left/right padding here is on the
     text, not the background, so the band itself still reaches both edges. */
  padding: 0.75rem clamp(0.5rem, 2vw, 1.5rem);
  /* A flat, evenly-opaque band, not a fade-to-transparent gradient -- a
     gradient thins out right where the text sits, so legibility against a
     light or busy photo still varied by word position. */
  background: rgba(8, 8, 10, 0.75);
  color: rgba(245, 245, 247, 0.9);
  font-size: 0.95rem;
  text-align: center;
  transition: opacity ease;
}

.gallery-modal-caption.is-hidden {
  opacity: 0;
}

.gallery-modal-caption:empty {
  display: none;
}

.gallery-modal-close {
  position: absolute;
  top: clamp(1rem, 3vw, 2rem);
  right: clamp(1rem, 3vw, 2rem);
  z-index: 3;
  width: 2.75rem;
  height: 2.75rem;
  border: 0;
  border-radius: 999px;
  background: rgba(245, 245, 247, 0.12);
  color: #f5f5f7;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background 160ms ease;
  touch-action: manipulation;
}

.gallery-modal-close:hover {
  background: rgba(245, 245, 247, 0.24);
}

/* Doubled up with .gallery-modal-carousel, not just .gallery-modal-nav
   alone -- a global @media (max-width: 960px) rule resets the shared
   .codette-carousel-control's `top` back to
   calc(var(--carousel-media-height) / 2) for the homepage carousel's mobile
   layout. That variable is undefined here, which collapses to `auto` and
   drops the button to its normal flow position (below the image) on any
   narrow viewport. Equal specificity would lose that fight based on source
   order; this wins outright, at every width, regardless of it. */
.gallery-modal-carousel .gallery-modal-nav {
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
}

.gallery-modal-prev {
  left: clamp(0.5rem, 2vw, 1.5rem);
}

.gallery-modal-next {
  right: clamp(0.5rem, 2vw, 1.5rem);
}

.promo-card {
  overflow: hidden;
}

.promo-media {
  border-radius: var(--radius-lg) 0 0 var(--radius-lg);
}

.promo-copy {
  padding: 1.5rem 1.5rem 1.5rem 0;
}

.quote-band {
  margin: 0;
  padding: clamp(1.25rem, 5vw, 2.5rem);
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: clamp(16rem, 28vw, 20rem);
}

.quote-text {
  margin: 0;
  font-family: var(--font-heading);
  font-size: clamp(1.3rem, 5.5vw, 3rem);
  line-height: 1.1;
  letter-spacing: -0.03em;
  /* This heading-scale size reads great for a punchy one-liner, but a couple
     of Jena's real client quotes are full paragraphs (500-700+ characters) --
     at this font size that wraps into dozens of lines and blows out the
     carousel's height on those slides. Clamping to 5 lines with an ellipsis
     keeps every slide within a similar, bounded height regardless of quote
     length; short quotes never reach the cap, so they're unaffected. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 5;
  overflow: hidden;
}

.quote-attribution {
  margin-top: 1.5rem;
  color: var(--color-muted);
}

.cta-band {
  grid-template-columns: 1.6fr auto;
  align-items: end;
  padding: 2rem;
}

.faq-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.faq-item summary {
  cursor: pointer;
  padding: 1.25rem 1.5rem;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.05rem;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}

.faq-item summary::-webkit-details-marker {
  display: none;
}

.faq-item summary::after {
  content: "+";
  font-size: 1.5rem;
  line-height: 1;
  color: var(--color-accent);
  flex-shrink: 0;
}

.faq-item[open] summary::after {
  content: "\2212";
}

.faq-answer {
  height: 0;
  overflow: hidden;
  transition: height 220ms ease;
}

.faq-answer-inner {
  padding: 0 1.5rem 1.5rem;
}

@media (prefers-reduced-motion: reduce) {
  .faq-answer {
    transition: none;
  }
}

.faq-answer p {
  margin: 0 0 1rem;
  color: var(--color-muted);
  line-height: 1.7;
}

.faq-answer p:last-child {
  margin-bottom: 0;
}

.signup-band {
  grid-template-columns: 1.3fr 1fr;
  align-items: center;
  padding: 2rem;
}

.signup-form {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.75rem;
}

.signup-form input {
  min-height: 3rem;
  padding: 0.85rem 1rem;
  border: var(--border-subtle);
  border-radius: 0;
  background: rgba(255, 255, 255, 0.72);
  color: var(--color-text);
}

.contact-card {
  padding: 1.5rem;
}

.contact-kicker {
  margin: 0 0 0.8rem;
  color: var(--color-accent);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.contact-value,
.contact-value a {
  margin: 0;
  color: var(--color-text);
  font-family: var(--font-heading);
  font-size: 1.3rem;
  text-decoration: none;
}

.contact-form-heading {
  margin: 2.75rem 0 0.75rem;
  font-family: var(--font-heading);
  font-size: clamp(1.4rem, 2.4vw, 1.8rem);
  letter-spacing: -0.03em;
}

.contact-form-copy {
  margin: 0;
}

.contact-form {
  margin-top: 1.5rem;
  padding: 2rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.contact-form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
}

.contact-form-field {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.contact-form-label {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--color-text);
}

.contact-form-optional {
  font-weight: 400;
  color: var(--color-muted);
}

.contact-form-input {
  padding: 0.75rem 1rem;
  border: var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--color-page-top, var(--color-surface));
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: 1rem;
}

.contact-form-input:focus {
  outline: none;
  border-color: var(--color-accent);
}

.contact-form-textarea {
  resize: vertical;
}

.contact-form-checkboxes {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.25rem;
}

.contact-form-checkbox {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.92rem;
  color: var(--color-text);
  cursor: pointer;
}

.contact-form-error {
  margin: 0;
  color: var(--color-accent);
  font-size: 0.85rem;
}

.contact-form-status {
  margin: 0;
  font-weight: 700;
  color: var(--color-accent);
}

/* Off-screen rather than display:none, for the same reason as the chat
   widget's honeypot -- see its comment in public/scripts.js. */
.contact-form-honeypot {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}

.contact-form-submit {
  align-self: flex-start;
}

@media (max-width: 640px) {
  .contact-form-row {
    grid-template-columns: 1fr;
  }
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.gradient-masthead {
  position: relative;
  overflow: hidden;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: max(42rem, 85vh);
  padding: calc(var(--section-space) * 1.5) 0 var(--section-space);
  background: linear-gradient(0deg, var(--color-accent-2, var(--color-accent)) 0%, var(--color-accent) 100%);
  color: #fff;
}

.gradient-masthead .container {
  position: relative;
  z-index: 1;
}

.masthead-video {
  position: absolute;
  top: -20vh;
  left: 0;
  z-index: 0;
  width: 100%;
  height: calc(100% + 20vh);
  object-fit: cover;
  transition: transform 120ms ease-out;
  will-change: transform;
}

.masthead-video-overlay {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(0deg, var(--color-accent-2, var(--color-accent)) 0%, var(--color-accent) 100%);
  opacity: 0.5;
}

.gradient-masthead .eyebrow {
  color: rgba(255, 255, 255, 0.85);
  margin-bottom: 3rem;
}

.masthead-eyebrow-link {
  display: inline-block;
  text-decoration: none;
}

.masthead-eyebrow-link::before {
  content: "← ";
}

.masthead-eyebrow-link:hover {
  text-decoration: underline;
}

.gradient-masthead .display-title {
  color: inherit;
  font-family: "Birmingham", var(--font-heading);
  font-weight: 400;
  font-size: clamp(3.2rem, 9.5vw, 7.5rem);
  margin-bottom: 1.5rem;
}

.hero-title-word {
  display: inline-block;
  opacity: 0;
}

/* Held at opacity: 0 (not animating) until scripts.js confirms the Beyond
   Wonderland font has actually loaded and adds this class — otherwise the
   stagger reveal could run against the fallback font while the real one
   is still fetching, then visibly swap mid-animation or right after it. */
.fonts-ready .hero-title-word {
  animation: hero-title-fade-in 600ms ease forwards;
}

.hero-title-word:nth-child(1) {
  animation-delay: 500ms;
}

.hero-title-word:nth-child(2) {
  animation-delay: 1000ms;
}

.hero-title-word:nth-child(3) {
  animation-delay: 1500ms;
}

@keyframes hero-title-fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero-title-word {
    animation: none;
    opacity: 1;
  }
}

.gradient-masthead .masthead-subheading {
  margin: 0.5rem 0 2rem;
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: clamp(1.3rem, 3.2vw, 2.3rem);
  color: rgba(255, 255, 255, 0.92);
}

.gradient-masthead .button-row {
  justify-content: center;
}

.gradient-masthead .button-primary {
  background: #fff;
  color: var(--color-accent);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.masthead-circle {
  position: absolute;
  z-index: 0;
  border-radius: 50%;
  background: linear-gradient(0deg, rgba(255, 255, 255, 0.14) 0%, rgba(255, 255, 255, 0.04) 100%);
}

.masthead-circle-1 {
  width: 70rem;
  height: 70rem;
  left: -30rem;
  bottom: -42rem;
}

.masthead-circle-2 {
  width: 38rem;
  height: 38rem;
  right: -14rem;
  top: -18rem;
}

.masthead-circle-3 {
  width: 18rem;
  height: 18rem;
  right: 8%;
  bottom: -6rem;
}

.page-title-bar {
  text-align: center;
  padding: var(--section-space) 0 calc(var(--section-space) * 0.5);
}

.page-title-bar .button-row {
  justify-content: center;
}

.image-masthead {
  position: relative;
  overflow: hidden;
  /* Trying a shorter, right-anchored hero (was centered at
     max(42rem, 85vh)) -- asymmetric alignment per Adam's usual
     preference, closer to ahmedia.ai's subpage hero. The rem floor had
     to come down too, not just the vh: 42rem (672px) alone exceeded
     70vh on most real viewport heights, so it silently overrode the
     new shorter target and the hero never actually looked shorter.
     Revert this, the .container margin below, and the button-row
     justify-content to restore the original centered version. */
  text-align: right;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: max(26rem, 70vh);
  padding: calc(var(--section-space) * 1.5) 0 var(--section-space);
  color: #fff;
}

.image-masthead .container {
  position: relative;
  z-index: 1;
  margin: 0 var(--gutter) 0 auto;
}

.masthead-image {
  position: absolute;
  top: -20vh;
  left: 0;
  z-index: 0;
  width: 100%;
  height: calc(100% + 20vh);
  object-fit: cover;
  transition: transform 120ms ease-out;
  will-change: transform;
}

@media (max-width: 760px) {
  .masthead-video,
  .masthead-image {
    top: 0;
    height: 100%;
    transition: none;
    will-change: auto;
  }
}

.masthead-image-overlay {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(180deg, rgba(20, 12, 20, 0.4), rgba(20, 12, 20, 0.6));
}

.image-masthead .eyebrow {
  color: rgba(255, 255, 255, 0.85);
}

.image-masthead .display-title {
  color: inherit;
}

.image-masthead .masthead-subheading {
  color: rgba(255, 255, 255, 0.92);
}

.image-masthead .button-row {
  justify-content: flex-end;
}

.image-masthead .button-primary {
  background: #fff;
  color: var(--color-accent);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.masthead-subheading {
  margin: 0.5rem 0 2rem;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: clamp(1.4rem, 3.5vw, 2.5rem);
  color: var(--color-muted);
}

.spotlight-media-circle {
  width: min(100%, 26rem);
  aspect-ratio: 1 / 1;
  margin: 0 auto;
  border-radius: 50%;
  overflow: hidden;
  min-height: 0;
}

.spotlight-media-circle img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (max-width: 960px) {
  .masthead-circle-1 {
    width: 40rem;
    height: 40rem;
    left: -18rem;
    bottom: -24rem;
  }

  .masthead-circle-2,
  .masthead-circle-3 {
    display: none;
  }


  .hero-copy,
  .hero-panel,
  .spotlight-media,
  .spotlight-copy,
  .split-grid > :first-child,
  .split-body {
    grid-column: 1 / -1;
  }

  /* Desktop alternates image/text sides per section via order (left/right,
     right/left, left/right...), which on a single mobile column instead
     stacks the tail of one section against the head of the next — e.g.
     two images landing back to back. Reset to always image-then-text,
     ignoring the desktop left/right variant, so each section's own image
     and copy stay paired together. */
  .spotlight-grid .spotlight-media {
    order: 1;
  }

  .spotlight-grid .spotlight-copy {
    order: 2;
  }

  .feature-grid,
  .section-heading,
  .cta-band,
  .signup-band,
  .promo-pair,
  .contact-grid,
  .signup-form,
  .preview-row,
  .promo-card {
    grid-template-columns: 1fr;
  }

  .promo-media {
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  }

  .promo-copy {
    padding: 0 1.5rem 1.5rem;
  }

  .codette-carousel-control {
    top: calc(var(--carousel-media-height) / 2);
  }
}



.back-to-top-link {
  cursor: pointer;
  width: 50px;
  height: 50px;
  position: fixed;
  right: 20px;
  bottom: 82px;
  z-index: 30;
  opacity: 0;
  pointer-events: none;
  transform: translateY(0.35rem);
  transition: opacity 180ms ease, transform 180ms ease;
}

.back-to-top-link.visible {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

.back-to-top-link a {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: color-mix(in srgb, var(--color-text) 86%, transparent);
  box-shadow: var(--shadow-soft);
}

.back-to-top-link svg {
  width: 1.1rem;
  height: 1.1rem;
}

.back-to-top-link path {
  fill: var(--color-surface);
  transition: fill 180ms ease;
}

.back-to-top-link:hover path {
  fill: var(--color-accent);
}

/* Same fixed slot as .back-to-top-link, but visible only near the top of
   the page — the two swap places at the same scroll threshold, never both
   shown at once. Deliberately a bare triangle with no circular backing,
   introducing a second "arrow language" (plain SVG triangle, no chip)
   distinct from the back-to-top button's own style, per Adam's direction. */
.scroll-down-link {
  cursor: pointer;
  width: 50px;
  height: 50px;
  position: fixed;
  right: 20px;
  bottom: 82px;
  z-index: 30;
  opacity: 0;
  pointer-events: none;
  transition: opacity 180ms ease, transform 180ms ease;
}

.scroll-down-link.visible {
  opacity: 1;
  pointer-events: auto;
}

.scroll-down-link a {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
}

.scroll-down-link svg {
  width: 1.4rem;
  height: 1.4rem;
}

.scroll-down-link path {
  fill: #fff;
  transition: fill 180ms ease;
}

/* White only reads against the home hero's video background, which always
   fills the viewport. Subpage heroes are shorter (see .image-masthead's
   70vh), so the arrow's fixed position can sit below the hero on the
   plain white page background by the time it's visible -- :has() lets this
   stay a page-type check without threading masthead type into the layout.
   Accent at rest here, so the hover state below is flipped to gray instead
   of the home page's accent -- same color for both states would erase the
   hover feedback entirely. */
body:has(.image-masthead) .scroll-down-link path {
  fill: var(--color-accent);
}

.scroll-down-link:hover path {
  fill: var(--color-accent);
}

body:has(.image-masthead) .scroll-down-link:hover path {
  fill: var(--color-muted);
}

.chat-container {
  position: fixed;
  bottom: 20px;
  right: 20px;
  width: min(350px, calc(100vw - 2rem));
  height: min(500px, calc(100vh - 4rem));
  background: var(--color-page-bottom);
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-lg);
  box-shadow: 0 0 20px color-mix(in srgb, var(--color-accent) 20%, transparent);
  display: none;
  flex-direction: column;
  overflow: hidden;
  z-index: 2000;
}

.chat-widget.is-open .chat-container {
  display: flex;
}

.chat-widget.is-open .chat-reopen-button {
  display: none;
}

.chat-messages {
  flex: 1;
  padding: 20px;
  padding-top: 50px;
  overflow-y: auto;
  background: color-mix(in srgb, var(--color-text) 4%, transparent);
}

.chat-input-row {
  display: flex;
  padding: 15px;
  border-top: 1px solid var(--color-accent);
  background: color-mix(in srgb, var(--color-text) 6%, transparent);
}

.chat-input {
  flex: 1;
  padding: 10px 15px;
  border: 1px solid var(--color-accent);
  border-radius: 20px;
  margin-right: 10px;
  font-size: 14px;
  outline: none;
  background: var(--color-surface);
  color: var(--color-text);
}

.chat-input:focus {
  box-shadow: 0 0 10px var(--color-accent);
}

.chat-input::placeholder {
  color: color-mix(in srgb, var(--color-text) 50%, transparent);
}

.chat-send-button,
.chat-reopen-button {
  background: var(--color-accent);
  color: var(--color-surface);
  border: none;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 180ms ease, box-shadow 180ms ease;
  /* See .codette-carousel-control's comment -- same fix, same reason. */
  touch-action: manipulation;
}

.chat-send-button {
  width: 40px;
  height: 40px;
}

.chat-send-button svg,
.chat-reopen-button svg,
.chat-close-button svg {
  width: 1.1rem;
  height: 1.1rem;
  fill: currentColor;
}

/*
 * The "comments" glyph's viewBox (640x512, 1.25:1) is wider than the
 * square box above, so at the shared size it gets letterboxed and
 * reads visually smaller than the other (square-viewBox) icons.
 * Size it up specifically so it fills the reopen button the same way.
 */
.chat-reopen-button svg {
  width: 1.5rem;
  height: 1.5rem;
}

.chat-send-button:hover,
.chat-reopen-button:hover {
  box-shadow: 0 0 15px var(--color-accent);
}

.chat-reopen-button {
  position: fixed;
  bottom: 20px;
  right: 20px;
  width: 50px;
  height: 50px;
  box-shadow: 0 0 15px color-mix(in srgb, var(--color-accent) 30%, transparent);
  z-index: 2000;
}

.chat-reopen-button:hover {
  transform: scale(1.1);
}

.chat-message {
  margin-bottom: 15px;
  padding: 10px 15px;
  border-radius: 15px;
  max-width: 80%;
  word-wrap: break-word;
}

.chat-user-message {
  background: var(--color-accent);
  color: var(--color-surface);
  margin-left: auto;
}

.chat-bot-message {
  background: color-mix(in srgb, var(--color-accent) 10%, transparent);
  color: var(--color-text);
  border: 1px solid var(--color-accent);
}

.chat-close-button {
  position: absolute;
  top: 10px;
  right: 10px;
  background: none;
  border: none;
  color: var(--color-accent);
  cursor: pointer;
  padding: 5px;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  transition: background 180ms ease, box-shadow 180ms ease;
  touch-action: manipulation;
}

.chat-close-button:hover {
  background: color-mix(in srgb, var(--color-accent) 10%, transparent);
  box-shadow: 0 0 10px var(--color-accent);
}

.chat-messages::-webkit-scrollbar {
  width: 8px;
}

.chat-messages::-webkit-scrollbar-track {
  background: color-mix(in srgb, var(--color-text) 6%, transparent);
}

.chat-messages::-webkit-scrollbar-thumb {
  background: var(--color-accent);
  border-radius: 4px;
}

/* RichEditor answers arrive as full <p> blocks; without this they carry
   their own default paragraph spacing, which reads as too loose inside an
   80%-width chat bubble. */
.chat-answer p {
  margin: 0 0 0.5em;
}

.chat-answer p:last-child {
  margin-bottom: 0;
}

.chat-answer a {
  color: inherit;
  text-decoration: underline;
}

.chat-typing {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 14px 15px;
}

.chat-typing span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-accent);
  opacity: 0.4;
  animation: chat-typing-bounce 1s infinite ease-in-out;
}

.chat-typing span:nth-child(2) {
  animation-delay: 0.15s;
}

.chat-typing span:nth-child(3) {
  animation-delay: 0.3s;
}

@keyframes chat-typing-bounce {
  0%, 60%, 100% {
    opacity: 0.4;
    transform: translateY(0);
  }
  30% {
    opacity: 1;
    transform: translateY(-3px);
  }
}

.chat-chips,
.chat-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 15px;
}

.chat-chip,
.chat-option {
  align-self: flex-start;
  max-width: 90%;
  text-align: left;
  background: var(--color-surface);
  color: var(--color-accent);
  border: 1px solid var(--color-accent);
  border-radius: 15px;
  padding: 8px 14px;
  font-size: 0.85rem;
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease;
}

.chat-chip:hover,
.chat-option:hover {
  background: var(--color-accent);
  color: var(--color-surface);
}

a.chat-option {
  display: inline-block;
  text-decoration: none;
}

.chat-cta-row {
  flex-direction: row;
  flex-wrap: wrap;
}

.chat-cta-row .chat-option {
  max-width: none;
  text-align: center;
}

.chat-lead-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 15px;
  margin-bottom: 15px;
  border: 1px solid var(--color-accent);
  border-radius: 15px;
  background: color-mix(in srgb, var(--color-accent) 6%, transparent);
}

.chat-lead-field {
  padding: 8px 10px;
  border: 1px solid var(--color-accent);
  border-radius: 8px;
  font-size: 0.85rem;
  background: var(--color-surface);
  color: var(--color-text);
}

.chat-lead-field:focus {
  outline: none;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-accent) 40%, transparent);
}

/* Off-screen rather than display:none -- a hidden-but-present field is a
   more reliable honeypot, since some bots specifically skip fields that
   aren't rendered at all. */
.chat-lead-honeypot {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}

.chat-lead-submit {
  padding: 8px 14px;
  border: none;
  border-radius: 15px;
  background: var(--color-accent);
  color: var(--color-surface);
  font-size: 0.85rem;
  font-weight: 700;
  cursor: pointer;
}

.chat-lead-submit:disabled {
  opacity: 0.6;
  cursor: default;
}

.chat-field-error {
  margin: 0;
  color: var(--color-accent);
  font-size: 0.8rem;
}

@media (max-width: 480px) {
  .chat-container {
    right: 1rem;
    left: 1rem;
    width: auto;
  }
}
