/** Shopify CDN: Minification failed

Line 184:21 Unexpected "*"

**/
/* ============================================================
   tc60-v7 · Figma export transcript pass (2026-08-05)
   Loaded last, after v6. Inherits every token from tc60.css/tc60-v3.css
   (--orange-*, --grey-*, --ink*, --radius, --ease, --film, --grain).

   One file for the whole punch list rather than a v7/v8/v9 split, because
   every change here traces back to the same source (Bryan's Figma export
   transcript, 2026-08-05) and reverting the pass means deleting one line
   in hub-v3.html plus this file — same shape as tc60-v6's "layered last"
   convention.

   Contents:
     §1  topbar hidden
     §2  hero logo slot
     §3  pathchooser hidden / stats moved into #choose
     §4  read-more clamp (Lineup reviews)
     §5  timeline — draggable horizontal filmstrip (tc60-v7.js §1)
     §6  awards — four claims as four plaques + CTA
     §6b offers header centred
     §6c brand filter
     §7  product slider (replaces bundle calculator; brand-filtered grid)
     §8  sign-up capture, moved up under the products
     §9  rsum — bigger 5.0 / 9,000+, Google link removed (now dead —
         the whole .rsum card was later deleted from hub-v3.html)
     §10 header line-height (People / History / Awards / Offers)
     §11 capture — header/body copy spacing
     §12 then & now — before/after drag slider (tc60-v7.js §14)
     §13 product slider — placeholder lifestyle photos
     §15 mobile CTAs — equal width, one line (hero + brand filter)
     §16 legacy year-by-year timeline, hidden (revert: one class/rule)
   ============================================================ */

/* ---- §1 · topbar hidden --------------------------------------------
   "hide the entire top bar nav for now, keep it simple" — kept as a CSS
   toggle rather than deleting the markup, so it's a one-line revert. */
.topbar-v3 { display: none !important; }
/* the hero had negative top margin to sit under a transparent bar
   (tc60-v3.css `.hero-v3 { margin-top: -68px }`) — with no bar to sit
   under, that pulls the tunnel up under nothing and clips its own top. */
.hero-v3 { margin-top: 0 !important; }

/* ---- §2 · hero logo -------------------------------------------------
   Real lockup landed 2026-08-05 (TC_60_logo.png), replacing the dashed
   placeholder frame this slot used to render. Sized by height with `width:
   auto` rather than a fixed box, since the real file's aspect ratio isn't
   a plain 3:1 like the placeholder assumed — `object-fit: contain` inside
   a fixed box would either add letterboxing or force a guessed crop.
   Bumped twice more same day ("the logo needs to be much bigger", then
   "even bigger"), then eased back down slightly ("make the logo slightly
   smaller") — was clamp(40px, 4.6vw, 58px), sized for the placeholder's
   small wordmark box; up through clamp(90px, 11vw, 150px) and
   clamp(160px, 20vw, 280px) to this, then eased down again 2026-08-13
   ("make the logo a little smaller") after the new Aug-13 lockup landed,
   then to 3/4 of that same day ("even smaller, maybe 3/4 the size"), then
   smaller again same day once the headline (below) went bigger alongside
   it — the two were asked for together ("logo smaller and the header
   bigger"), so the logo gives up more of the hero's visual weight to the
   headline rather than the pair just both changing in isolation. */
.hero-logo-slot {
  display: flex; align-items: center; justify-content: center;
  height: clamp(72px, 9vw, 128px);
  /* was 4px, then tightened again ("close the gap even more") — 0 rather
     than negative, since the PNG file may carry its own baked-in
     transparent padding underneath the mark that a negative margin can't
     see or account for. */
  margin: 0 auto 0;
}
.hero-logo-img { height: 100%; width: auto; display: block; }

/* The real site header (#stickyHeader) is `position: sticky`/`fixed` with
   a higher z-index than the hero. `.hero-stage` (tc60-v3.css) is itself
   `position: sticky; top: 0`, so once the hero-runway scrolls, it pins
   flush to the literal top of the viewport — underneath the real header,
   not below it — clipping the top of the logo. Turned out not to be a
   mobile-only problem ("cut off is happening on smaller desktop sizes as
   well") — the header's own rendered height changes at every one of the
   theme's own breakpoints, not just under 1023px, so a single mobile
   override still left 1024-1199px (laptop-width) screens at top:0.
   Mirroring all four of theme.liquid's `.global-content-top-margin`
   breakpoints here (same reserved-header-height values, just applied to
   the sticky offset instead of a top margin) covers every width instead
   of guessing which ones count as "smaller". A flat +28px on top of each
   is breathing room ("increase the spacing between the logo and the
   header") — the sticky pin sits below the header either way, this just
   widens the gap rather than sitting flush against it. Since the hero's
   content is vertically centred inside `.hero-stage` (place-items:
   center), pushing the sticky top down shifts the whole centred block
   (and the logo inside it) down by the same amount.

   That's also why it stopped reading as centred on desktop: `.hero-stage`
   kept tc60-v3.css's `height: 100vh` while its `top` moved off 0, so the
   box now runs from `top` to `top + 100vh` — past the bottom of the
   viewport by `top` px. `place-items: center` centres inside that full,
   partly-offscreen box, not inside the visible slice, so the content
   itself sits `top/2` px below the true centre of the screen. Setting
   `height: calc(100vh - <top>)` on each breakpoint makes the box exactly
   fill the space below the header again, so centring lands where it
   visually should.

   Mobile's gap (the base rule, <768px) got another +30px on top of that
   ("on mobile, the spacing between logo and the header needs to be
   more") — desktop/tablet were left as-is since only mobile was called
   out that round. Desktop's turn came next ("on desktop, give some space
   between the logo and header as well") — same +30px, applied to the two
   desktop breakpoints only (1024px/1200px), tablet (768px) still untouched
   since it's never been called out either time. */
.hero-stage { top: 168px; height: calc(100vh - 168px); }
@media (min-width: 768px) {
  .hero-stage { top: 145px; height: calc(100vh - 145px); }
}
@media (min-width: 1024px) {
  .hero-stage { top: 159px; height: calc(100vh - 159px); }
}
@media (min-width: 1200px) {
  .hero-stage { top: 198px; height: calc(100vh - 198px); }
}

/* ---- §3 · pathchooser hidden / stats relocated ----------------------
   The three-door grid is hidden outright; the lifetime stats (moved here
   from #people in hub-v3.html) take over its slot. Without a header above
   them any more, the stats are now the FIRST thing in the section, so the
   top border/margin that used to separate them from the lineup band reads
   as a stray line floating under the horizon rule — drop it here only. */
.pathx-grid.is-hidden { display: none; }
.choose .lstats { margin-top: 0; padding-top: 0; border-top: none; }
/* Cut from three stats to two 2026-08-13 ("10,000+ Google Reviews,
   1,000,000+ Product Sold") — tc60-v5.css's `.lstats` is still
   `repeat(3, minmax(0,1fr))`, which would leave a dangling empty third
   column at desktop widths with only two children. */
.choose .lstats { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* ---- §4 · read more (Lineup reviews) --------------------------------
   The real reviews run far longer than the placeholders they replaced.
   Clamped to 4 lines by default; `.lq-more` only appears when
   wireReadMore() (tc60-v5.js) measures real overflow. A `role="button"`
   SPAN, not a `<button>` — see the long note beside moreToggle() in
   tc60-v5.js for why a real button breaks here. */
.lq-text.lq-clamp {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  overflow: hidden;
}
.lq-text.lq-clamp.is-expanded {
  display: block;
  -webkit-line-clamp: unset;
  overflow: visible;
}
.lq-more {
  display: inline-block;
  margin-top: 8px;
  font-family: var(--font-head); font-weight: 600;
  font-size: 12.5px; letter-spacing: .01em;
  color: var(--orange-300);
  cursor: pointer;
  border-bottom: 1px solid transparent;
  transition: border-color .2s var(--ease);
}
.lq-more:hover, .lq-more:focus-visible { border-color: currentColor; }
.lq-more:focus-visible { outline: 2px solid var(--orange-300); outline-offset: 3px; border-radius: 2px; }
.lq-more[hidden] { display: none; }

/* ---- §5 · timeline — draggable horizontal filmstrip ------------------
   REBUILT 2026-08-05 (second pass, same day): "the scroll on the timeline
   is not working, pls make it draggable to view the timeline horizontally".
   The original pinned/scrubbed mechanic (a 460vh runway + `position: sticky`
   stage, scrubbed by reading the page's OWN vertical scroll position — see
   the git history on this section) is gone. In its place: `.tlf-frames` is
   just a native horizontally-scrollable box, exactly like the product
   slider below (`.pslide-viewport`) — touch already drags it, and
   tc60-v7.js §1 adds pointer-drag for a mouse, since a plain overflow box
   does nothing for a mouse without that. Simpler, and it can't silently
   stop working the way a scroll-jacked one can if the runway's height
   maths ever drifts from the viewport.

   COLOUR, not lifted from the original React/GSAP reference: the reference
   ran on a dark stage with a lime accent; #history here is a LIGHT section
   (`.has-watermark`, no `.bg-ink`), so this reads off the page's own
   --orange-*/--grey-* tokens instead of inventing a new dark card. Class
   names keep the tlf- prefix from that pass rather than reverting to plain
   names, so this is still a one-block diff against git history. */
.tlf-runway { position: relative; }
.tlf-stage {
  display: flex; flex-direction: column;
  margin-top: clamp(26px, 3.4vw, 40px);
}

.tlf-stage-head {
  position: relative; z-index: 3;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  padding: 0 0 18px;
}
.tlf-eyebrow {
  font-family: var(--font-head); font-weight: 600;
  font-size: 11px; text-transform: uppercase; letter-spacing: .14em;
  color: var(--grey-500);
}
.tlf-sixty { color: var(--orange-500); font-weight: 600; }

/* #history already carries a giant "60" watermark from `.has-watermark`
   (tc60-v3.css), top-right at the same spot the ghost year needs — the two
   stacked into unreadable clutter. The ghost year replaces it here; the
   plain "60" is unchanged everywhere else `.has-watermark` is used. */
#history .numeral-watermark { display: none; }

/* Giant ghost year — far plane behind the filmstrip; rolls 1966 -> 2026 */
.tlf-yearwm {
  position: absolute; top: 2%; right: -1vw; z-index: 0;
  font-family: var(--font-head); font-weight: 600;
  font-size: clamp(90px, 13vw, 180px);
  line-height: 1; letter-spacing: -.05em;
  color: var(--grey-800);
  opacity: .06;
  font-variant-numeric: tabular-nums;
  pointer-events: none; user-select: none;
}

.tlf-frames {
  position: relative;
  width: 100vw; margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw);
  padding: 0 calc(50vw - 50%);
  box-sizing: border-box;
  /* the scroll container itself, native-scrolled — drag (tc60-v7.js §1) or
     swipe moves it, no JS transform on the track underneath any more. */
  overflow-x: auto; overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  cursor: grab;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 4%, #000 96%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 4%, #000 96%, transparent 100%);
}
.tlf-frames::-webkit-scrollbar { display: none; }
.tlf-frames.is-dragging { cursor: grabbing; scroll-snap-type: none; }
.tlf-track {
  display: flex; align-items: stretch;
  width: max-content; gap: 2.5vw;
}
.tlf-frame {
  flex: 0 0 min(78vw, 520px);
  display: flex; flex-direction: column;
  scroll-snap-align: start;
}
.tlf-frame-text { flex: 0 0 auto; padding-bottom: 16px; }
.tlf-frame-year {
  font-family: var(--font-head); font-weight: 600;
  font-size: 13px; letter-spacing: .08em;
  color: var(--orange-500);
  margin-bottom: 8px;
}
.tlf-frame-text h3 {
  font-family: var(--font-head); font-weight: 600;
  font-size: clamp(20px, 2.6vw, 28px); letter-spacing: -.02em; line-height: 1.14;
  color: var(--grey-800);
  margin: 0;
}
.tlf-frame-media {
  position: relative; margin: 0;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--white-200);
  pointer-events: none; /* dragging the strip must not start an image drag */
}
.tlf-frame-media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  -webkit-user-drag: none;
}
/* four of seven milestones have no real photo yet — see hub-v3.html's note.
   A plain labelled panel, not a mis-attributed stock/lifestyle shot. */
.tlf-frame.is-photo-tbc .tlf-frame-media {
  display: flex; align-items: center; justify-content: center;
  background: var(--white-200);
  border: 1px dashed var(--white-300);
}
.tlf-tbc {
  font-family: var(--font-head); font-weight: 600;
  font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--grey-500);
}

/* ---- bottom axis ---- */
.tlf-axis { position: relative; height: 56px; margin: 18px 0 0; flex: 0 0 auto; z-index: 3; }
.tlf-line { position: absolute; left: 0; right: 0; top: 6px; height: 2px; background: var(--white-300); }
.tlf-line-fill {
  position: absolute; left: 0; top: 0; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--orange-400), var(--orange-300));
}
.tlf-playhead {
  position: absolute; left: 0; top: 50%; width: 12px; height: 12px;
  border-radius: 50%; background: var(--orange-300);
  box-shadow: 0 0 0 4px rgba(243, 191, 130, .28);
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.tlf-marks { position: absolute; left: 0; right: 0; top: 0; display: flex; justify-content: space-between; }
.tlf-mark {
  -webkit-appearance: none; appearance: none;
  background: none; border: none; padding: 0; margin: 0;
  font: inherit; color: inherit; width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  cursor: pointer; overflow: visible;
}
.tlf-mark:focus { outline: none; }
.tlf-mark:focus-visible { outline: 2px solid var(--orange-300); outline-offset: 4px; border-radius: 4px; }
.tlf-mark-dot {
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--white-300); border: 2px solid var(--white);
  box-sizing: border-box;
  transition: background .3s, transform .3s;
}
.tlf-mark.active .tlf-mark-dot { background: var(--orange-300); transform: scale(1.4); }
.tlf-mark-year {
  font-family: var(--font-head); font-weight: 600;
  font-size: 11px; white-space: nowrap; color: var(--grey-500);
  transition: color .3s;
}
.tlf-mark.active .tlf-mark-year { color: var(--grey-800); }

/* Narrow viewports keep the exact same horizontal drag/swipe strip — this
   used to switch to a vertically-stacked column here, which is the wrong
   fix now that touch scrolling is the primary way everyone reaches this
   component anyway. Only the ghost year (crowds a narrow frame) and the
   eyebrow row (no room next to a narrower filmstrip) drop off. */
@media (max-width: 680px) {
  .tlf-yearwm { display: none; }
  .tlf-stage-head { display: none; }
  .tlf-frame { flex-basis: 84vw; }
}

/* ---- §6 · awards — the four claims now four plaques -------------------
   Was one `.plaque.is-list` card holding all four claims as a bulleted
   list ("I dont literally mean put [all four] in 1 card"). Each is now its
   own `.plaque.is-type` card — the same class the ring's other text
   plaques already use, no new CSS needed. The empty rule block this
   replaced is gone rather than left dead, since it was 15 lines scoped to
   one class nothing else on the page uses.

   Below the ring: the `.spin-legend` strip that restated every plaque as
   plain text is gone, replaced with another push to the offer — see
   .awards-cta. */
.awards-cta { margin-top: clamp(28px, 4vw, 40px); text-align: center; }

/* ---- §6a · award images fill the card, no side padding -----------------
   "each award card not have padding on the sides for the images... just
   shows the full award". tc60-v3.css's `.p-face` padding (16px 20px) is
   shared by every plaque face, image and text alike — dropping it site-wide
   would crowd the .p-big/.p-sm text plaques against their own edges. Scoped
   to the image plaques only (`.plaque:not(.is-type)`, since that's the
   existing split between logo-image and stat-text plaques), keeping
   object-fit: contain so each logo still keeps its own aspect ratio and
   just uses the full card box instead of a padded-down one.

   Second pass: "remove the white background card and stroke... just the
   award itself without being inside another 'card'". tc60-v3.css's
   `.plaque` base rule gives every plaque a white fill, a hairline border,
   and a drop shadow — right for the .is-type stat cards, which are just
   text and need a surface to sit on, but wrong for the real badge images:
   each one is already a self-contained card (GPTW's navy plate, the
   Straits Times lockup's own bordered rectangle), so the plaque's white
   frame around it read as a card inside a card. Same selector split as
   above, this time on the plaque itself rather than its face. */
.plaque:not(.is-type) .p-face { padding: 0; }
.plaque:not(.is-type) { background: transparent; border: none; box-shadow: none; }

/* ---- §6b · offers header centred ------------------------------------
   "Center align the header here to make it obvious" — once the lead
   paragraph was removed there was nothing left to fill `.hang-head`'s
   second grid column, so the single remaining child just sat in column
   one instead of centring. Scoped to #promo rather than a generic
   `.hang-head` modifier, since every other head on the page still runs
   the two-column head + lead layout. */
.hang-head.is-centered {
  grid-template-columns: 1fr;
  justify-items: center;
  text-align: center;
}
/* "Remove the line before 15-30 August 2026" — `.eyebrow::before` (tc60.css)
   draws a 26px orange rule before every eyebrow's text; `#promo`'s is the
   only eyebrow on the page carrying `.centered`, so that's what scopes this
   to just the one line instead of stripping it from every eyebrow (e.g.
   #people's "Everyone else in the picture" keeps its rule). */
.eyebrow.centered::before { display: none; }

/* The promo date moves to the script face on request 2026-08-14 ("change
   15-30 August 2026 to our September Spirit font"). Same `.eyebrow.centered`
   scope as the rule above — it's still the only eyebrow on the page with
   this class. Three corrections carried over from `.hero-roll-lead`/
   `.hero-h1` (tc60-v6.css §1-2), since every script-face use on this page
   needs them: weight forced to 400 (the face ships one weight), tracking
   zeroed (Inter's 2.5px letter-spacing shreds a handwriting face), and
   uppercase turned off (the face has no real capitals — forcing "August"
   caps would render disconnected block letters, not script). Size bumped
   from the inherited 11px too: verified in headless Chrome, at 11px the
   face's own small x-height (39.6% of em, tc60-v6.css §1) rendered the
   date as an illegible orange squiggle — 16px was the smallest that read
   clearly. Bumped again to 40px on request 2026-08-14 ("make it a lot
   bigger!! Use 40px maybe"). */
.eyebrow.centered {
  font-family: var(--font-script);
  font-weight: 400;
  font-size: 40px;
  letter-spacing: 0;
  text-transform: none;
}

/* ---- §6c · brand filter -----------------------------------------------
   Three levels, one per TC60 brand — replaces the single nine-card slider
   with three filtered views of three cards each, wired in tc60-v7.js §2. */
.pfilter {
  display: flex; justify-content: center; flex-wrap: wrap;
  gap: 10px;
  margin-top: clamp(20px, 3vw, 30px);
}
.pfilter-btn {
  -webkit-appearance: none; appearance: none;
  font-family: var(--font-head); font-weight: 500;
  font-size: 13.5px; letter-spacing: -.005em;
  padding: 10px 20px;
  border: 1px solid var(--white-300);
  border-radius: var(--radius);
  background: var(--white);
  color: var(--grey-600);
  cursor: pointer;
  transition: background .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease);
}
.pfilter-btn:hover { border-color: var(--orange-300); color: var(--grey-800); }
.pfilter-btn.is-active { background: var(--grey-800); border-color: var(--grey-800); color: #fff; }
.pfilter-btn:focus-visible { outline: 2px solid var(--orange-300); outline-offset: 2px; }

/* ---- §7 · product slider (replaces bundle calculator) ----------------
   Card anatomy matches Bryan's Sonos Owners Offer reference
   (figma.com/design/MUDLrQ2PQbSIaFsqOpYsoR node 1:803): photo, category,
   name, was/now price, one line, a shop link. Native scroll-snap rather
   than a JS-computed track transform — nine cards of very different
   description lengths don't want a fixed step size, and scroll-snap
   gets the "one card at a time" feel for free.

   Nine cards total, three per brand, filtered by tc60-v7.js §2 down to
   the active brand's three — `.pslide-card.is-filtered` is what the
   filter toggles. On a wide viewport the visible three sit in a plain
   3-col grid (see the "no slider needed" media query below); the
   horizontal scroll-snap track only carries the weight on narrow
   viewports, where three cards can still overflow. */
.pslide { margin-top: clamp(26px, 3.6vw, 44px); }
.pslide-card.is-filtered { display: none; }
.pslide-viewport {
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.pslide-viewport::-webkit-scrollbar { display: none; }
.pslide-track {
  display: flex; gap: clamp(14px, 1.6vw, 22px);
  padding: 4px 4px 16px;
}
.pslide-card {
  scroll-snap-align: start;
  flex: 0 0 clamp(220px, 26vw, 300px);
  display: flex; flex-direction: column;
  background: var(--white);
  border: 1px solid var(--white-300);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color .35s var(--ease), transform .35s var(--ease), box-shadow .35s var(--ease);
}
.pslide-card:hover {
  border-color: var(--orange-200);
  transform: translateY(-3px);
  box-shadow: 0 20px 44px -26px rgba(47, 51, 53, .3);
}
.pslide-shot { margin: 0; aspect-ratio: 4 / 3; background: var(--white-200); overflow: hidden; }
.pslide-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* the third product per brand has no confirmed photo yet — same TBC
   treatment as the timeline's `.tlf-tbc`, not a mis-attributed stock shot. */
.pslide-shot-tbc { display: flex; align-items: center; justify-content: center; border: 1px dashed var(--white-300); }
.pslide-tbc {
  font-family: var(--font-head); font-weight: 600;
  font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--grey-500);
}
.pslide-cat {
  margin: 14px 18px 0;
  font-family: var(--font-head); font-weight: 600;
  font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--grey-500);
}
.pslide-name {
  margin: 4px 18px 0;
  font-family: var(--font-head); font-weight: 600;
  font-size: 19px; letter-spacing: -.01em; color: var(--grey-800);
}
.pslide-price {
  margin: 8px 18px 0;
  display: flex; align-items: baseline; gap: 8px;
  font-variant-numeric: tabular-nums;
}
.pslide-price .was { font-size: 13px; color: var(--grey-500); text-decoration: line-through; }
.pslide-price .now { font-family: var(--font-head); font-weight: 600; font-size: 17px; color: var(--orange-500); }
/* §21 · whole-number % off badge beside the price (2026-08-11) — rounded
   from each card's own was/now pair, not the page's 20/25% headline
   figures, since per-card savings vary card to card. */
.pslide-discount {
  font-family: var(--font-head); font-weight: 600;
  font-size: 11px; color: var(--orange-500);
  background: var(--orange-100);
  padding: 2px 7px; border-radius: 20px; line-height: 1.5;
}
.pslide-desc { margin: 8px 18px 0; font-size: 13px; line-height: 1.55; color: var(--grey-600); flex: 1; }
.pslide-go {
  display: flex; align-items: center; gap: 6px;
  margin: 14px 18px 18px;
  font-family: var(--font-head); font-weight: 600;
  font-size: 13px; color: var(--grey-800);
}
.pslide-go .arrow { transition: transform .3s var(--ease); }
.pslide-go:hover .arrow { transform: translateX(4px); }

.pslide-nav { display: flex; align-items: center; gap: 14px; margin-top: 10px; }
.pslide-bar { flex: 1; height: 3px; background: var(--white-300); border-radius: 2px; overflow: hidden; }
.pslide-bar i { display: block; height: 100%; width: 0; background: var(--orange-300); transition: width .25s var(--ease); }
.pslide-btn {
  flex: 0 0 auto; width: 38px; height: 38px;
  border-radius: 50%; border: 1px solid var(--white-300);
  background: var(--white); color: var(--grey-800);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: border-color .25s var(--ease), background .25s var(--ease);
}
.pslide-btn:hover { border-color: var(--orange-300); background: var(--orange-100); }
.pslide-btn:active { transform: scale(.92); }

/* "add 1 more button at the bottom of the products" — anchors to the same
   #signup capture the individual "Shop ___" links and every other CTA on
   this page already point to, so it's one more door into the same form
   rather than a new destination. Same centred-CTA shape as .awards-cta. */
.pslide-cta { margin-top: clamp(20px, 3vw, 32px); text-align: center; }

/* Above 680px, three visible cards fit a viewport without needing to
   scroll at all — the slider mechanic (scroll-snap, prev/next, the
   progress bar) is a narrow-viewport-only concern now that filtering
   caps the visible set at three. */
@media (min-width: 681px) {
  .pslide-viewport { overflow: visible; }
  .pslide-track { display: grid; grid-template-columns: repeat(3, 1fr); padding: 4px 4px 0; }
  .pslide-nav { display: none; }
}

/* ---- §8 · sign-up capture, moved up ------------------------------------
   The Paperform embed shell that used to live here (figma.com/design/
   MUDLrQ2PQbSIaFsqOpYsoR node 1:902) is gone on request — Bryan is folding
   the real form into the `.capture` card below himself rather than this
   mockup carrying an empty shell alongside it. `.capture` already supplies
   its own dark gradient card (tc60.css), so it needs only spacing here,
   now that it sits directly under the product grid instead of in its own
   `.bg-soft` section. */
.pslide + .capture { margin-top: clamp(40px, 5.5vw, 72px); }

/* ---- §9 · rsum — bigger impact, stacked, Google link removed -----------
   "Make the 9,000+ 5-star MORE impactful and obvious. Remove the link to
   read more on google." First pass gave 9,000+ its own stat the same size
   as the 5.0 score, side by side on one baseline — which, at those very
   different type sizes (14px stars, 40px numerals), read as a run-together
   "★★★★★5.0 9,000+ Google reviews" rather than two distinct stats. Second
   pass: both stats now stack big-number-over-caption, the same shape the
   awards ring's own `.plaque.is-type` stat cards use (p-big over p-sm), so
   each stat is unambiguous on its own and a hairline `.rsum-divider`
   separates the two instead of relying on gap alone. The "Outstanding —
   certified a Great Place to Work® six years running." sentence and the
   "Read them on Google" link are both deleted from the markup; their old
   CSS rules (`.rsum-txt`, `.rsum-link`, both tc60-v5.css) are left there,
   unused, same as this pass's supersede-don't-touch-the-earlier-file
   convention. */
.rsum { align-items: stretch; gap: clamp(20px, 2.6vw, 32px); }
.rsum-stat { display: flex; flex-direction: column; gap: 6px; }
.rsum-divider { width: 1px; align-self: stretch; background: rgba(255, 255, 255, .16); }
.rsum-score { font-size: clamp(32px, 3.8vw, 44px); font-weight: 600; line-height: 1; }
.rsum-count {
  font-family: var(--font-head); font-weight: 600;
  font-size: clamp(32px, 3.8vw, 44px); line-height: 1; letter-spacing: -.03em;
  color: var(--orange-300);
}
.rsum-stat-lbl {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 500; letter-spacing: .01em;
  color: var(--grey-400); white-space: nowrap;
}
.rsum-stat-lbl .rsum-stars { color: var(--orange-300); font-size: 12px; letter-spacing: 1px; }
@media (max-width: 480px) {
  .rsum-divider { display: none; }
}

/* ---- §10 · header line-height ------------------------------------------
   "Make the headers […] have more line height between" — the base rule
   (tc60-v3.css `.hang-head h2 { line-height: 1.04 }`) sits two-line
   headlines almost touching. Scoped to the three sections that hold the
   four requested headlines (#people has one, #history has two — the
   timeline head AND "They say it better than us." — #promo has one)
   rather than overriding `.hang-head h2` globally: #voices' "Everyone's
   favourite ___" head is also technically a `.hang-head h2` but it carries
   the roller mechanic (`.hero-roll`), and that animation's vertical math
   assumes its own line-height — this leaves it alone on purpose. */
#people .hang-head h2,
#history .hang-head h2,
#promo .hang-head h2 {
  line-height: 1.22;
}

/* ---- §11 · capture — header/body spacing --------------------------------
   "More space between the header and the body" — h2/p both reset to
   margin:0 at the base (tc60.css), so there was nothing between them.
   Scoped to `.capture .lead` rather than `.lead` generally, since
   `.hang-head .lead` elsewhere on the page already sets its own spacing
   for a different layout (it sits beside a heading, not under one). */
.capture .lead { margin-top: clamp(14px, 1.8vw, 22px); }

/* ---- §12 · then & now ---------------------------------------------------
   NEW, optional section ("add 1 more section as an option") — a single
   BEFORE/PRESENT comparison alongside the year-by-year filmstrip above,
   rather than instead of it. First built as a static two-column grid,
   REBUILT the same day as a draggable before/after slider once Bryan
   pointed at the exact reference: the "Play your way at home or away"
   image-comparison slider in sections/home-or-away.liquid. Markup, class
   shapes (`.thennow-layer`/`--before`/`--after`, `.thennow-handle`) and
   the clip-path drag mechanic (tc60-v7.js §14) are ported from that
   section — same idea (`clip-path: inset()` on the top layer, a
   draggable handle that sets both the clip and its own `left`), restyled
   in this page's own flat/4px-radius language instead of the Mojave
   page's pill-shaped chrome, and the SVG left/right-arrow handle glyph
   swapped for a single ↔ character rather than duplicating two inline
   SVGs for a mockup.

   Only the "Now" facts below the slider are things Bryan actually said
   this pass (stores across 4 countries, 100+ staff, the three brands);
   the "Then" list's bullets are this pass's own inference from the 1966
   timeline entry, not a supplied fact — flagged in the HTML comment, not
   asserted as fact-checked. Same reason the "Now" side of the slider is
   a TBC placeholder rather than a guessed present-day store shot: none
   of 2022/2024/2026 has a real photo in the timeline above either, and
   reusing an old storefront photo under a "now" caption would be exactly
   the misattribution this page has avoided everywhere else (see the
   timeline's own PHOTO TBC note). The "Then" side is real — the same
   `W_storefront_1.jpg` the 1966 timeline frame uses, same caption
   context, no new claim. */
.thennow { margin-top: clamp(36px, 4.6vw, 56px); }
.thennow-head {
  display: flex; flex-direction: column; align-items: center;
  gap: 6px; text-align: center;
  margin-bottom: clamp(18px, 2.4vw, 26px);
}
.thennow-eyebrow {
  font-family: var(--font-head); font-weight: 600;
  font-size: 11px; text-transform: uppercase; letter-spacing: .14em;
  color: var(--orange-500);
}
.thennow-head h3 {
  font-family: var(--font-head); font-weight: 400;
  font-size: clamp(22px, 2.6vw, 30px); letter-spacing: -.02em;
  color: var(--grey-800); margin: 0;
}

.thennow-slider-wrap { display: flex; justify-content: center; }
/* Height changed from a fixed `min(460px, 62vw)` to `aspect-ratio` on
   request 2026-08-13 ("increase the height... so it doesn't crop the
   image"). Both Aug-13 photos are exactly 3000×1400 — at 1122px (this
   page's max content width, `--wrap` minus its gutters), the old fixed
   460px box was ~64px shorter than that ratio wants, so `object-fit:
   cover` on `.thennow-media img` was cropping ~32px off the top and
   bottom to fill it. Sizing the box to the photos' own ratio means cover
   has nothing left to crop, at any width — this replaces the guess with
   the actual number instead of just guessing taller. */
.thennow-slider {
  position: relative;
  width: 100%;
  aspect-ratio: 3000 / 1400;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--white-200);
  user-select: none;
}
/* Mobile gets its own square (1500x1500) crop of the same two photos —
   see the `<picture><source media="(max-width: 680px)">` swap in
   page.tc60.liquid — rather than just stretching the 3000x1400 desktop
   crop's aspect-ratio taller, which would zoom `object-fit: cover` in and
   crop the newspaper-ad half off the sides. Ported from the SG repo's
   same-day fix, 2026-08-14. */
@media (max-width: 680px) {
  .thennow-slider { aspect-ratio: 1 / 1; }
}
.thennow-layer { position: absolute; inset: 0; width: 100%; overflow: hidden; }
.thennow-layer--before { z-index: 0; }
.thennow-layer--after { z-index: 1; }
.thennow-media { position: absolute; inset: 0; margin: 0; width: 100%; height: 100%; }
.thennow-media picture { display: block; width: 100%; height: 100%; }
.thennow-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.thennow-media.is-tbc {
  display: flex; align-items: center; justify-content: center;
  background: var(--white-200);
  border: 1px dashed var(--white-300);
}
.thennow-tbc {
  font-family: var(--font-head); font-weight: 600;
  font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--grey-500);
}
.thennow-tag {
  position: absolute; top: 16px; z-index: 3;
  font-family: var(--font-head); font-weight: 600;
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: #fff;
  background: rgba(20, 21, 22, .55);
  padding: 7px 12px; border-radius: var(--radius);
  pointer-events: none;
}
.thennow-tag--before { left: 16px; }
.thennow-tag--after { right: 16px; }
.thennow-handle {
  position: absolute; top: 0; bottom: 0; z-index: 4;
  width: 44px;
  padding: 0; border: none; background: transparent;
  display: flex; align-items: center; justify-content: center;
  cursor: ew-resize;
}
.thennow-handle::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 50%;
  transform: translateX(-50%);
  width: 2px; background: rgba(255, 255, 255, .85);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .12);
}
.thennow-handle-inner {
  position: relative; z-index: 1;
  display: flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  border-radius: 50%;
  background: #fff; color: var(--grey-800);
  font-size: 16px; line-height: 1;
  box-shadow: 0 6px 16px -6px rgba(0, 0, 0, .35);
  transition: background .15s var(--ease);
}
.thennow-handle:hover .thennow-handle-inner,
.thennow-handle:focus-visible .thennow-handle-inner { background: var(--orange-100); }
.thennow-handle:focus-visible { outline: none; }

/* §17 · Then & Now rewrite (2026-08-07) — replaces the terse bullet-only
   THEN/NOW lists with a lead paragraph under the head and two column blocks
   (label + subhead + copy) under the slider, plus a shared stat row and a
   closing line. `.thennow-list`/`--then`/`--now` are gone rather than left
   orphaned — nothing on the page still renders them. */
.thennow-lead { max-width: 720px; margin: 0 auto clamp(28px, 4vw, 44px); text-align: center; }

.thennow-facts {
  margin-top: clamp(18px, 2.4vw, 26px);
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(24px, 3.2vw, 40px);
}
/* Columns capped narrower than their 1fr cell on request, 2026-08-07
   ("more separation… I think they just need shorter width divs") — the
   gap alone wasn't reading as separation because each div still spanned
   its full half of the row. `--now` hugs the right edge of its cell
   (it's already text-align:right) so the empty space lands in the
   middle rather than on the outer edges. */
.thennow-col { max-width: 340px; }
.thennow-col--now { margin-left: auto; }
@media (max-width: 560px) {
  .thennow-facts { grid-template-columns: 1fr; }
  .thennow-col, .thennow-col--now { max-width: none; margin-left: 0; }
}
.thennow-col--now { text-align: right; }
@media (max-width: 560px) {
  .thennow-col--now { text-align: left; }
}
.thennow-col-label {
  font-family: var(--font-head); font-weight: 600;
  font-size: 11px; text-transform: uppercase; letter-spacing: .14em;
  color: var(--orange-500); margin: 0 0 6px;
}
.thennow-col-h4 {
  font-family: var(--font-head); font-weight: 500;
  font-size: clamp(17px, 1.8vw, 20px); letter-spacing: -.01em;
  color: var(--grey-800); margin: 0 0 8px;
}
.thennow-col-p {
  font-family: var(--font-head); font-weight: 400;
  font-size: 14px; line-height: 1.55; color: var(--grey-600);
  margin: 0;
}

.thennow-stats {
  list-style: none; margin: clamp(22px, 3vw, 32px) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: clamp(10px, 2vw, 22px);
}
.thennow-stats li {
  font-family: var(--font-head); font-weight: 600;
  font-size: 13px; color: var(--grey-800);
  padding-left: 16px; position: relative;
}
.thennow-stats li::before {
  content: ""; position: absolute; left: 0; top: 7px;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--orange-400);
}

.thennow-close {
  margin: clamp(18px, 2.4vw, 26px) auto 0;
  max-width: 640px; text-align: center;
  font-family: var(--font-head); font-weight: 500;
  font-size: clamp(15px, 1.6vw, 17px); line-height: 1.5;
  color: var(--grey-700);
}

/* §18 · Additional Savings callout (2026-08-07, un-boxed 2026-08-11) — was
   a bordered card under the #promo header; now reads as plain paragraph
   text under the header instead of its own card. */
.tc60-callout {
  margin: clamp(20px, 3vw, 32px) auto 0;
  max-width: 640px;
  text-align: center;
}
.tc60-callout-title {
  font-family: var(--font-head); font-weight: 600;
  font-size: 15px; color: var(--orange-500); margin: 0 0 4px;
}
.tc60-callout-line {
  font-family: var(--font-head); font-weight: 500;
  font-size: 14px; line-height: 1.5; color: var(--grey-700);
  margin: 4px 0 0;
}
.tc60-callout-line:first-of-type { margin-top: 0; }

/* ---- §13 · product slider — placeholder lifestyle photos (superseded) --
   This section used to flatten all nine cards to the dashed
   `.pslide-shot-tbc`/`.pslide-tbc` placeholder pending real lifestyle
   photography. Superseded 2026-08-06: the lineup was replaced and every
   card now carries a real photo (hub-v3.html §"BESTSELLER PRODUCT
   SLIDER"), so nothing in the markup uses those two classes any more.
   Left defined in tc60-v3.css rather than deleted, since other mockup
   variants in this folder still reference them. */

/* ---- §15 · mobile CTAs — equal width, one line -------------------------
   "make both the buttons in the hero the same width. Make the primary
   CTA 1 liner. (Same for every similar button below)" — every `.btn` on
   the page shares the same long copy pattern ("Celebrate with us. Enjoy
   20% off. →"), which is tight enough at `.btn-lg`'s desktop padding to
   wrap on a narrow phone. Scoped to `.btn`/`.btn-lg` generally rather than
   just `.hero-actions`, so the lineup/awards/voices single-button CTAs
   and the capture form's submit button (plain `.btn`, not `.btn-lg`) get
   the same one-line treatment without touching each individually.

   "Same width" only has a real pair to compare in the hero (primary CTA
   + the `.skip-ahead` secondary) — everywhere else on the page a CTA
   wrapper holds just one button. Both hero buttons go full-width and
   stack (flex-wrap already used them one-per-row above 680px; below it
   they're forced to it), which makes them equal by construction. */
@media (max-width: 680px) {
  .btn { white-space: nowrap; letter-spacing: 1px; }
  .btn-lg { padding: 16px 18px; font-size: 11px; }

  .hero-actions .btn,
  .hero-actions .skip-ahead {
    flex: 1 1 100%;
    width: 100%;
    justify-content: center;
    white-space: nowrap;
  }
  .skip-ahead { font-size: 13px; padding: 14px 18px; }

  /* ---- §15b · brand filter — one line per pill ----------------------
     "in '20% off section' make the product selections 1 line as well" —
     "Bowers & Wilkins" is the long label of the three; nowrap keeps it
     on one line inside its own pill regardless of how many pills fit
     on a row (three pills wrapping to two rows is fine — each pill's
     own label staying on one line is the actual ask). */
  .pfilter-btn { white-space: nowrap; padding: 9px 16px; font-size: 13px; }

  /* ---- §15c · TC60 Specials callout, smaller on mobile (2026-08-14) ----
     15px/14px (tc60-v7.css §18) reads oversized against the rest of the
     mobile #promo header — shrunk one tier down. */
  .tc60-callout-title { font-size: 13px; }
  .tc60-callout-line { font-size: 12.5px; }
}

/* ---- §16 · legacy year-by-year timeline, hidden ------------------------
   "I will likely launch with the before/after version first" — same
   reversible-hide pattern as the path chooser (§3, `.pathx-grid.is-hidden`):
   the block (hub-v3.html, "Sixty years, one room at a time." head through
   the seven-frame filmstrip) stays in the DOM, just not rendered. To bring
   it back: delete `is-hidden` from `.legacy-timeline`'s class list, or
   delete this one rule — either alone is a full revert, no other change
   needed on either side. */
.legacy-timeline.is-hidden { display: none; }

/* ---- §16b · staff lineup ("The People"), hidden — HK has no staff named
   yet (2026-08-14), so CAST is an empty array (tc60-v5.js) and the section
   would only render its head + empty lineup grid. Same reversible-hide
   pattern as above: to bring it back once HK staff are named, delete
   `is-hidden` from `#people`'s class list, or delete this one rule. */
.lineup-sec.is-hidden { display: none; }

/* §19 · sign-up capture — glass + glow behind the Paperform embed
   (2026-08-11), matching the frosted form-card treatment used on the
   Sonos Flagship 2nd Anniversary demo section (sections/sfs-2ndanni-demo.
   liquid — translucent panel over a dark background, soft border). Added
   a warm glow on top of that same idea, in the site's own gold accent
   (var(--orange-300), #F3BF82 — already used for glow elsewhere, e.g.
   .hero-badge .dot's box-shadow in tc60-v2.css) rather than introducing a
   new color, since `.capture` is already this gold-on-dark palette.
   `position: relative` lifts the panel above `.capture::before`'s giant
   faint "60" watermark, same reason `.capture h2`/`.capture .lead` already
   carry it (tc60.css). */
.capture-embed {
  position: relative;
  padding: clamp(20px, 3vw, 28px);
  border-radius: 10px;
  background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 255, 255, .14);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 0 60px rgba(243, 191, 130, .22),
              inset 0 1px 0 rgba(255, 255, 255, .08);
}

/* §20 · FAQ accordion (2026-08-11) — shell only, native <details>/
   <summary> so it opens/closes with no JS, matching every other flat,
   4px-radius, untextured control on this page. */
.faq-list { max-width: 720px; margin: clamp(20px, 3vw, 32px) auto 0; }
.faq-item {
  border-bottom: 1px solid var(--white-300);
}
.faq-item:first-of-type { border-top: 1px solid var(--white-300); }
.faq-q {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: clamp(16px, 2.2vw, 20px) 4px;
  font-family: var(--font-head); font-weight: 500;
  font-size: clamp(15px, 1.6vw, 17px); color: var(--grey-800);
  cursor: pointer; list-style: none;
}
.faq-q::-webkit-details-marker { display: none; }
.faq-icon { position: relative; flex-shrink: 0; width: 18px; height: 18px; }
.faq-icon::before,
.faq-icon::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  background: var(--grey-600); transition: transform .2s ease, opacity .2s ease;
}
.faq-icon::before { width: 12px; height: 1.5px; transform: translate(-50%, -50%); }
.faq-icon::after { width: 1.5px; height: 12px; transform: translate(-50%, -50%); }
.faq-item[open] .faq-icon::after { transform: translate(-50%, -50%) rotate(90deg); opacity: 0; }
.faq-a { padding: 0 4px clamp(16px, 2.2vw, 20px); }
.faq-a p {
  font-family: var(--font-body); font-size: 14px; line-height: 1.6;
  color: var(--grey-600); margin: 0;
}
/* §21 · FAQ real content (2026-08-13) — several answers run multiple
   paragraphs and/or a short list (bonus TC Points tiers, discount rates,
   product exceptions). `.faq-a p`'s reset above collapses adjacent
   paragraphs with no gap on purpose (the placeholder was one line), so
   that needs restoring now the shell has to hold more than one block.
   List dots reuse `.thennow-stats li::before`'s exact circle rather than
   a browser default marker, matching this page's own flat, no-native-UI
   list style. `strong` is forced to 600 rather than left at the browser
   default 700 — this page's Inter build only loads 300/400/500/600 (see
   the `<link>` in page.tc60.liquid), so an unset `<strong>` would ask
   for a weight that was never downloaded. */
.faq-a p + p, .faq-a p + ul, .faq-a ul + p { margin-top: 10px; }
.faq-a strong { font-weight: 600; color: var(--grey-800); }
.faq-a ul { list-style: none; margin: 10px 0 0; padding: 0; }
.faq-a li {
  position: relative; padding-left: 16px;
  font-family: var(--font-body); font-size: 14px; line-height: 1.6;
  color: var(--grey-600);
}
.faq-a li + li { margin-top: 4px; }
.faq-a li::before {
  content: ""; position: absolute; left: 0; top: 9px;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--orange-400);
}

/* §22 · awards category liner (2026-08-13) — replaces the "Drag to spin"
   hint that used to hang under the ring (`.spin-hint`, tc60-v3.css). */
.spin-categories {
  text-align: center; margin: 30px 0 0;
  font-size: 12px; letter-spacing: .04em; color: var(--grey-500);
}

/* ---- §23 · hero headline — write-on entrance (2026-08-13) --------------
   Each line of `.hero-h1` is now its own block span (`.wl`, see the markup
   in page.tc60.liquid) rather than text + `<br>`. A `clip-path: inset()`
   sweeps left→right per line — the standard way to fake a stroke-by-
   stroke "written" reveal on a live web font, without needing the
   glyphs as SVG paths (the OTF has no such data, and generating it for
   one headline isn't worth a build step).

   Only the RIGHT inset animates (0 top/bottom): a horizontal-only wipe
   can't clip an ascender or a descender's tail, which is the trap this
   file's own history keeps hitting (see the roller's descender note in
   tc60-v3.css). Second line starts before the first finishes — a dead
   gap between strokes reads as two separate reveals, not one hand
   writing continuously. */
.write-on .wl {
  display: block;
  clip-path: inset(0 100% 0 0);
  animation: tc60-write-on 1s var(--ease-out-3) forwards;
}
.write-on .wl:nth-of-type(2) { animation-delay: .5s; }
@keyframes tc60-write-on {
  to { clip-path: inset(0 0 0 0); }
}
@media (prefers-reduced-motion: reduce) {
  .write-on .wl { clip-path: none; animation: none; }
}

/* ---- §24 · one script accent inside an Inter sentence (2026-08-13) ---
   "Everyone's favourite" (#voices) moves to the hero's script face, while
   the rolling word after it stays Inter. #people's "10,000+ 5-star Google
   reviews possible." was given the same treatment on 2026-08-13 but
   reverted the same day on request — that whole header is Inter again
   (§10's shared `line-height: 1.22` applies to it, same as #history/#promo).

   This face needs the same three corrections `.hero-h1` already made when
   it swapped to September Spirit (tc60-v6.css §1): weight forced to 400
   (the face ships one weight; leaving the inherited 600 asks the browser
   to synthesize a bold, which looks smudged on a script face), tracking
   zeroed (Inter's negative letter-spacing closes a handwriting face into
   a smear), and word-spacing pulled in (the face's own word gaps run
   wide). */
.hero-roll-lead {
  font-family: var(--font-script);
  font-weight: 400;
  letter-spacing: 0;
  word-spacing: -.07em;
}

/* ---- §25 · form embed, wider on mobile (2026-08-14) ---------------------
   `.capture-embed`'s 520px cap never bound on a phone screen — the number
   that actually squeezed it there was `.capture`'s own card padding
   (`clamp(36px, 6vw, 64px)`, tc60.css), stacked on top of `.wrap`'s gutter.
   On a 375px phone that's roughly 40px (wrap) + 72px (card) of padding
   eaten from both sides combined, leaving the Paperform iframe under
   270px wide. Bleeding just the embed out to the card's own edge (not the
   card itself — `.capture h2`/`.capture .lead` keep their padding, they're
   short lines that don't need the width) recovers that padding on one
   element only. `.capture`'s existing `overflow: hidden` (tc60.css) clips
   the embed back to the card's own rounded corners for free, so this
   can't visually spill past them. Same 680px breakpoint as §15. */
@media (max-width: 680px) {
  .capture-embed {
    max-width: none;
    margin-left: calc(-1 * clamp(36px, 6vw, 64px));
    margin-right: calc(-1 * clamp(36px, 6vw, 64px));
  }
}

/* ---- §26 · Lineup placeholder states, for country ports (2026-08-14) ---
   MY/HK/TH name their staff before a photo or a Google review exists to
   go with the name — tc60-v5.js's CAST entries can now omit `photo` and
   `review` outright rather than borrow a stand-in image or invent a
   quote. `.lp-photo-placeholder` just holds the panel's own flat --ink-2
   fill where `.lp > img` would otherwise sit (same absolute/inset:0 box,
   no image); `.lp-tbc` above it is the same label the SG page already
   uses for Zoe's borrowed group photo. `.lq-pending` is the review
   column's equivalent — plain, muted, no quote marks, since it isn't
   quoting anyone yet. */
.lp-photo-placeholder {
  position: absolute; inset: 0;
  background: var(--ink-2);
}
.lq-text.lq-pending {
  opacity: .6;
  font-style: italic;
}

/* Bestseller cards, for country ports whose local pricing isn't confirmed
   yet — same slot `.now` fills, muted rather than orange so it doesn't
   read as a real number, and the card ships with everything else (photo,
   name, copy, link) real. */
.pslide-price .pslide-tbc {
  font-family: var(--font-head); font-weight: 600; font-size: 13px;
  color: var(--grey-500);
  text-transform: uppercase; letter-spacing: .04em;
}

/* ---- §27 · Compact lineup row, for a cast under 5 (2026-08-14) ---------
   .lineup (tc60-v5.css) is `display: flex` with every .lp at `flex: 1 1 0`
   inside a full-bleed, `width: 100%` row — with 5 people (SG) that fills
   the row edge to edge and looks intentional; with a shorter cast (MY's 2
   today) the same rule stretches each panel into a wide, flattened banner
   instead of a portrait. `.lineup--compact` (set in tc60-v5.js off CAST.length) turns
   off the fill: the row is only as wide as its panels need to be, so a
   short cast reads as a shorter row, not a stretched one. Panel height is
   untouched (still --lp-h). Scoped to the desktop row only — the ≤760px
   snap strip (tc60-v5.css) already uses a fixed `flex: 0 0 80%` per card
   and never stretched to begin with.

   OPEN STATE, ROUND 3 (2026-08-14). Round 1 kept the open panel's real
   `flex-grow: 2.7` expansion but added `max-width` to stop it ballooning
   to ~800px ("images get cut off badly when the aspect ratio becomes so
   long") — that fixed the crop, but capping a still-animating `flex-grow`
   transition with a hard `max-width` it doesn't know about made the box
   overshoot toward its uncapped flex-grow width and then visibly snap
   back to the cap ("clicking on the image opens up the other image and
   it just shrinks back down immediately" — the flex-basis layout math
   briefly favoring the wrong panel mid-transition, not a JS bug; `open(i)`
   in tc60-v5.js only ever toggles the one clicked index). Round 2 dropped
   width entirely for a `transform: scale` "active" bump instead — safe,
   but Bryan wanted the width animation back ("the same animation as
   before but just not so wide"), just smaller.

   This round transitions `flex-basis` directly between two fixed values
   (closed clamp(220px, 26vw, 320px) → open 1.25x that) with `flex-grow`
   pinned at 0 for BOTH states. That sidesteps round 1's whole bug class:
   flex-grow's width comes from divvying up the row's free space, which is
   plentiful here (the row itself stays full section width per the note
   above) — ANY nonzero grow value claims ALL of it since no sibling
   competes, so "grow a little" isn't expressible as a small flex-grow
   number, and a max-width safety net is what caused the overshoot/snap.
   A concrete flex-basis has no free space to overshoot into — it just
   tweens between two known pixel values, exactly as wide as asked and no
   wider. `box-shadow` still sells the open panel as lifted.

   GAP added between panels, same request ("have a gap between the 2
   photos") — compact mode was still inheriting the 5-across SG row's
   tight `--lp-gap: 3px` (tc60-v5.css), meant for a shoulder-to-shoulder
   cluster, not a couple of centered portraits.

   CENTERED, same request ("Center align both images horizontally"): the
   row's own box was always full section width even in compact mode (only
   the ITEMS stayed narrow, per the note above) — `padding-left: var(--gutter)`
   just nudged that left-anchored cluster over by one gutter, leaving all
   the freed-up space on the right. `justify-content: center` centers the
   cluster of panels in the row instead, splitting the leftover space
   evenly on both sides.

   SPECIFICITY TRAP, ROUND 2: the flex-basis transition above silently did
   nothing ("could we add some easing… now it's just jumping to the wider
   view") — same shape as round 2's transform bug, different property.
   `html.js .lineup.is-dealt .lp` (tc60-v5.css, the deal-in entrance rule's
   settled state) sets its own `transition` shorthand listing flex-grow/
   opacity/transform only; that selector's specificity (0,4,1 — an `html`
   type selector plus four classes) beats plain `.lineup.lineup--compact
   .lp` (0,3,0), and `.lineup.is-dealt` is active for the entire normal
   life of the page, not just during the deal-in — so its `transition`
   shorthand always won and silently dropped flex-basis from the animated
   property list. Matched it with the same `html.js` prefix on the base
   `.lp` rule below — which then OUTRANKED the plain `.lp.is-open` rule
   right under it (0,4,1 beats 0,4,0), so the open panel's own flex-basis
   silently lost too and the panel never widened at all. Prefixed
   `.lp.is-open` with `html.js` as well so both stay in step; verified in
   headless Chrome afterward with a real class toggle sampled across the
   transition rather than by eye. */
@media (min-width: 761px) {
  .lineup.lineup--compact {
    width: auto;
    justify-content: center;
    gap: clamp(16px, 2.4vw, 32px);
  }
  html.js .lineup.lineup--compact .lp {
    flex-grow: 0;
    flex-basis: clamp(220px, 26vw, 320px);
    transition: flex-basis .5s var(--ease-out-3);
  }
  html.js .lineup.lineup--compact .lp.is-open {
    flex-basis: calc(clamp(220px, 26vw, 320px) * 1.25);
    box-shadow: 0 14px 32px -12px rgba(0, 0, 0, .4);
  }
}
