/* ==========================================================================
   Hero — homepage hero, page hero, SVG curves
   ========================================================================== */

/* ── Homepage hero (Figma 6461:10022 "Landingpage_Sep26", 2026-10-01) ────────
   Headline top-left, intro top-right, then the STAGE: a rounded media card
   (the editor's film or image, ACF tab "Hero media") that IS the chat. The
   prompt pill floats over the film; the first focus (.is-chatting, set by
   hero-chat.js) fades the film out and the conversation takes the card.
   Below the card: the scroll hint bar. */
.hero {
  position: relative;
  overflow: hidden;               /* the 680px cursor glow now lives here — without this it widens the page at the edges */
  background-color: var(--bg-primary);
  --hero-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --hero-dur: 0.7s;
}
.hero__inner {
  position: relative;
  /* Figma 6461:10022, measured off the render: the headline's text box starts
     at y 136, not 124 - the old note was 12px short (Kajsa 2026-10-06). */
  padding-top: calc(var(--header-h) + 50px);
  padding-bottom: 8px;                         /* Figma: scroll bar bottom 968 → next section 976 */
}

/* Headline + intro on the 4-column grid: headline cols 1–2 (a 428px box in
   Figma, which is what wraps it onto three lines), intro cols 3–4 (433px). */
.hero__head {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: 20px;
  align-items: start;
}
.hero__title {
  grid-column: 1 / span 2;
  max-width: 428px;
  margin: 0;
  text-wrap: wrap;                /* the greedy rag of the Figma text box (tokens.css balances headings, which breaks this one differently) */
  font-size: var(--title-sm);
  line-height: var(--title-sm-lh);
  letter-spacing: var(--title-sm-ls);
  font-weight: 400;
  font-variation-settings: "opsz" 14;
  color: var(--text-title);
}
.hero__lead {
  grid-column: 3 / span 2;
  max-width: 433px;
  margin: 0;
  font-size: var(--body-sm);
  line-height: var(--body-sm-lh);
  color: var(--text-title);
}

/* ── The stage: 1340×604 card, 20px corners (Figma "Showreel" 6461:10023) ──
   Layers, bottom up: glow + dot grid (the chat's ground, revealed once the
   film is gone) · cursor glow · the media · the chat column. In chat mode the
   card never shrinks below a useful chat height — min-height transitions, so
   the growth is a glide; on touch the VISUAL viewport sets it (see below). */
.hero__stage {
  position: relative;
  z-index: 0;                     /* own stacking context: the layers' z-indexes stay inside the card */
  margin-top: 40px;               /* Figma: headline block ends 274 → card 313 */
  width: 100%;                    /* definite, not auto: an auto width would take the chat-mode min-height through the aspect ratio and widen the card past the page */
  overflow: hidden;
  border-radius: 20px;
  aspect-ratio: 1340 / 604;
  min-height: 0;
  background-color: var(--bg-primary);
  transition: min-height var(--hero-dur) var(--hero-ease);
}
/* The pale rim round the film (Kajsa 2026-10-13). There is no border: the card's
   own light ground sits under the dark .hero__media, and the card starts on a
   half pixel (y 351.09 at DPR 2), so every edge pixel the film only partly
   covers keeps a share of that light ground under it. Against a dark film it
   reads as a pale outline - same mechanism as the .btn--contact rim. Fix: make
   the ground the SAME colour as the film while a film is there. The chat rule
   below fades it to transparent again. */
.hero__stage:has(.hero__media) { background-color: var(--bg-dark); }
.hero.is-chatting .hero__stage { min-height: min(600px, calc(100vh - var(--header-h) - 60px)); }

/* Soft gradient cloud — lavender → blue → violet, concentrated lower-centre */
.hero__glow {
  position: absolute;
  inset: -10% -5% 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(38% 42% at 28% 82%, rgba(54, 69, 253, 0.30), transparent 70%),
    radial-gradient(44% 46% at 58% 92%, rgba(139, 123, 216, 0.34), transparent 72%),
    radial-gradient(42% 50% at 78% 78%, rgba(110, 132, 255, 0.24), transparent 72%),
    radial-gradient(34% 40% at 46% 68%, rgba(206, 188, 238, 0.34), transparent 70%),
    radial-gradient(30% 34% at 88% 96%, rgba(120, 96, 220, 0.26), transparent 72%);
  filter: blur(50px);
}

/* Faint dot grid (matches Figma background pattern) */
.hero__dots {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: radial-gradient(rgba(28, 27, 31, 0.06) 1px, transparent 1.4px);
  background-size: 46px 46px;
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 35%, #000 100%);
          mask-image: linear-gradient(180deg, transparent 0%, #000 35%, #000 100%);
}

/* Cursor-following spread glow (main.js moves it over the card) */
.hero__cursor {
  position: absolute;
  top: 0; left: 0;
  width: 680px; height: 680px;
  margin: -340px 0 0 -340px;     /* centre the circle on the pointer */
  border-radius: 50%;
  background: radial-gradient(circle, rgba(54, 69, 253, 0.38) 0%, rgba(139, 123, 216, 0.20) 38%, transparent 70%);
  filter: blur(40px);
  pointer-events: none;
  z-index: 0;
  opacity: 0;
  transition: opacity 0.45s ease;
  will-change: transform;
}
.hero.is-cursor-active .hero__cursor { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .hero__cursor { display: none; }
}

/* ── Media: the editor's film (Bunny Stream) or image, filling the card ────
   Background playback over-sizes the 16:9 player with container-query units
   so it COVERS the card (the case-hero recipe); the extra ×1.2 keeps the
   control bar, which Bunny paints along its bottom edge for a moment on
   autoplay, outside the card. Interactive modes (click / hybrid) fit the
   player instead, nothing cropped. On the chat's first focus the whole layer
   fades out (visibility flips after the fade) and hero-chat.js removes it. */
.hero__media {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  background-color: var(--bg-dark);
  transition: opacity var(--hero-dur) var(--hero-ease), visibility 0s var(--hero-dur);
}
.hero.is-chatting .hero__media { opacity: 0; visibility: hidden; pointer-events: none; }
.hero__embed {
  position: absolute;
  inset: 0;
  overflow: hidden;
  container-type: size;
}
.hero__embed iframe {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: calc(max(100cqw, 177.78cqh) * 1.2);
  height: calc(max(100cqh, 56.25cqw) * 1.2);
  border: 0;
  pointer-events: none;
}
.hero__embed.is-interactive iframe {
  top: 0;
  left: 0;
  transform: none;
  width: 100%;
  height: 100%;
  pointer-events: auto;
}
.hero__media .video-click { position: absolute; inset: 0; }

/* ── Chat column (Figma "Hero Chat Experience" 6051:7912, now inside the card)
   Order: title · flow · prompt · note, anchored to the card's bottom. Idle:
   only the prompt, 60px above the bottom edge (Figma). First focus
   (.is-chatting): the film fades, "Let’s Bring Out the Best in You." rises in
   above the prompt and the AI note unfolds under it. First send (.has-sent):
   the title rises away and the flow grows to fill the card above the prompt.
   Every step is a transition (grid rows, flex-grow, margins, padding), so
   nothing jumps. The column spans the card but only its children take
   pointer events, so an interactive film (click to play) stays clickable. */
.hero__ai {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  max-width: 650px;               /* Figma "Hero Prompt — New update" 6466:9865 */
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding-bottom: 60px;
  pointer-events: none;
  transition: padding var(--hero-dur) var(--hero-ease);
}
.hero__ai > * { pointer-events: auto; }
.hero.is-chatting .hero__ai { padding-bottom: 32px; }

/* "Let’s Bring Out the Best in You." (Figma "lets" 6051:7821): rises in from
   the prompt on first focus, rises on and fades on first send. */
.hero__ai-title-wrap {
  display: grid;
  grid-template-rows: 0fr;
  pointer-events: none;
  transition: grid-template-rows var(--hero-dur) var(--hero-ease);
}
.hero.is-chatting:not(.has-sent) .hero__ai-title-wrap { grid-template-rows: 1fr; }
.hero__ai-title {
  min-height: 0;
  margin: 0;
  text-align: center;
  font-size: var(--title-xs);
  line-height: var(--title-xs-lh);
  letter-spacing: -0.01em;
  font-variation-settings: "opsz" 14;
  color: var(--text-title);
  opacity: 0;
  visibility: hidden;
  transform: translateY(90px);    /* Figma: centre 552 (by the prompt) → 420 */
  transition: opacity 0.5s ease, transform var(--hero-dur) var(--hero-ease), visibility 0s 0.5s;
}
.hero.is-chatting:not(.has-sent) .hero__ai-title { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
.hero.has-sent .hero__ai-title { opacity: 0; transform: translateY(-160px); }   /* Figma: 420 → 260 while fading */
/* Figma: title bottom 442 → prompt top 520 */
.hero.is-chatting:not(.has-sent) .hero__ai-input { margin-top: 76px; }

/* ── Conversation flow ────────────────────────────────────────────────────
   Stays in the accessibility tree while idle (0 height, not display:none) so
   the aria-live log announces the first messages. After the first send it
   fills the card above the prompt and scrolls inside itself. */
.hero__ai-flow {
  display: flex;
  flex-direction: column;
  gap: 40px;                      /* Figma: question bubble → answer 44px */
  flex: 0 1 0px;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: none;
  padding: 0;
  /* soft edge at the card's top instead of a hard clip */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 28px);
          mask-image: linear-gradient(to bottom, transparent 0, #000 28px);
  transition: flex-grow var(--hero-dur) var(--hero-ease), padding var(--hero-dur) var(--hero-ease);
}
.hero__ai-flow::-webkit-scrollbar { display: none; }
.hero.has-sent .hero__ai-flow { flex-grow: 1; padding: 32px 0 24px; }
/* Only an overflowing history traps the scroll gesture (class set by
   hero-chat.js); over a short one the page keeps scrolling normally. */
.hero__ai-flow.is-overflowing { overscroll-behavior-y: contain; }

.hero__msg {
  font-size: var(--body-sm);
  line-height: var(--body-sm-lh);
  font-variation-settings: "opsz" 14;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.35s ease, transform 0.35s ease;
}
.hero__msg.is-in { opacity: 1; transform: none; }
/* The visitor: a bubble on the right (Figma 6051:7910) */
.hero__msg--user {
  align-self: flex-end;
  max-width: 80%;
  padding: 10px 20px;
  border-radius: 20px;
  background: rgba(255, 255, 255, 0.3);
  color: var(--text-title);
}
/* The answer: plain text on the left, no bubble (Figma 6051:7876) */
.hero__msg--bot { align-self: stretch; color: var(--text-body); }
.hero__msg-text {
  display: block;
  white-space: pre-wrap;
  word-break: break-word;         /* Safari < 15.4 fallback for the next line */
  overflow-wrap: anywhere;
}
/* Typing indicator: three pulsing dots where the answer will start */
.hero__typing { display: inline-flex; gap: 4px; align-items: center; height: var(--body-sm-lh); }
.hero__typing span {
  width: 6px; height: 6px; border-radius: 50%;
  background: rgba(28, 27, 31, 0.45);
  animation: hero-dot 1.2s infinite;
}
.hero__typing span:nth-child(2) { animation-delay: 0.2s; }
.hero__typing span:nth-child(3) { animation-delay: 0.4s; }
@keyframes hero-dot { 0%, 60%, 100% { opacity: 0.3; } 30% { opacity: 1; } }
/* Answer actions — copy · read aloud (Figma 6051:7892). Thumbs up/down need a
   feedback endpoint and the link chips need structured answers — both later. */
.hero__msg-actions { display: flex; gap: 9px; margin-top: 19px; }
.hero__msg-action {
  display: flex;
  width: 20px; height: 20px;
  padding: 0; border: 0; border-radius: 4px;
  background: transparent;
  color: var(--text-title);
  opacity: 0.8;
  cursor: pointer;
  transition: opacity 0.2s, color 0.2s;
}
.hero__msg-action svg { width: 20px; height: 20px; }
@media (hover: hover) {
  .hero__msg-action:hover { opacity: 1; color: var(--dragster-blue); }
}
.hero__msg-action:focus-visible { opacity: 1; outline: 2px solid var(--dragster-blue); outline-offset: 2px; }
.hero__msg-action.is-active { opacity: 1; color: var(--dragster-blue); }
/* Links the answer points at (server tags [[page:…]] / [[case:…]], resolved by
   hero-chat.js from the site's catalog): glass link chips (Figma 6051:7877)
   and case cards with the case's image. */
.hero__msg-refs { display: flex; flex-direction: column; gap: 12px; margin-top: 19px; }
.hero__msg-cards, .hero__msg-links { display: flex; flex-wrap: wrap; gap: 12px; }
.hero__chip {
  display: inline-flex;
  align-items: center;
  gap: 24px;
  padding: 4px 12px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.29);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
  font-size: var(--body-xs);
  line-height: var(--body-xs-lh);
  letter-spacing: -0.01em;
  color: var(--text-title);
  text-decoration: none;
  transition: background 0.2s ease;
}
.hero__chip-label { color: var(--text-body); }
.hero__chip svg { flex-shrink: 0; width: 12px; height: 12px; margin-right: -14px; transition: transform 0.25s var(--hero-ease); }   /* 24px gap before, 10px after (Figma) */
@media (hover: hover) {
  .hero__chip:hover { background: rgba(255, 255, 255, 0.6); }
  .hero__chip:hover svg { transform: translateX(3px); }
}
.hero__chip:focus-visible { outline: 2px solid var(--dragster-blue); outline-offset: 2px; }
.hero__card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: min(100%, 320px);
  color: var(--text-title);
  text-decoration: none;
}
.hero__card-media { overflow: hidden; border-radius: 12px; background: rgba(255, 255, 255, 0.3); }
.hero__card-img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  transition: transform 0.5s var(--hero-ease);
}
.hero__card-text { display: flex; flex-direction: column; font-size: var(--body-xs); line-height: var(--body-xs-lh); }
.hero__card-label, .hero__card-sub { color: var(--text-body); }
.hero__card-title { font-size: var(--body-sm); line-height: var(--body-sm-lh); }
@media (hover: hover) {
  .hero__card:hover .hero__card-img { transform: scale(1.03); }
}
.hero__card:focus-visible { outline: 2px solid var(--dragster-blue); outline-offset: 4px; border-radius: 12px; }

/* ── Prompt (Figma 6461:10022, "Hero Prompt — New update" 6808:13445: 424×48,
   white 50 %, 16/24 black text 22px in, blue 40px submit 4px from the edge).
   The GLASS is the case-hero tags' (Kajsa 2026-10-26): the form carries
   .glass-card + the tags' --fx-filter in front-page.php, so glassfilter.js lays
   the same liquid-glass backdrop under it and glass-card.css draws the same
   specular rim instead of a flat white border. glass-card.css loads AFTER this
   file, so the rules that must beat it are written .hero__ai-input.glass-card
   (0,2,0) further down. In chat mode the pill widens to the chat column. */
.hero__ai-input {
  position: relative;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  max-width: 424px;
  margin-inline: auto;
  min-height: 48px;
  padding: 4px 4px 4px 22px;      /* 4 + 40 (button) + 4 = 48; text at x 22 */
  border-radius: 24px;
  background: rgba(255, 255, 255, 0.5);
}
.hero.is-chatting .hero__ai-input { max-width: 100%; }
.hero__ai-input.glass-card {
  border-radius: 24px;
  transition: background 0.3s ease, max-width var(--hero-dur) var(--hero-ease), margin-top var(--hero-dur) var(--hero-ease);
}
/* The tags' 1px rim (.case-hero-x__tag::before), not the card's 1.5px. */
.hero__ai-input.glass-card::before { padding: 1px; }
/* .glass-card > * makes every child position: relative - the hint must stay
   absolute over the field. */
.hero__ai-input.glass-card > .hero__ai-hint { position: absolute; }
.hero__ai-input:focus-within { background: rgba(255, 255, 255, 0.62); }   /* Figma "Prompt=Active" */
.hero__ai-field {
  flex: 1;
  min-width: 0;
  max-height: 120px;
  padding: 0;
  border: 0;
  background: transparent;
  resize: none;
  font-family: var(--font);
  font-size: 16px;                /* Figma 6808:13446: 16/24 — and never below 16px: iOS zooms smaller fields */
  line-height: var(--body-sm-lh);
  letter-spacing: var(--body-sm-ls);
  font-variation-settings: "opsz" 14;
  color: #000;
  outline: none;
}
/* The field's own placeholder ("Type your message…") shows only while focused —
   in idle the rotating hint stands in for it. */
.hero__ai-field::placeholder { color: transparent; transition: color 0.2s ease; }
.hero__ai-input:focus-within .hero__ai-field::placeholder { color: rgba(0, 0, 0, 0.6); }
/* Rotating hint: two stacked layers that crossfade (hero-chat.js swaps the
   text); hidden as soon as the field is focused or holds text. */
.hero__ai-hint {
  position: absolute;
  top: 12px; left: 22px; right: 56px;   /* = the textarea's first line: (48 − 24) / 2 = 12; right = 4 + 40 + 12 gap */
  height: 24px;
  font-size: 16px;
  line-height: var(--body-sm-lh);
  letter-spacing: var(--body-sm-ls);
  font-variation-settings: "opsz" 14;
  color: rgba(0, 0, 0, 0.86);
  pointer-events: none;
  transition: opacity 0.2s ease;
}
.hero__ai-hint span {
  position: absolute;
  inset: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  opacity: 0;
  transition: opacity 0.6s ease;
}
.hero__ai-hint span.is-on { opacity: 1; }
.hero__ai-input:focus-within .hero__ai-hint,
.hero__ai-input.has-text .hero__ai-hint { opacity: 0; }
.hero__ai-send {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 50%;
  background: var(--dragster-blue);
  color: #fff;
  cursor: pointer;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.12), inset 0 0 0 0.5px rgba(255, 255, 255, 0.32), inset 0 1px 0.5px rgba(255, 255, 255, 0.24);   /* Figma: drop shadow y4 blur10 12 % */
  transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease;
}
.hero__ai-send svg { width: 24px; height: 24px; }   /* Figma arrow 24 in a 40 button */
@media (hover: hover) {
  .hero__ai-send:hover { transform: translateY(-1px); box-shadow: 0 6px 14px rgba(54, 69, 253, 0.35), inset 0 0 0 0.5px rgba(255, 255, 255, 0.32), inset 0 1px 0.5px rgba(255, 255, 255, 0.24); }
}
.hero__ai-send:focus-visible { outline: 2px solid #fff; outline-offset: -4px; }   /* inside the button: the glass pill clips anything outside it */
.hero__ai-send:disabled { opacity: 0.5; cursor: default; transform: none; }

/* AI disclosure — shown as soon as chat mode opens, i.e. before anything is
   sent. Rendered all along and collapsed with max-height, so its arrival is a
   transition like everything else, not a display:none pop. */
.hero__ai-note {
  margin: 0;
  max-height: 0;
  overflow: hidden;
  font-size: var(--body-xxs);
  line-height: 1.4;
  text-align: center;
  color: rgba(28, 27, 31, 0.6);
  opacity: 0;
  transition: max-height var(--hero-dur) var(--hero-ease), margin-top var(--hero-dur) var(--hero-ease), opacity 0.4s ease 0.3s;
}
.hero.is-chatting .hero__ai-note { max-height: 48px; margin-top: 12px; opacity: 1; }
.hero__ai-note a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
/* Screen-reader announcements for copy / read-aloud (visually hidden) */
.hero__ai-status {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Scroll hint under the card — the shared bar component; its own 12px
   padding is the Figma gap (card 917 → bar 928). */
.hero__scroll { margin-top: 0; }

@media (prefers-reduced-motion: reduce) {
  .hero__stage, .hero__media, .hero__ai, .hero__ai-title-wrap, .hero__ai-flow, .hero__ai-input, .hero__ai-input.glass-card, .hero__ai-hint span, .hero__ai-note { transition: none; }
  .hero__ai-title { transition: none; transform: none; }
  .hero.has-sent .hero__ai-title { transform: none; }
  .hero__msg { transition: none; opacity: 1; transform: none; }
  .hero__typing span { animation: none; opacity: 0.6; }
  .hero__chip svg, .hero__card-img { transition: none; }
}

/* Compact insets wherever height is scarce: touch devices (the keyboard eats
   the visual viewport — phones AND tablets) and short desktop windows. */
@media (hover: none), (max-height: 760px) {
  .hero.is-chatting .hero__ai { padding-bottom: max(16px, env(safe-area-inset-bottom)); }
  .hero.has-sent .hero__ai-flow { padding: 24px 0 16px; }
}
/* Touch devices: in chat mode the card fills the VISUAL viewport under the
   header (--chat-vh is set by hero-chat.js, so it follows the keyboard and the
   prompt stays above it); the script scrolls the card's top edge under the
   header, so the card is the whole screen — like a native chat. */
@media (hover: none) {
  .hero.is-chatting .hero__stage { min-height: calc(var(--chat-vh, 100svh) - var(--header-h)); }
}

@media (max-width: 767px) {
  /* No phone frame in Figma — these are the theme's choices. */
  .hero__inner { padding-top: calc(var(--header-h) + 24px); }
  .hero__head { grid-template-columns: minmax(0, 1fr); row-gap: 16px; }
  .hero__title, .hero__lead { grid-column: 1 / -1; max-width: none; }
  .hero__title { font-size: var(--title-md); line-height: var(--title-md-lh); letter-spacing: var(--title-md-ls); }   /* the mobile Title/Medium pair — Title/Small drops to 24px, too small for a hero */
  .hero__stage { margin-top: 24px; border-radius: 16px; aspect-ratio: 4 / 3; }  /* 4:3 keeps the film some height on a portrait screen */
  /* 4:3 box: the 16:9 player only overflows sideways, so sink it a little to
     keep the control bar below the edge (crop ≈ 12% top / 30% bottom). */
  .hero__embed:not(.is-interactive) iframe { top: 58%; }
  .hero__ai { padding-inline: 16px; padding-bottom: 16px; }
  .hero__ai-title { font-size: 26px; line-height: 34px; }
  .hero.is-chatting:not(.has-sent) .hero__ai-input { margin-top: 40px; }
  .hero__ai-field, .hero__ai-hint { font-size: 16px; }   /* 4 of the 5 prompts fit the hint at 16px; still no iOS zoom */
  .hero__msg--user { max-width: 92%; }
  .hero.is-chatting .hero__ai-flow { -webkit-overflow-scrolling: touch; }

}

/* ── Chat mode: the hero SECTION becomes the chat's ground (2026-10-05) ────
   When the chat starts, the glow and the dot grid stop being a layer inside
   the card and become the background of the whole hero section.

   It is a pure CROSSFADE: .hero__bg fades in while the card's own copy of the
   same two layers fades out and the card's fill goes transparent. Nothing
   changes size or position, so the film's fade is exactly what it always was.

   A first attempt grew the card to full bleed instead — dropping the
   container width, the radius and the aspect ratio. The card then changed
   geometry while the film was still fading and the whole hero lurched
   (Kajsa 2026-10-05). Do not reach for layout again: the ground is a fade.

   The headline block fades and slides out of frame but KEEPS its space, which
   is now part of the glow — that is what lets the card stay put. */
.hero__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;              /* the glow is inset -5% sideways; without this it would widen the page */
  opacity: 0;
  transition: opacity var(--hero-dur) var(--hero-ease);
}
.hero.is-chatting .hero__bg { opacity: 1; }
.hero__inner { z-index: 1; }     /* the content rides above the ground */

/* The headline slides out of frame; its space stays and becomes glow. */
.hero__head {
  transition: opacity 0.45s ease, transform var(--hero-dur) var(--hero-ease);
}
.hero.is-chatting .hero__head {
  opacity: 0;
  transform: translateY(-48px);
  pointer-events: none;
}

/* The card hands its ground to the section: the fill goes transparent and its
   own glow + dots fade out, so the two never stack and double up. */
.hero__stage > .hero__glow,
.hero__stage > .hero__dots {
  transition: opacity var(--hero-dur) var(--hero-ease);
}
.hero.is-chatting .hero__stage {
  background-color: transparent;
  transition: min-height var(--hero-dur) var(--hero-ease),
              background-color var(--hero-dur) var(--hero-ease);
}
.hero.is-chatting .hero__stage > .hero__glow,
.hero.is-chatting .hero__stage > .hero__dots { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  .hero__bg,
  .hero__head,
  .hero__stage > .hero__glow,
  .hero__stage > .hero__dots { transition: none; }
  .hero.is-chatting .hero__head { transform: none; }
}

/* ── SVG background curves ───────────────────────────────────────────────── */

.section__curve {
  position: absolute;
  left: 50%;
  /* Figma 3486:26931: the curve in this section is MIRRORED horizontally
     (loop on the right, bright tail exiting bottom-left) and its ink starts
     262px from the section top (geometry top 291 − 29 half-stroke). */
  transform: translateX(-50%) scaleX(-1);
  top: 262px;
  /* Original Figma svg is 1440×781. It spans the full section width and past
     1440px scales UNIFORMLY (aspect-ratio locks height to width) so shape and
     stroke keep their proportions; the svg clips the path's off-canvas ends
     just like the Figma frame does. */
  width: max(1440px, 100vw);
  height: auto;
  aspect-ratio: 1440 / 781;
  pointer-events: none;
  z-index: 0;
}
/* Drawn in on scroll (main.js smoothDraw sets the exact length); large initial
   dashoffset keeps the path hidden before the script runs. */
.section__curve-path {
  stroke-dasharray: 9000;
  stroke-dashoffset: 9000;
}

/* ── Generic page hero (About, Contact, Careers, etc.) ───────────────────── */
.page-hero {
  position: relative;
  padding-top: calc(var(--header-h) + 80px);
  padding-bottom: 80px;
  background-color: var(--bg-primary);
  background-size: cover;
  background-position: right center;
  background-repeat: no-repeat;
  min-height: 80vh;
  display: flex;
  align-items: center;
  overflow: hidden;
}

.page-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, var(--bg-primary) 0%, var(--bg-primary) 50%, transparent 100%);
  pointer-events: none;
  z-index: 2;
}

.page-hero .container { position: relative; z-index: 3; }

/* ── Carousel variant (full-bleed image, content bottom) ─────────────────── */
.page-hero--carousel {
  background: transparent;
  min-height: 100svh;
  max-height: 1024px;
  padding: 0;
  align-items: flex-end;        /* content sits at the bottom */
}
.page-hero--carousel::before { content: none; }   /* no light gradient */

.page-hero__carousel {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* Slide-over carousel (Figma proto 1841-3648): the next image pushes in from
   the right edge and sweeps left across the current one, which stays put
   beneath (.is-under) until it is fully covered. The wrapper is its own
   stacking context (z-index: 0), so slide z-indexes never beat the gradient. */
.page-hero__slide {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  visibility: hidden;
  transform: translateX(100%);
  transition: transform 1.1s cubic-bezier(0.65, 0, 0.25, 1), visibility 0s 1.1s;
  z-index: 1;
}
.page-hero__slide.is-active {
  visibility: visible;
  transform: translateX(0);
  z-index: 3;
  /* Visibility must flip IMMEDIATELY on the way in — the base rule's 1.1s
     visibility delay is only for hiding after the slide-out completes. */
  transition: transform 1.1s cubic-bezier(0.65, 0, 0.25, 1), visibility 0s 0s;
}
/* The outgoing slide pushes out to the LEFT in sync with the incoming one —
   a conveyor move; it goes hidden only after the 1.1s exit completes. */
.page-hero__slide.is-under {
  visibility: visible;
  transform: translateX(-100%);
  z-index: 2;
  transition: transform 1.1s cubic-bezier(0.65, 0, 0.25, 1), visibility 0s 1.1s;
}
@media (prefers-reduced-motion: reduce) {
  .page-hero__slide { transition: none; }
}

/* Dark gradient at the bottom so the white text stays readable */
.page-hero__gradient {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,0) 45%, rgba(0,0,0,0.55) 100%);
  pointer-events: none;
  z-index: 1;
}

.page-hero--carousel .container { position: relative; z-index: 2; width: 100%; }

.page-hero__bottom {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 40px;
}

.page-hero--carousel .page-hero__title {
  font-size: var(--title-lg);        /* 80px */
  line-height: var(--title-lg-lh);   /* 86px */
  letter-spacing: -0.02em;
  color: #fff;
  max-width: 1000px;
  margin: 0;
}

.page-hero__control {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-shrink: 0;
}
.page-hero__view {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  text-align: right;
  color: #fff;
  text-decoration: none;
  font-size: var(--body-sm);
  line-height: 24px;
}

/* ── Carousel Control Button ─────────────────────────────────────────────── */
.carousel-control {
  position: relative;
  flex-shrink: 0;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.35);   /* faint track — the ring draws the progress */
  background: transparent;
  color: white;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
}

.carousel-control:hover {
  background: rgba(255, 255, 255, 0.1);
  border-color: white;
}

/* Progress ring — fills clockwise over one slide interval (keep the 5s in
   sync with INTERVAL in main.js); freezes while the carousel is paused and
   restarts on every slide change (main.js re-triggers the animation). */
.carousel-control__ring {
  position: absolute;
  inset: -2px;
  width: calc(100% + 4px);
  height: calc(100% + 4px);
  transform: rotate(-90deg);
  pointer-events: none;
}
.carousel-control__ring-fill {
  fill: none;
  stroke: #fff;
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-dasharray: 188.5;   /* 2πr, r = 30 */
  stroke-dashoffset: 188.5;
  animation: dsr-carousel-ring 5s linear forwards;
}
.page-hero--carousel.paused .carousel-control__ring-fill { animation-play-state: paused; }
@keyframes dsr-carousel-ring { to { stroke-dashoffset: 0; } }

.carousel-control__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
}

.carousel-control__icon svg {
  width: 24px;
  height: 24px;
  transition: opacity 0.3s ease;
}

/* Text label ("Pause"/"Play") — hidden by default; the carousel hero shows it
   next to the icon on mobile only (see page-all-case-studies.css). */
.carousel-control__label { display: none; }

.carousel-control.paused .carousel-control__icon {
  display: none;   /* remove the pause icon entirely so the triangle centers */
}

.carousel-control.paused::after {
  content: '';
  display: block;
  width: 0;
  height: 0;
  border-left: 13px solid white;
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
  transform: translateX(2px);   /* optical centering of the triangle */
}

.page-hero__content {
  max-width: 620px;
}

.page-hero__type {
  display: inline-block;
  font-size: var(--body-sm);
  color: var(--dragster-blue);
  font-weight: 500;
  margin-bottom: 24px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.page-hero__title {
  font-size: var(--title-lg);
  font-weight: 400;
  letter-spacing: -0.02em;
  color: var(--text-title);
  line-height: var(--title-lg-lh);
  margin-bottom: 32px;
}

.page-hero__tagline {
  font-size: var(--body-lg);
  color: var(--text-body);
  line-height: var(--body-lg-lh);
  margin-bottom: 48px;
  max-width: 540px;
}

.page-hero__lead {
  font-size: var(--title-xs);
  font-weight: 400;
  color: var(--text-body);
  margin-top: 24px;
  max-width: 660px;
}

/* ── Responsive ──────────────────────────────────────────────────────────── */
@media (max-width: 1024px) {
  .page-hero {
    padding-top: calc(var(--header-h) + 60px);
    padding-bottom: 60px;
    background-position: right;
    min-height: 60vh;
  }

  .page-hero__title {
    font-size: var(--title-md);
    line-height: var(--title-md-lh);
  }

  .page-hero__tagline {
    font-size: var(--body-md);
    line-height: var(--body-md-lh);
  }

  .carousel-control {
    width: 56px;
    height: 56px;
  }
}

@media (max-width: 767px) {
  .page-hero {
    padding-top: calc(var(--header-h) + 40px);
    padding-bottom: 40px;
    background-image: none !important;
    min-height: auto;
  }

  .page-hero::before {
    background: transparent;
  }

  .page-hero__content {
    max-width: 100%;
  }

  .page-hero__type {
    font-size: var(--body-xs);
    margin-bottom: 16px;
  }

  .page-hero__title {
    font-size: var(--title-sm);
    line-height: var(--title-sm-lh);
    margin-bottom: 20px;
  }

  .page-hero__tagline {
    font-size: var(--body-md);
    line-height: var(--body-md-lh);
    margin-bottom: 32px;
  }

  .carousel-control {
    width: 48px;
    height: 48px;
    bottom: 20px;
    right: 20px;
  }

  .carousel-control__icon svg {
    width: 20px;
    height: 20px;
  }

  .carousel-control.paused::after {
    border-left: 10px solid white;
    border-top: 6px solid transparent;
    border-bottom: 6px solid transparent;
  }
}

/* ── Case Hero ────────────────────────────────────────────────────────────── */
.case-hero {
  position: relative;
  overflow: hidden;
  padding: calc(var(--header-h) + 80px) 0 80px;
  background-color: var(--bg-primary);
  background-size: cover;
  background-position: right center;
  background-repeat: no-repeat;
  min-height: 70vh;
  display: flex;
  align-items: center;
}

.case-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;                 /* above the .media-fill picture (z-index 0) */
  background: linear-gradient(90deg, var(--bg-primary) 0%, var(--bg-primary) 55%, transparent 100%);
  pointer-events: none;
}

.case-hero .container { position: relative; z-index: 2; }

.case-hero__content {
  max-width: 620px;
}

.case-hero__type {
  display: inline-block;
  font-size: var(--body-xs);
  color: var(--dragster-blue);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-right: 16px;
  margin-bottom: 24px;
}

.case-hero__year {
  display: inline-block;
  font-size: var(--body-xs);
  color: var(--text-body);
  font-weight: 400;
}

.case-hero__client {
  font-size: var(--body-md);
  color: var(--text-body);
  margin-bottom: 16px;
}

.case-hero__title {
  font-size: var(--title-lg);
  font-weight: 400;
  letter-spacing: -0.02em;
  color: var(--text-title);
  line-height: var(--title-lg-lh);
  margin-bottom: 32px;
}

.case-hero__tagline {
  font-size: var(--body-lg);
  color: var(--text-body);
  line-height: var(--body-lg-lh);
  max-width: 540px;
}


/* -- Home hero: exactly one screen tall ------------------------------------
   Kajsa 2026-10-06. Idle the hero came out 920px on a 900px screen, so the
   scroll bar sat just under the fold. The parts are fixed - 124 padding, 150
   headline, 40 gap, 48 scroll bar, 8 padding = 370 - and the only elastic one
   is the card, whose height comes from its 1340:604 ratio.

   So the inner column is a flex box and the card SHRINKS to whatever is left.
   flex: 0 1 auto, never 1 1: allowed to grow, the card would be 710 tall on a
   1080 screen and the designed ratio would be gone. Spare height instead
   collects above the scroll bar, which keeps it on the bottom edge where the
   'scroll to explore more' line belongs.

   CHAT MODE IS EXEMPT. .hero.is-chatting .hero__stage asks for min-height
   min(600px, 100vh - header - 60) on pointer screens and --chat-vh on touch,
   which is more than the idle leftover; held to a hard 100svh the card would
   be cut off by .hero's overflow: hidden. height: auto + min-height keeps
   exactly today's behaviour there, and revealStage() already scrolls the card
   into view. */
.hero { height: 100svh; }

/* Min and max on the same height (Kajsa 2026-10-06). The fixed parts above and
   below the card add up to 382px, so the card gets whatever is left:
     820  floor - card lands at 438, ratio 2.78 at 1220 wide. Below this the
          hero stops shrinking and runs past the fold INSTEAD of flattening the
          card further; without it a 700px window gave a 3.52 letterbox.
          It only binds under ~820px of viewport, so 900 and 1080 never see it.
    1024  cap - the same ceiling .expertise-hero already uses.
          The card is ratio-capped at 550 anyway (flex: 0 1 auto never grows),
          so above ~932px the extra height is just air above the scroll bar;
          the cap stops that air running away on a very tall display.
   Phones keep the plain 100svh below: their content adds up to about 647px, so
   a 820 floor would only add slack, and the card there is 4:3 by design. */
/* 932 = the 382px of fixed parts above the card (padding + headline + the 40px
   gap + scroll bar + 8) PLUS the card's own 550. At that floor the card can
   always have its designed height, so nothing ever squashes it. Below 932 of
   viewport the hero simply runs past the fold, which is the documented trade:
   a hero taller than the screen beats a card that changes shape (Kajsa
   2026-10-09). The old 820 floor left 438px for a 550px card, so on a very
   ordinary 1440x800 laptop the card came out at ratio 2.79 against Figma's
   2.22 and the film cropped harder. */
/* Kajsa 2026-10-12: the desktop hero fills the screen, exactly one viewport.
   This REVERSES the 2026-10-09 decision above - read that note first, it is
   still the honest account of what the clamp bought. The floor of 932px
   existed so the card always had room for its designed 1340/604, and the price
   was a hero taller than the screen on an ordinary laptop. The price is now the
   other way round: on a short screen the card goes flatter than Figma.

   flex-shrink MUST come back with it. The card carries an aspect-ratio and
   shrink: 0, so at a definite 100svh it would simply refuse to fit and .hero's
   overflow: hidden would CLIP the scroll bar instead - the exact failure the
   2026-10-09 note warns about. With shrink back on, the card gives way and
   everything stays inside the viewport.

   The auto margin on .hero__head is untouched, so on a TALL screen the slack
   still collects above the card and the designed ratio is kept; only screens
   too short to hold 382px of fixed chrome plus a 550px card flatten it. */
@media (min-width: 768px) {
  .hero { height: 100svh; }
}

.hero__inner {
  display: flex;
  flex-direction: column;
  height: 100%;
}
/* flex-shrink 0, not 1: the card HAS an aspect-ratio, and shrink is what was
   overriding it. With the floor above there is never anything to shrink away,
   so the ratio simply always wins. Grow stays 0 - letting it grow would break
   the ratio the other way and crop the film even harder on a tall screen. */
.hero__stage { flex: 0 0 auto; }
/* The leftover height goes ABOVE the card, under the intro, instead of below
   it. The card's bottom then sits the same distance over the scroll bar at
   every height, and the only thing that moves is the airiest part of the
   layout. .hero__stage keeps its 40px margin-top as the minimum. */
.hero__head { margin-bottom: auto; }
.hero__scroll { margin-top: 0; }

/* NO floor under the card, deliberately. .hero carries overflow: hidden for the
   cursor glow, so a floor would not make the hero grow on a short screen - it
   would push the scroll bar past a definite height and get it CLIPPED, which is
   worse than a flat card. The card therefore absorbs the whole difference:
   measured 2.22 at 1080 and on phones (untouched), 2.30 at 900, 3.52 at 700.
   A 700px-tall window simply cannot hold 370px of fixed chrome plus a 2.22
   card; if that screen matters more than the exact screen height, the answer is
   to go back to min-height and let the hero run past the fold there. */

/* Chat mode is exempt: the stage asks for min-height min(600px, ...) there,
   more than the idle leftover, and a definite 100svh would cut it off. */
.hero.is-chatting { height: auto; min-height: 100svh; }

/* ── Phone: the slack goes BELOW the card, not above it ─────────────────
   The two rules just above are a DESKTOP decision (2026-10-09): on a wide
   screen the only elastic part is the air under the intro, and parking the
   leftover height there keeps the card a constant distance above the scroll
   bar. On a phone the same rule dumps everything into one hole and pushes the
   card onto the bottom edge. Measured on the live page: 6px of air at 375x667
   but 175px at 375x812, 196px at 390x844 and 230px at 414x896 - it GROWS with
   the screen, and the card's lower edge landed at 788 of 844 / 840 of 896,
   right at the fold where iOS draws its toolbar. That is why the film read as
   hidden by the section below (Kajsa 2026-10-12).

   This block MUST come last in the file. The rules it overrides are global,
   not inside a min-width query, so an override placed in the earlier 767
   block loses on source order at equal specificity - which is exactly what
   happened on the first attempt. And the auto margin belongs on .hero__scroll,
   the flex child: .scroll-bar is nested INSIDE it and margin-top there does
   nothing to the hero's column. */
@media (max-width: 767px) {
  .hero__head { margin-bottom: 0; }
  .hero__scroll { margin-top: auto; }
}

/* ── The dark hairline around the card's rounded corners ─────────────────
   .hero__stage rounds 20px and clips; .hero__media sat inside it as a SQUARE
   box filled #1C1B1F, with the film's iframe on top. An iframe is composited
   as its own layer, so its clipped edge is antialiased a hair differently from
   the background painted beneath it - and in the curve that seam exposed the
   square black box underneath. Against the near-white page it reads as a dark
   outline, and only on the curve, never along the straight edges (Kajsa
   2026-10-12).

   Same shape as the pale rim on .btn--contact: the colour comes from the
   GROUND under the layer, not from the layer's own edge. So the fix is the
   same in spirit - stop the ground from having a corner there. Rounding the
   inner layers to the parent's curve means no square black corner exists for
   the seam to reveal.

   border-radius: inherit, not a repeated 20px: the stage drops to 16px on a
   phone and grows again on desktop, and a hardcoded number would silently
   stop matching at one of those breakpoints. */
.hero__media { border-radius: inherit; }
.hero__embed { border-radius: inherit; }

/* ── Desktop: let the card give way again ────────────────────────────────
   Pair to the 100svh height above. It has to sit at the END of the file: the
   rule it overrides, .hero__stage { flex: 0 0 auto }, is GLOBAL and declared
   further down, so an override placed up there loses on source order at equal
   specificity. Measured when I made exactly that mistake: the hero filled the
   screen but the card stayed 1220x550, so at 1440x800 the content ran 124px
   past the hero and overflow: hidden ate the scroll bar.
   min-height: 0 because a flex item's automatic minimum can otherwise refuse
   to shrink past its content. */
@media (min-width: 768px) {
  .hero__stage { flex: 0 1 auto; min-height: 0; }
}

/* ── The scroll bar is an ANCHOR, so it must not move ────────────────────
   Two things were wrong and they share one cause: the leftover height sat
   ABOVE the card, so the bar was welded to the card's lower edge (measured
   gap: 0px at every size) and inherited every change in the card's height.
   Entering chat mode therefore shoved it +22px at 1920x960, +40 at 1440x900,
   +60 at 1280x720 - and -98 at 1440x1080, i.e. it jumped BOTH ways depending
   on the screen, and landed below the fold on three sizes out of four
   (Kajsa 2026-10-12).

   Now the slack sits BELOW the card, exactly as on a phone: the bar is pinned
   to the bottom of the hero and the card grows down into the slack instead of
   pushing anything. The bar then sits at the same place in both states and at
   every screen height, which is what an affordance that says "scroll" needs.

   On a SHORT screen there is no slack to eat - the card is already shrunk to
   fit - so the head gives up its height in chat mode instead. It is faded out
   and translated away by then, so nothing visible is lost, and the card grows
   UPWARD into that space. Both move on the same --hero-dur clock as the rest. */
@media (min-width: 768px) {
  /* The head owns the minimum gap to the card (the card's own margin-top is
     `auto` below), and never shrinks: it has overflow: hidden, so letting flex
     squeeze it clipped the third line of the headline (Kajsa 2026-10-13). */
  .hero__head { margin-bottom: 40px; flex-shrink: 0; }
  /* Kajsa 2026-10-13: 8px gap under the card instead of `auto`. With `auto` the
     bar was pinned to the bottom of the hero; with 8px it follows the card, and
     any slack ends up BELOW the bar. */
  .hero__scroll { margin-top: 8px; }
  /* Kajsa 2026-10-13: the slack goes ABOVE the card (it replaces the base 40px),
     so card and scroll bar sit together at the bottom of the hero. */
  .hero__stage { margin-top: auto; }
  .hero__head {
    transition: opacity var(--hero-dur) var(--hero-ease),
                transform var(--hero-dur) var(--hero-ease),
                height var(--hero-dur) var(--hero-ease),
                margin-top var(--hero-dur) var(--hero-ease),
                margin-bottom var(--hero-dur) var(--hero-ease);
    overflow: hidden;
  }
  .hero.is-chatting .hero__head { height: 0; margin-top: 0; margin-bottom: 0; }

  /* Chat mode sets .hero to height: auto (it must be free to grow past the
     screen on a short one), and .hero__inner is height: 100% - which against
     an auto parent resolves to auto. The inner box then shrink-wraps its
     content and margin-top: auto on the bar has NO free space to push into,
     so the bar stopped hugging the bottom and floated mid-hero: measured -68px
     at 1440x900 and -248px at 1440x1080, i.e. a worse jump than before, just
     upwards. Giving the inner box its own floor restores the push. */
  .hero.is-chatting .hero__inner { min-height: 100svh; }
}

/* -- Home hero head on desktop: the Dragster Effect band's layout (Kajsa 2026-10-15) --
   Two equal halves with a 100px gutter, title left, intro right, instead of a 428px
   title and a 433px intro that stay that size on a wide screen and leave the left half
   empty. Same title step as before (--title-sm, Figma's 40/50 at 1440, fluid above it);
   the intro goes from Body/Small to Body/Medium so it holds its own beside it. >=1025
   only - tablet and phone keep their own head. Last in the file on purpose: the head
   rules it overrides are global and declared earlier at equal specificity. */
@media (min-width: 1025px) {
  .hero__head { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--space-100); }
  /* ALWAYS three lines (Kajsa 2026-10-15): the width is in EM, so it scales with the fluid title size and the line count cannot change with the screen. 14em is the middle of the three-line window (about 11em breaks to four, about 17em to two). */
  .hero__title { grid-column: 1; max-width: 14em; }
  .hero__lead {
    grid-column: 2;
    max-width: 610px;
    font-size: var(--body-md);
    line-height: var(--body-md-lh);
    letter-spacing: var(--body-md-ls);
  }
}

/* -- Hero card takes the spare height (Kajsa 2026-10-15) --------------------
   Spare height used to collect ABOVE the card (head margin-bottom: auto) and keep
   the card at its designed ratio. Now the card GROWS into it instead: the head sits
   against the card and the card is flex-grow: 1, so on a tall screen the video is
   taller, not the gap. Shrink still works (flex: 0 1 auto above), so a short screen
   behaves as before. Grow is on in chat mode too: a stage that is flex-grow 0 there
   would drop from its grown idle height to the chat height in one frame, which is
   the jump this hero has fought before. Desktop/tablet only; the phone card keeps
   its 4:3. */
@media (min-width: 768px) {
  /* 40px between the text and the card (Figma's gap). Setting this to 0 when the card started growing removed the gap altogether - the stage's own margin-top does not apply there (Kajsa 2026-10-15). */
  .hero:not(.is-chatting) .hero__head { margin-bottom: 40px; }
  .hero .hero__stage { flex-grow: 1; }
}

/* -- Phone: the card takes the spare height too (Kajsa 2026-10-15) ------------
   The 100svh hero left ~150px of air between the 4:3 card and the scroll bar on an
   812px phone. The card now GROWS into it (4:3 stays as the floor), so the film is
   taller instead of the gap. Shrink stays off, as before, so a short screen does not
   crush the card. Last in the file: the global .hero__stage { flex: 0 0 auto } is
   declared further down and would win on source order. Chat mode keeps grow on too,
   so the card never changes size in one frame when the chat opens. */
@media (max-width: 767px) {
  /* 12px of air above the scroll bar: with the card growing there is no auto-margin slack left to give it any. */
  .hero .hero__stage { flex-grow: 1; margin-bottom: 12px; }
  /* Chat mode makes .hero height:auto, so against it the inner column has no spare height and the grown card would drop back to 4:3 for a frame before the chat height takes over. Its own floor keeps the slack, same as desktop. */
  .hero.is-chatting .hero__inner { min-height: 100svh; }
}

/* -- No dark ground under the card's rounded edge (Kajsa 2026-10-15) ----------
   The 2026-10-13 fix for the PALE rim put a dark ground (#1C1B1F) under the film so
   a dark film would not show light edge pixels. That swaps the problem rather than
   solving it: a LIGHT film (the pale-blue clip) now shows the dark ground through
   every partly covered edge pixel in the curve, i.e. a black rim. The ground can only
   be right for one brightness, and the films vary.
   So the ground stops reaching the edge: the stage itself is transparent and the dark
   fill on .hero__media is held 2px inside it (padding + content-box), which still
   gives a dark card before the film has loaded but leaves nothing underneath the
   antialiased rim to show through. The iframe/poster are positioned against the
   padding box, so they still fill the card edge to edge. Last in the file: the two
   rules it overrides are declared earlier at equal specificity. */
.hero__stage:has(.hero__media) { background-color: transparent; }
.hero__media { padding: 2px; background-clip: content-box; }

/* No glow under the pointer on the home hero (Kajsa 2026-10-30): the pearl trail
   (pearl-cursor.js) is the only cursor effect. main.js still moves the element. */
.hero__cursor { display: none; }

/* No gradient cloud behind the chat (Kajsa 2026-11-02). Both copies - the card's
   idle one and .hero__bg's chat-mode one - are off; the dot grid stays. The
   markup is left in front-page.php, so bringing it back is deleting this rule. */
.hero__glow { display: none; }
