/* about.css — About page: hero + intro (Task 7); #process/#twistors/#homebase later */

/* === Hero — SPEC §5.1 ===================================================
   ref/About1.png's hero photo is an explicitly-flagged stock placeholder
   ("asset thật chờ anh Trí" — SPEC §5.1), since replaced by the real
   assets/img/about-hero.png (1281×530, same crop). Geometry pixel-scanned
   from that ref frame regardless, since the placeholder shares the final
   layout's structural numbers (top offset, caption corner padding):
   image top measured at exactly y109 (hard edge, matches the ~110 plan);
   caption padding measured ~39-40px independently from all 4 corners
   (TL-top, TL-left, BR-bottom, BR-right all converged there), not the
   SPEC/plan's rough "~48" — same pattern as home.css's hero-play override.
   Image itself sized to the standard 60rem content margin (1320 wide)
   per SPEC's explicit "full-width trong margin 60", not the ref frame's
   incidental native-resolution placeholder inset (that placeholder sat
   ~80px from the viewport edge, i.e. centered native-size within the
   1320 box — a placeholder-only quirk, not a spec'd margin). */
#hero {
  padding: 110rem var(--mx) 96rem;
}

.hero-banner {
  position: relative;
  width: 100%;
  height: 515rem;
  border-radius: 4rem; /* ref corner crop shows a hard square edge at pixel level; kept a slight radius per plan since 4rem is sub-pixel-invisible at this scale anyway */
  overflow: hidden;
}

.hero-banner img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero-caption {
  position: absolute;
  color: var(--white);
  font-weight: 700;
  font-size: 40rem;
  line-height: 1.15; /* matches .footer-cta's 40px/1.15 pairing elsewhere in the site */
}

.hero-caption--tl {
  top: 40rem;
  left: 40rem;
}

.hero-caption--br {
  right: 40rem;
  bottom: 24rem; /* not 40 — single line with no descenders leaves ~16rem of unused line-box
    space below the baseline; 24 nets out to the same ~40rem visual ink-to-corner gap the
    top-left caption gets from a literal top/left:40rem (verified via rendered screenshot,
    pixel-scanned the same way as the ref). */
  text-align: right;
}

.hero-intro {
  margin-top: 20rem; /* ref: image-bottom → intro ascender-top ≈ 23px visual ink gap;
    verified via rendered-screenshot pixel scan (same method as the caption paddings above). */
  font-size: 17rem;
  line-height: 1.35;
  color: var(--black);
}

/* === How The Twists Work — SPEC §5.2 (About G1 + G3) ====================
   #process reuses the shared .stmt pin (Phase A: title shrink + intro fade)
   then, via initStatement's extra() hook (js/about.js), runs Phase B: a
   horizontal track translates left (scrubbed) while a hand-drawn twisting
   line reveals left→right and each step fades in as the line reaches it. */

/* Phase A title is 56rem here (Home's statement is 60) — SPEC §5.2. Kept
   above the track in the stacking order so the shrunk title (pinned near
   the top) is never occluded by a step scrolling under it. */
#process .stmt-title { font-size: 56rem; position: relative; z-index: 3; }
#process .stmt-intro { z-index: 2; }

/* Phase B track — lives inside the pinned .stmt section; its x is animated.
   Width = line right-edge (full-arrow.svg ends at track-x ~2287) + a
   trailing black margin (~178rem ≈ 1/8 viewport: after the arrowhead
   finishes drawing there's a short beat of empty black before the pin
   releases → the arrow reads as "landed" with a little breathing room,
   not cut off at the edge, and not a long empty scroll).
   dist = scrollWidth − innerWidth and the single-clip line reveal in
   js/about.js is derived from scrollWidth, so the draw auto-finishes at
   lineW/scrollWidth of the scrub and the remaining scroll shows blank track.
   Tuned against ref/About1_Guide3.png. */
.proc-track {
  position: absolute;
  top: 0;
  left: 0;
  width: 2465rem;
  height: 100%;
  z-index: 1;
  will-change: transform;
}

/* A process step: number circle + name + sub-item list. Positioned in the
   track via inline left/top (set from STEP_POS in js/about.js). Faded in by
   the timeline as the line reaches it. */
.proc-step {
  position: absolute;
  color: #fff;
  opacity: 0;
  will-change: opacity;
  z-index: 2;               /* number circles/text stack over the line ink */
  text-align: left;         /* .stmt is centered; guide stacks each block as a
                               left-aligned column (circle above title above items) */
}

/* BREAK (index 1) is the odd one out: its number circle sits INLINE with the
   title ("02  BREAK") on one row, above the items — the other three stack
   number → title → items (guide_left/right.jpg). */
.proc-step--inline .proc-head {
  display: flex;
  align-items: center;
  gap: 12rem;
}
.proc-step--inline .proc-num { margin-bottom: 0; }

/* TWIST (index 2, --clear) sits just left of the line's loop; a descending
   stroke off the loop passes close above its title — QA pixel-scan measured
   ~40rem clearance there (title-corner to nearest opaque ink px), the
   tightest of the four clusters (the others measure 50-145rem). The ink is
   ABOVE the title, so the clearing direction is DOWN: extra circle→title
   gap pushes title+items away from it as a unit, without moving the circle
   (STEP_POS/FEAT in about.js are untouched — this only affects .proc-num's
   own margin, i.e. the space *after* it, not its position). +20rem lands the
   title's nearest-ink gap at ~53rem, in line with the other clusters. */
.proc-step--clear .proc-num { margin-bottom: 34rem; }

.proc-num {
  width: 44rem;
  height: 44rem;
  border: 1px solid #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20rem;
  font-weight: 400;
  /* sits just above-left of the name (SPEC §5.2 "vòng tròn just above-left") */
  margin-left: -6rem;
  margin-bottom: 14rem;
}

.proc-name {
  font-size: 30rem;
  font-weight: 700;
  text-transform: uppercase;
  line-height: 1;
}

.proc-items {
  list-style: none;
  margin-top: 26rem;
  width: 250rem;
}
.proc-items li {
  border-top: 1px solid #fff;
  padding-top: 12rem;
  padding-bottom: 18rem;
  font-size: 16rem;
  font-weight: 400;
  letter-spacing: 0.5rem;
  text-transform: uppercase;
  line-height: 1;
}

/* The hand-drawn line — ONE exported asset (assets/img/process/full-arrow.svg:
   the whole twisting line + detached arrowhead as a single filled path). It's a
   fixed-size <img> (LINE_W×LINE_H rem, set inline from js/about.js) inside this
   overflow:hidden wrapper; animating the wrapper width 0→LINE_W draws the line
   left→right (the arrowhead, at the right end, is revealed last). left/top/
   height are set inline from js/about.js so LINE_X/LINE_Y are single-sourced
   there. max-width:none defeats base.css's img{max-width:100%}. */
.proc-line {
  position: absolute;
  overflow: hidden;
  width: 0;
  will-change: width;
}
.proc-line img { max-width: none; display: block; }

/* Reduced-motion (js/about.js builds this branch): whole track shown
   statically, all segments full width + steps visible, section is tall and
   horizontally scrollable so everything is reachable without scroll-scrub.
   Title + intro flow normally above the track band (no pin transform, no
   centered-absolute overlap) so nothing sits on top of the line. */
#process.proc-static {
  height: auto;
  min-height: 100vh;
  display: block;
  overflow-x: auto;
  overflow-y: hidden;
  padding-top: 140rem;
}
#process.proc-static .stmt-title {
  position: relative;
  transform: none !important;
  margin: 0 auto 32rem;
}
#process.proc-static .stmt-intro {
  position: relative;
  top: auto;
  left: auto;
  transform: none;
  margin: 0 auto 48rem;
  opacity: 1;
}
#process.proc-static .proc-track { position: relative; height: 700rem; }
#process.proc-static .proc-step { opacity: 1; }
#process.proc-static .proc-line { width: auto !important; } /* shrink-fit to the full 2163rem img → whole line shown */

/* === Meet The Twistors — SPEC §5.3 (About G4/G5/G6) ====================
   White section: header + paragraph (x60), then a full-bleed strip of 10
   cutout "people" (JS-built into .tw-strip) with one reusable info .tw-card
   that repositions/repopulates per the active member. State machine +
   card population live in js/about.js (initTwistors).

   Vertical anchoring (all rem = px @1440, from ref pixel-scan of the two
   About crops): heads land ~y367, feet on a floor ~y685, the card spans
   ~y577→817 (overlapping the lower half of the strip). Those map inside
   .tw-stage to: floor = stage-bottom − 140; card-top = 247. */
#twistors {
  position: relative;
  background: var(--white);
  padding-top: 141rem;   /* lands the header cap ~y149 below the section top */
  padding-bottom: 84rem; /* ~y817 card bottom → homebase header */
}

.tw-head {
  margin: 0 var(--mx);
  font-size: 44rem;
  font-weight: 700;
  line-height: 1;
  text-transform: uppercase;   /* "Twistors" gw inherits it → renders TWISTORS */
}

.tw-copy {
  margin: 24rem var(--mx) 0;
  max-width: 790rem;   /* ref wraps block 1 into 3 lines (…love culture, enjoy) */
  font-size: 20rem;
  line-height: 1.05;   /* ref line boxes are tight (~20rem baseline-to-baseline) */
  color: var(--black);
}
.tw-copy p + p { margin-top: 20rem; } /* the blank-line gap between the two blocks */

/* Full-bleed stage that holds the strip + the floating card. Tall enough to
   contain the card, which hangs ~132rem below the floor line. margin-top is
   tuned so the feet-floor lands ~section-y 685 (ref). */
.tw-stage {
  position: relative;
  width: 100%;
  height: 495rem;
  margin-top: 11rem; /* lands the feet-floor at ~section-y 685 (ref) */
}

/* --- A person: a focusable button, absolutely placed (left/width = inline
   x%/w% from MEMBERS), bottom-aligned so every cutout's feet sit on the
   floor. Two stacked images (dimmed + clear) crossfade for the reveal. --- */
.tw-person {
  position: absolute;
  bottom: 140rem;           /* floor = stage-bottom − 140 → section-y ~685 */
  padding: 0;
  border: 0;
  background: none;
  line-height: 0;
  cursor: pointer;
  z-index: 1;               /* dim people keep DOM (left→right) overlap order */
}
/* the revealed person pops above dim neighbours so an overlapping faded arm
   never covers the clear cutout (still below the card at z-index 5) */
.tw-person.is-active { z-index: 3; }
.tw-person .dim { display: block; width: 100%; height: auto; }
.tw-person .clear {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;               /* clear hidden by default; shown when active */
}
/* No will-change here: with 10 people × 2 images each, a blanket will-change:opacity
   would force 20 permanent compositor layers for elements that are static almost all
   the time (only the currently-hovered pair actually transitions) — the "stray/global
   will-change" pattern flagged in the QA pass-2 audit. Modern browsers promote a
   layer on their own once a transition actually starts, which is plenty for a single
   pair crossfading at a time. */
.tw-person .dim, .tw-person .clear { transition: opacity .25s ease; }
.tw-person.is-active .clear { opacity: 1; }
.tw-person.is-active .dim { opacity: 0; }
/* keyboard focus ring sits on the (invisible) button box around the cutout */
.tw-person:focus-visible { outline: 2px solid #1888c0; outline-offset: 2px; }

/* --- The single reusable info card (SPEC §5.3). One element, JS-populated;
   background = member card colour, text = member ink colour. Measured from
   the ref at ~410×240 (the plan's "535×315" over-stated it; the header
   cap-height confirms the crops are 1:1 with the 1440 frame). --- */
@keyframes tw-card-wipe {
  from { clip-path: inset(0 100% 0 0 round 24rem); }
  to   { clip-path: inset(0 0 0 0 round 24rem); }
}
.tw-card {
  position: absolute;
  top: 247rem;              /* card-top ~section-y 577 */
  left: 0;                  /* JS sets the anchored left per active member */
  width: 410rem;
  height: 240rem;
  border-radius: 24rem;
  padding: 20rem;
  display: flex;
  gap: 20rem;
  color: var(--white);      /* overridden inline by member ink */
  z-index: 5;
  pointer-events: none;     /* card never eats hover from the people behind */
  /* Reveal = a colour wipe: the card rests fully clipped from the right; the
     brand-colour panel sweeps in left→right via the tw-card-wipe keyframes each
     time .is-in is applied. JS (initTwistors show()) removes → reflows → re-adds
     .is-in on every member switch, which restarts the animation. A keyframe (not
     a transition) is used on purpose: the synchronous remove/reflow/add restart
     reliably re-fires an animation, whereas a clip-path transition out of a
     %-inset does not re-trigger. The round radius holds the 24rem corners the
     whole way, so the sweep reads as one solid card, never a hard rectangle. */
  clip-path: inset(0 100% 0 0 round 24rem);
  will-change: clip-path;
}
.tw-card.is-in {
  clip-path: inset(0 0 0 0 round 24rem);
  animation: tw-card-wipe .52s cubic-bezier(.76, 0, .24, 1);
}

/* left tile: the composited main+secondary pose PNG on a cream ground.
   The PNG carries its own cream ground + rounded corners at a 248:323 ratio.
   The tile used to be 160x200 (ratio .8) — wider than the PNG — so `contain`
   letterboxed it: a cream sliver each side + the PNG's own rounded box inset
   inside the tile's (the "viền trắng" in review). Matching the tile ratio to
   the PNG lets `cover` fill it edge-to-edge, no crop and no sliver, so the full
   pose still reads. Height stays locked to the card; width follows the ratio. */
.tw-tile {
  flex: 0 0 auto;
  width: auto;
  aspect-ratio: 248 / 323;
  height: 100%;
  border-radius: 16rem;
  background: #f0ede6;
  overflow: hidden;
}
.tw-tile img { width: 100%; height: 100%; object-fit: cover; object-position: center bottom; display: block; }

/* right side: bold label column + right-aligned handwriting value column.
   Ref renders these ~14rem (cap-height 10rem measured — the plan's "20rem"
   over-stated it, same as the card box). */
.tw-info {
  flex: 1 1 auto;
  position: relative;
  display: flex;
  justify-content: space-between;
  padding: 10rem 0 0;  /* labels/values nudged 10rem below the tile top (ref) */
}
.tw-labels { font-weight: 700; }
.tw-labels, .tw-values { font-size: 14rem; line-height: 17rem; white-space: nowrap; }
.tw-labels span, .tw-values span { display: block; }
.tw-values { font-family: var(--font-hand); text-align: right; }

/* bottom-right monogram: white disc holding the member's scribble SVG.
   Inset by the card padding so it sits inside the corner (bottom edge level
   with the tile) instead of flush to the card's rounded border. */
.tw-disc {
  position: absolute;
  right: 20rem;
  bottom: 20rem;
  width: 72rem;
  height: 72rem;
  border-radius: 50%;
  background: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.tw-disc img { width: 72rem; height: 72rem; display: block; }

@media (prefers-reduced-motion: reduce) {
  .tw-person .dim, .tw-person .clear { transition: none; }
  /* Skip the wipe: .is-in still sets the fully-open clip, so the card just
     appears instantly instead of sweeping in. */
  .tw-card.is-in { animation: none; }
}

/* === Home Base — SPEC §5.4 ===============================================
   White section: 2-line header (x60) + a 5-slide carousel (center slide in
   colour, sides grayscale + peeking both viewport edges) + 5 dots + a
   centered CTA. Header/CTA markup is static in about.html; the track +
   dots are JS-built (js/about.js initHomebase) — same split as #twistors.

   SPEC §5.4 gives the center slide as "1105×470, peek 120, gap 28" —
   pixel-scanning the two ref crops (ref_a1_homebase.png / ref_a2_homebase.png,
   both 1440×950, the About1/About2 states) shows those are pre-asset
   estimates that don't match. Column-scanning the photo band (y≈105–580,
   staying clear of the border-radius corners) gives three runs per crop:
     a1: [0–306] [328–1096] [1117–1439]   a2: [0–314] [335–1104] [1125–1439]
   i.e. center width ≈768–769rem, gap ≈21–22rem, and a visible side-peek
   that looks asymmetric per-crop (306 vs 322 in a1) but averages to an
   identical 314/314 across the two — that's just per-photo edge-brightness
   noise around a true ~314, not a real asymmetry (confirmed: a2's own two
   peeks already match exactly at 314/314). The three numbers self-check via
   the peeking-carousel identity peek = 720 − slideW/2 − gap:
   720 − 769/2 − 22 ≈ 314 ✓. Height follows the 1153×732 asset's native
   aspect ratio at that width (769 × 732/1153 ≈ 488), which also matches the
   measured photo-band height (584−96=488) exactly — slides render at their
   native aspect; object-fit:cover is a safety net, not an active crop.
   Used: 769×488 slide, 22 gap (not SPEC's 1105/470/28 or the initial
   765/300/28 plan estimate — both close, but measured wins per project
   convention). Dots measured at 12rem diameter / 26rem centre-to-centre
   (→14rem flex gap) — matches SPEC's dot size; SPEC/plan gave no dot gap. */
#homebase {
  position: relative;
  background: var(--white);
  padding: 56rem 0 64rem;
  overflow: hidden; /* clips the track's off-screen slide edges */
}

.hb-head {
  margin: 0 var(--mx) 40rem;
  font-size: 44rem;
  font-weight: 700;
  line-height: 1;
  text-transform: uppercase;
}

.hb-carousel {
  position: relative;
  width: 100%;
  overflow: hidden;
}

.hb-track {
  display: flex;
  gap: 22rem;
  cursor: grab;
  touch-action: pan-y;      /* vertical page-scroll still passes through; we own horizontal drag */
  user-select: none;
  will-change: transform;
  transition: transform .5s ease;
}
.hb-track.is-dragging { cursor: grabbing; transition: none; }

.hb-slide {
  flex: 0 0 769rem;
  width: 769rem;
  height: 488rem;
  border-radius: 12rem;
  overflow: hidden;
  cursor: pointer;        /* click a side slide to bring it to center */
}
.hb-slide.is-active { cursor: default; } /* centered one: nothing to do on click */
.hb-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: grayscale(1);
  transition: filter .4s ease;
  -webkit-user-drag: none;
  user-select: none;
}
/* the centered slide transitions to full colour — SPEC §5.4 */
.hb-slide.is-active img { filter: grayscale(0); }

.hb-dots {
  margin: 16rem auto 0;
  width: fit-content;
  display: flex;
  align-items: center;
  gap: 14rem; /* dots shrunk 50% (12→6rem); gap kept at 14 for the airy ref spacing (~2× dot) */
}
.hb-dot {
  width: 12rem;
  height: 12rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  /* paging dot art — inactive = Ellipse 92 (grey), active = Ellipse 94 (black) */
  background: url("../assets/img/Ellipse 92.png") center / contain no-repeat;
}
.hb-dot.is-active { background-image: url("../assets/img/Ellipse 94.png"); }
.hb-dot:focus-visible { outline: 2px solid #1888c0; outline-offset: 2px; }

/* .btn-pill is inline-flex by default (content-sized inline element); block
   flex + margin:auto centers it in the full-width section — SPEC §5.4 note
   "khác Home: căn giữa" (Home's equivalent CTA is left-aligned in a column). */
.hb-cta {
  display: flex;
  width: fit-content;
  margin: 28rem auto 0;
  font-size: 16rem; /* feedback: "Start the twist" → size 16 (base .btn-pill is 17) */
}

@media (prefers-reduced-motion: reduce) {
  .hb-track { transition: none; }
  .hb-slide img { transition: none; }
}

/* ======================================================================
   MOBILE (≤768px) — About: hero / process (stacked, pin off) / twistors
   (reflowed strip + tap card) / homebase (full-width swipe carousel).
   Phase-2 first-pass responsive. Desktop (>768px) unaffected.
   ====================================================================== */
@media (max-width: 768px) {
  /* --- Hero: banner + captions stacked, intro readable. Shorter banner so
     it isn't a tall block on a phone; captions shrink to fit corners. --- */
  #hero { padding: 92rem var(--mx) 56rem; }
  .hero-banner { height: 300rem; }
  .hero-caption { font-size: 26rem; }
  .hero-caption--tl { top: 22rem; left: 22rem; }
  .hero-caption--br { right: 22rem; bottom: 16rem; }
  .hero-intro { margin-top: 18rem; font-size: 16rem; line-height: 1.4; }

  /* --- Process "How The Twists Work": disable the pinned horizontal track
     (about.js takes the proc-static branch at ≤768), then re-flow the static
     track into a simple vertical stack of the 4 steps. The hand-drawn line is
     decorative + absolutely placed for the desktop track, so hide it here.
     Title/intro wrap readably (override #process-specific sizes). --- */
  #process.proc-static {
    min-height: auto;
    overflow-x: hidden;            /* stacked → no horizontal scroll needed */
    padding: 72rem var(--mx) 56rem;
  }
  #process .stmt-title { font-size: 32rem; white-space: normal; }
  #process.proc-static .stmt-title { margin: 0 0 20rem; }
  #process .stmt-intro { font-size: 16rem; line-height: 1.45; }
  #process.proc-static .stmt-intro { margin: 0 0 40rem; max-width: 100%; }
  #process.proc-static .proc-track {
    position: static;
    width: 100%;
    height: auto;
  }
  #process.proc-static .proc-step {
    position: static !important;   /* neutralises the inline left/top coords */
    opacity: 1;
    margin: 0 0 40rem;
    text-align: left;              /* .stmt is text-align:center; stacked list reads better left */
  }
  #process.proc-static .proc-line { display: none; } /* decorative line, hidden when stacked */
  .proc-num { margin-left: 0; }
  /* the desktop-only line-clearance drop (.proc-step--clear, see above) has
     nothing to clear once the line is hidden here — reset TWIST back to the
     same circle→title gap as every other stacked card. */
  .proc-step--clear .proc-num { margin-bottom: 14rem; }
  .proc-step--inline .proc-head { gap: 10rem; } /* keep "02 BREAK" inline in the stack too */
  .proc-items { width: auto; max-width: 300rem; margin-top: 20rem; }

  /* --- Meet The Twistors: the absolute %-positioned 10-person strip breaks
     at phone width, so reflow it into a horizontal-scroll row of fixed-height
     cutouts. Tapping a person (focus fires on tap → existing JS activates it)
     reveals the clear cutout + repopulates the card, now shown full-width in
     normal flow below the strip instead of absolutely anchored. --- */
  #twistors { padding-top: 80rem; padding-bottom: 56rem; }
  .tw-head { font-size: 30rem; }
  .tw-copy { max-width: none; font-size: 17rem; line-height: 1.4; }
  .tw-copy p + p { margin-top: 16rem; }

  .tw-stage { height: auto; margin-top: 24rem; }
  .tw-strip {
    display: flex;
    flex-wrap: nowrap;
    gap: 12rem;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    padding: 0 var(--mx) 10rem;
    scroll-snap-type: x proximity;
  }
  .tw-person {
    position: static !important;   /* neutralises inline left/bottom */
    width: auto !important;        /* neutralises inline width:% */
    bottom: auto !important;
    flex: 0 0 auto;
    height: 210rem;                /* fixed-height cutouts, natural width */
    scroll-snap-align: center;
  }
  .tw-person .dim { height: 100%; width: auto; }
  .tw-person .clear { width: 100%; height: 100%; } /* fills the dim-sized box */

  .tw-card {
    position: static !important;   /* was absolute + JS-anchored left */
    left: auto !important;
    top: auto !important;
    width: auto;                   /* was 410rem → overflowed; full width now */
    height: auto;                  /* was 240rem fixed; grow to fit wrapped text */
    min-height: 190rem;
    margin: 24rem var(--mx) 0;
    overflow: hidden;              /* safety net: keep content within the card box */
  }
  .tw-tile { flex: 0 0 120rem; width: 120rem; aspect-ratio: auto; } /* fixed 120 wide, height follows the card (no desktop ratio lock) */
  /* the label/value columns are nowrap on desktop; let them wrap on a narrow
     phone card so long values ("Operation Director") don't push past the box */
  .tw-labels, .tw-values { white-space: normal; }

  /* --- Home Base: peeking 769rem carousel → one full-bleed slide at a time
     with native swipe (about.js switches to px/vw centering at ≤768). Dots
     below, CTA centered (already), grayscale side-peek removed. --- */
  #homebase { padding: 48rem 0 56rem; }
  .hb-head { margin: 0 var(--mx) 28rem; font-size: 30rem; }
  .hb-track { gap: 0; }
  .hb-slide {
    flex: 0 0 100%;               /* one carousel-width slide at a time */
    width: 100%;
    height: auto;
    aspect-ratio: 1153 / 732;
    border-radius: 0;              /* full-bleed edge-to-edge */
  }
  .hb-slide img { filter: none !important; } /* no grayscale on mobile */
  .hb-dots { margin-top: 20rem; }
  .hb-cta { margin-top: 28rem; }
}
