/* ================================================================================================
   HOME: hero slider -- vocabulary layer (position / overlay / motion / height / controls)
   ================================================================================================
   Loaded after site.css. site.css still owns the hero's bones (the .hero/.hero-viewport/
   .hero-slide/.hero-scrim/.hero-content box model, the crossfade, the Ken Burns keyframes, the
   scrim formula, the stagger-in animation) and the SAFE DEFAULT for every enum -- scrim-navy,
   mid-left, kenburns, standard height. Every rule in this file is an attribute-scoped variant on
   top of that default, so a slide with a missing or bad data-pos/data-overlay/data-motion/
   data-height value silently renders as the safe default instead of unstyled markup: nothing here
   matches an absent or unrecognised attribute value, so the plain site.css rule is what's left.

   All six data-pos values, five data-overlay values and both data-motion values live on the same
   `.hero-slide` element (see the DOM contract), so every selector below reads off `.hero-slide`
   directly rather than threading attributes through descendants.
   ================================================================================================ */

/* ---------------------------------------------------------------------------------------------
   HEIGHT -- data-height lives on the outer .hero, not the slide, because it's a slider-wide
   setting (site_settings group 'slider'), not a per-slide one.
   --------------------------------------------------------------------------------------------- */
.hero[data-height="compact"] .hero-viewport,
.hero[data-height="compact"] .hero-content { min-height: clamp(360px, 58svh, 520px); }
.hero[data-height="tall"] .hero-viewport,
.hero[data-height="tall"] .hero-content { min-height: clamp(560px, 88svh, 860px); }
/* "standard" and anything unrecognised fall through to site.css's clamp(460px, 74svh, 720px). */

/* ---------------------------------------------------------------------------------------------
   NEW ELEMENT -- .hero-proof (the DOM contract's trust line under the actions row) has no prior
   styling anywhere in site.css to refine; this is its only rule. Kept deliberately quiet (small,
   soft-white) since it's a supporting line under a headline and a CTA pair, not competing with
   either. Included in the panel-white text-theme and light-text-shadow blocks further down.
   --------------------------------------------------------------------------------------------- */
.hero-proof { margin-top: 22px; font-size: 0.86rem; font-weight: 600;
  color: color-mix(in oklch, white 82%, transparent); }

/* ---------------------------------------------------------------------------------------------
   POSITION -- 6 slots (a revision to the original 3-slot plan).

   Vertical: mid-* centres the text column inside the slide; low-* drops it to the slide's own
   bottom padding (already 72px/104px in site.css) instead of centring through it, so that
   padding reads as real air above the controls bar rather than being swallowed by centring.

   Horizontal: align-items is the single knob for left/center/right because .hero-content is a
   column flex box and align-items governs the CROSS-axis of every one of its children equally.
   .hero-actions is just another child of that box, so the CTA pair moves with the headline by
   construction -- there is no second place that has to be kept in sync.

   There is deliberately no "top" slot. The site header is position:sticky and translucent, so it
   floats OVER the hero instead of pushing it down; text anchored to the top of the band sits
   directly under the logo/nav on anything shorter than a very tall desktop viewport. Don't add a
   top-* value back without first moving the header out of the hero's stacking context -- this
   was cut on purpose, not an oversight.
   --------------------------------------------------------------------------------------------- */
.hero-slide[data-pos^="mid-"] .hero-content { justify-content: center; }
.hero-slide[data-pos^="low-"] .hero-content { justify-content: flex-end; }

/* mid-left / low-left need nothing further: align-items:flex-start + text-align:left is
   site.css's own default, i.e. the safe degrade target for a missing/bad data-pos. */
.hero-slide[data-pos$="-center"] .hero-content { align-items: center; text-align: center; }
.hero-slide[data-pos$="-right"] .hero-content { align-items: flex-end; text-align: right; }

/* MOBILE COLLAPSE: below the header's existing 860px breakpoint the band is nearly square and
   a right-anchored column has nowhere to go without crowding the opposite edge or the header's
   own controls. Collapse -right to its -left twin; -center already reads fine at any width so
   it's left alone. This is a deliberate simplification, not a bug -- if a phone screenshot shows
   the CTA on the "wrong" side of a slide the client picked as mid-right, that's this rule
   working as designed, not a regression to chase. */
@media (max-width: 860px) {
  .hero-slide[data-pos$="-right"] .hero-content { align-items: flex-start; text-align: left; }
}

/* ---------------------------------------------------------------------------------------------
   OVERLAY -- 5 treatments. Direction/shape is derived from data-pos so the wash always falls on
   the side the text actually sits on; a left gradient under a right-anchored headline is exactly
   the bug this is written to avoid.

   scrim-navy / scrim-soft reuse site.css's --scrim-dir / --scrim-mix custom properties on
   .hero-scrim (see the comment there) instead of restating the five-stop gradient per
   combination -- soft only touches the mix (intensity), right/center only touch the direction
   or shape, so the two knobs combine freely across all six positions from a handful of rules.
   --------------------------------------------------------------------------------------------- */

/* scrim-soft: same shape as scrim-navy, roughly half the peak alpha -- for photos that are
   already dark enough not to need the full wash. 0.52 lands scrim-soft's peak alpha at ~0.45
   against the ~0.85-0.88 --scrim values the manifest actually produces, matching the brief's
   "~0.45" target without hand-tuning a second five-stop formula. */
.hero-slide[data-overlay="scrim-soft"] .hero-scrim { --scrim-mix: calc(var(--scrim) * 0.52); }

/* Mirror the wash for a right-anchored slide: same stops, gradient line reversed so 0% (the
   opaque end) lands on the right edge instead of the left. */
.hero-slide[data-pos$="-right"] .hero-scrim { --scrim-dir: 270deg; }
@media (max-width: 860px) {
  /* Mirrors the content collapse above: once -right has folded back to a left-anchored column,
     the wash needs to fall left too, or the darkest part of the photo ends up under nothing. */
  .hero-slide[data-pos$="-right"] .hero-scrim { --scrim-dir: 90deg; }
}

/* Centre position can't be produced by flipping an angle -- it needs its own symmetric shape,
   a plateau in the middle fading to transparent on BOTH edges, mirrored around the 50% stop.
   Still driven by --scrim-mix so scrim-navy/scrim-soft share this one rule. */
.hero-slide[data-pos$="-center"] .hero-scrim {
  background:
    linear-gradient(90deg,
      transparent 0%,
      color-mix(in oklch, var(--brand-deeper) calc(var(--scrim-mix) * 6%), transparent) 10%,
      color-mix(in oklch, var(--brand-deeper) calc(var(--scrim-mix) * 45%), transparent) 30%,
      color-mix(in oklch, var(--brand-deeper) calc(var(--scrim-mix) * 92%), transparent) 45%,
      color-mix(in oklch, var(--brand-deeper) calc(var(--scrim-mix) * 100%), transparent) 50%,
      color-mix(in oklch, var(--brand-deeper) calc(var(--scrim-mix) * 92%), transparent) 55%,
      color-mix(in oklch, var(--brand-deeper) calc(var(--scrim-mix) * 45%), transparent) 70%,
      color-mix(in oklch, var(--brand-deeper) calc(var(--scrim-mix) * 6%), transparent) 90%,
      transparent 100%),
    linear-gradient(0deg, color-mix(in oklch, var(--brand-deeper) 62%, transparent) 0%, transparent 42%);
}

/* panel-navy / panel-white / none all drop the horizontal wash. This must be the LAST rule
   touching .hero-scrim's background in this file so it wins over the -center formula above for
   a panel/none slide that also happens to be centred -- same selector specificity, later wins.
   The bottom vignette is kept even for "none": the controls bar (arrows/dots/play-pause) is
   always rendered regardless of overlay choice, and a bright photo bottom would otherwise leave
   it with no contrast help at all. This is a deliberate reading of "none" as "no TEXT wash", not
   literally zero pixels -- flag it if the client explicitly wants the controls unprotected too. */
.hero-slide[data-overlay^="panel-"] .hero-scrim,
.hero-slide[data-overlay="none"] .hero-scrim {
  background: linear-gradient(0deg, color-mix(in oklch, var(--brand-deeper) 62%, transparent) 0%, transparent 42%);
}

/* panel-navy / panel-white: a solid card sized to the text rather than a wash over the whole
   photo. This is the reliable answer for a bright text region (live slide 2's body-composition
   chart, measured mean RGB 245/241/237) that no amount of gradient can fix without swallowing
   the photo entirely.

   There's no wrapper element around just the text stack in the DOM contract -- .hero-content
   itself is both "the full-height positioning box" and "the text stack", doing double duty.
   width:fit-content resolves that: a column flex container sized to fit-content takes the width
   of its widest child (the h1, almost always) and every shorter child still gets positioned
   inside THAT width by the existing align-items/text-align rules above, so the card ends up
   hugging the actual text instead of being an arbitrary fixed-size rectangle. The trade-off:
   an unusually long CTA label could stretch the card wider than the headline: treat button
   labels the same way you'd treat headline length, not as a separate constraint.

   margin-inline replaces .shell's margin-inline:auto centring (which would otherwise always
   centre the now-narrow box regardless of data-pos) with an explicit push to whichever edge
   data-pos asks for. */
.hero-slide[data-overlay^="panel-"] .hero-content {
  width: fit-content;
  max-width: min(58ch, calc(100% - clamp(36px, 8vw, 88px)));
  padding-inline: clamp(22px, 3vw, 34px);
  padding-block: clamp(20px, 2.6vw, 30px);
  margin-inline: clamp(18px, 4vw, 44px) auto; /* default = flush left */
  border-radius: 4px 18px 18px 4px;
  box-shadow: 0 26px 50px -22px rgba(4, 12, 26, 0.55);
}
.hero-slide[data-overlay^="panel-"][data-pos$="-center"] .hero-content {
  margin-inline: auto;
  border-radius: 16px;
}
.hero-slide[data-overlay^="panel-"][data-pos$="-right"] .hero-content {
  margin-inline: auto clamp(18px, 4vw, 44px);
  border-radius: 18px 4px 4px 18px;
}
@media (max-width: 860px) {
  /* Follows the same -right-collapses-to-left rule as everywhere else in this file. */
  .hero-slide[data-overlay^="panel-"][data-pos$="-right"] .hero-content {
    margin-inline: clamp(18px, 4vw, 44px) auto;
    border-radius: 4px 18px 18px 4px;
  }
}

.hero-slide[data-overlay="panel-navy"] .hero-content {
  background: var(--brand-deeper);
  border-left: 4px solid var(--gold);
}
.hero-slide[data-overlay="panel-navy"][data-pos$="-right"] .hero-content {
  border-left: 0;
  border-right: 4px solid var(--gold);
}
@media (max-width: 860px) {
  .hero-slide[data-overlay="panel-navy"][data-pos$="-right"] .hero-content {
    border-left: 4px solid var(--gold);
    border-right: 0;
  }
}
/* Text stays the default light theme on panel-navy (it's still a dark background) -- nothing
   further to override here beyond the card itself. */

/* panel-white: NAVY text, derived purely from the overlay value -- see the theme block below.
   "Real edge", per the brief: a defined 1px border plus a lift shadow, not just a soft glow that
   would blend into a bright photo the way the other overlays' washes do on purpose. */
.hero-slide[data-overlay="panel-white"] .hero-content {
  background: #fff;
  border: 1px solid var(--line);
}

/* ---- Text theme, derived from overlay, never a separate class ----
   panel-white implies navy text; every other overlay (including panel-navy) implies light text.
   Doing this as a `:not()` on the overlay value -- rather than a light/dark class toggled
   alongside data-overlay -- is what makes "dark text on a dark veil" structurally impossible:
   there is no third state to get out of sync with the actual background. */
.hero-slide[data-overlay="panel-white"] .hero-h,
.hero-slide[data-overlay="panel-white"] .hero-h-ar { color: var(--brand); text-shadow: none; }
.hero-slide[data-overlay="panel-white"] .hero-proof { color: var(--ink-soft); }
/* Gold reads as a dark-background accent everywhere else on the site; on white it's marginal,
   so panel-white's eyebrow switches to the same green used for on-white accents elsewhere
   (.prod-cat, .team-role) instead of inventing a new tint. */
/* The rule before the eyebrow is the only part that takes a fill; the
   text takes the colour. Setting both on both made it green on green. */
.hero-slide[data-overlay="panel-white"] .hero-eyebrow { color: var(--green); }
.hero-slide[data-overlay="panel-white"] .hero-eyebrow::before { background: var(--green); }
.hero-slide[data-overlay="panel-white"] .btn-ghost {
  color: var(--brand);
  border-color: color-mix(in oklch, var(--brand) 45%, transparent);
}
.hero-slide[data-overlay="panel-white"] .btn-ghost:hover {
  background: color-mix(in oklch, var(--brand) 8%, transparent);
  border-color: var(--brand);
}
/* Global :focus-visible is a gold ring (site.css, :root) -- gold-on-white is marginal contrast.
   Scoped to the panel's own buttons only; the arrows/dots/play-pause in .hero-ui always sit over
   the photo, never over the panel, so they keep the gold ring everywhere. */
.hero-slide[data-overlay="panel-white"] .hero-actions a:focus-visible {
  outline-color: var(--brand-deep);
}

/* Light-text survival shadow: every overlay except the two panels sits directly over a photo, so
   the headline/eyebrow/proof need a shadow that still reads if the scrim under them happens to
   land on a bright patch. Both panels are excluded -- panel-navy already guarantees contrast via
   a solid background (a shadow there is just noise) and panel-white uses navy text instead. */
.hero-slide:not([data-overlay^="panel-"]) .hero-h,
.hero-slide:not([data-overlay^="panel-"]) .hero-h-ar,
.hero-slide:not([data-overlay^="panel-"]) .hero-eyebrow,
.hero-slide:not([data-overlay^="panel-"]) .hero-proof {
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.55);
}

/* ---------------------------------------------------------------------------------------------
   MOTION -- data-motion="kenburns" is site.css's unqualified default (the existing heroKB
   animation already runs on every active slide's image); "still" is the one new case, and it
   resets back to a true 1:1 scale rather than leaving the idle 1.02 that only exists to give
   Ken Burns' zoom-out room to run without exposing an edge. prefers-reduced-motion already turns
   heroKB off globally further down site.css (outside this file's scope) -- that rule already
   covers both values here, kenburns by force-disabling the animation and still by already having
   none, so nothing further is needed in this file for reduced motion. */
.hero-slide.is-active[data-motion="still"] .hero-media img {
  animation: none;
  transform: none;
}

/* ---------------------------------------------------------------------------------------------
   CONTROLS
   --------------------------------------------------------------------------------------------- */

/* Play/pause is new -- there's no prior art for it in site.css. Sized to match .hero-arrow's
   circle so the three buttons read as one family. margin-inline-end:auto is the grouping trick:
   it pins play/pause to .hero-ui's own left edge and pushes everything after it (prev, next,
   dots) into one tight cluster at the right edge, using .hero-ui's own `gap` for the spacing
   within that cluster -- without a wrapper div around the arrows, which the DOM contract doesn't
   provide. (The old space-between rule this replaces would have spread prev/next/dots apart
   from EACH OTHER by the same amount as from play/pause, instead of pairing the arrows.) */
/* Was tuned for "floats over the photo" (white-on-transparent, needs the photo/scrim behind it
   for contrast). The whole control bar now sits below the picture on its own white surface
   (site.css's .hero .hero-ui) instead of overlaid on top of it, so this needs the light-surface
   treatment site.css's .hero-arrow already uses -- navy icon on a brand-tint circle -- not a
   white-on-white ghost. */
.hero-playpause {
  width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center;
  cursor: pointer; color: var(--brand); background: var(--brand-tint);
  border: 1.4px solid var(--line);
  transition: transform 200ms var(--ease), background 200ms var(--ease), border-color 200ms var(--ease), color 200ms var(--ease);
  margin-inline-end: auto;
}
.hero-playpause:hover { background: var(--brand); color: #fff; }
.hero-playpause:active { transform: scale(0.95); }
.hero-playpause svg { width: 17px; height: 17px; }
/* Cosmetic only, and reversible: assumes aria-pressed="true" means "currently paused" (the
   common toggle-button reading). If the unit wiring up the click handler defines the opposite,
   swap which state gets the tint -- nothing else here depends on the assumption. */
.hero-playpause[aria-pressed="true"] {
  background: color-mix(in oklch, var(--gold) 20%, white);
  border-color: color-mix(in oklch, var(--gold) 55%, transparent);
  color: color-mix(in oklch, var(--gold) 70%, var(--brand));
}

/* Progress bar: the primary driver is site.css's existing data-playing/data-paused convention on
   .hero (kept as-is, see the rule there). This is a fallback for the same state expressed the
   other way round -- directly off the play/pause button's own aria-pressed, in case whichever
   unit wires up the interactivity only ever touches the button and never .hero's dataset. Either
   convention (or both) correctly pauses the bar; neither is assumed to be the only one wired up. */
.hero:has(.hero-playpause[aria-pressed="true"]) .hero-progress span {
  animation-play-state: paused;
}


/* ---------------------------------------------------------------------------------------------
   PANEL SIZING -- a panel is a card behind the words, not a column. It
   inherits .hero-content's min-height from site.css otherwise, which
   made both panel treatments render as a full-height slab down the side
   of the band.
--------------------------------------------------------------------------------------------- */
.hero-slide[data-overlay^="panel-"] .hero-content {
  min-height: 0;
  align-self: center;
  padding: clamp(1.5rem, 3vw, 2.75rem);
  border-radius: 4px;
}

.hero-slide[data-overlay^="panel-"][data-pos^="low-"] .hero-content {
  align-self: end;
  margin-bottom: clamp(3.5rem, 8vh, 6rem);
}

/* ---------------------------------------------------------------------------------------------
   REDUCED MOTION -- hero.js also stamps .is-reduced-motion on the
   section, so this holds even where the media query is unavailable.
   The comment in the motion block claiming site.css covered this was
   wrong: nothing there names these three animations.
--------------------------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .hero-slide .hero-media img,
  .hero-slide .hero-content > *,
  .hero-progress span {
    animation: none !important;
    transition: none !important;
  }
}

.hero.is-reduced-motion .hero-media img,
.hero.is-reduced-motion .hero-content > *,
.hero.is-reduced-motion .hero-progress span {
  animation: none !important;
  transition: none !important;
}

/* ---------------------------------------------------------------------------------------------
   CONTROL ICONS -- the play triangle and the pause bars share one <svg>;
   which is showing is driven by the button's pressed state, so the
   markup does not have to be swapped at runtime.
--------------------------------------------------------------------------------------------- */
.hero-playpause svg,
.hero-arrow svg { display: block; }

.hero-playpause .hero-icon-pause,
.hero-playpause .hero-icon-play { fill: currentColor; }

.hero-playpause .hero-icon-play { display: none; }
.hero-playpause[aria-pressed="true"] .hero-icon-pause { display: none; }
.hero-playpause[aria-pressed="true"] .hero-icon-play { display: inline; }
