/* ==========================================================================
   EC · Product Rail — block styles
   ==========================================================================
   Section-isolated per docs/DESIGN-SYNC rule 3. The SHARED product primitives
   (.product-tile, .product-tile__media/__flag/__body/__name/__price,
   .product-grid, .product-rail, .product-rail--4) are Wave 1 components already
   in pb-shell.css and are NOT redeclared here. This file carries only the
   per-variant pieces the shell doesn't own:
     • the round 62 META CARD — meta row + in-flow swatch strip (from rails.css);
     • the category CHIPS (from home.css §6);
     • the working SLIDER track override + the .rail wrapper & ‹ › arrows (home.css);
     • the v9b B1 FULL-BLEED PEEK rail + its glass arrows, and the R6 DOT PAGER;
     • the UGC/BTS image carousel .ugc-rail + presentational .rail-nav (range.css).
   Enqueued only when the block is present via block.json's file:./style.css.

   TWO CARD BODIES, chosen by the block's `card_style` field, because v9b's three
   usages of this block no longer agree. Round 62 removed the hover-only swatch
   strip from BOTH mockup twins (home.css §6, rails.css) on accessibility grounds:
   a colour you can only reach by hovering is a colour most people never see, and
   on touch there is no hover to reach it with. The strip is gone from this sheet
   and from render.php too — there is no longer a swatch treatment inside
   .product-tile__media anywhere.

   TWO SLIDER WIDTHS, chosen by the block's `rail_style` field, because v9b's B1
   made the Home rail full-bleed while leaving the interior rails capped: --peek /
   .rail--bleed is an OPT-IN layer over the plain --slider 4-up, exactly as the
   mockup writes it.
   ========================================================================== */

/* ==========================================================================
   META CARD (round 62 / BA1) — the Home New Arrivals tile now reads exactly like
   the shop page's range card: a small META ROW (price · fibre · colour count)
   ABOVE the name, then the name, then the colour swatches.
   The swatches are ALWAYS VISIBLE and sit in the tile body, not over the photo:
   a colour you can only reach by hovering is a colour most people never see, and
   on touch there is no hover to reach it with.
   Ported from rails.css (which is itself the rail's translation of shop.css's
   .range-card__meta — same declarations, same 10px of air, no middot separators).
   ========================================================================== */
.product-tile__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;   /* price hard left, colour count flush right */
  column-gap: var(--space-sm);
  row-gap: var(--space-3xs);
  margin-block: 10px;               /* the shop card's 10px of air, above + below */
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  color: var(--text-muted);
}
.product-tile__meta > span { white-space: nowrap; }
/* (0,2,0) and (0,3,0) — LOAD-BEARING. pb-shell.css is enqueued AFTER block sheets,
   so these have to out-rank the shell's own .product-tile__price (0,1,0) and
   .product-tile__price .from (0,2,0) rather than merely follow them. */
.product-tile__meta .product-tile__price { font-size: inherit; color: var(--text); }
.product-tile__meta .product-tile__price .from {
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  font-size: var(--fs-xs);
  color: var(--text-muted);
  margin-right: 3px;
}
/* In-flow swatch strip. The dot is the shop card's 34px, not the old 16px legend.
   Still scoped to the BODY at (0,2,0)/(0,3,0) even though round 62 left it the only
   swatch treatment in the block: pb-shell.css prints AFTER this sheet, so an
   unscoped (0,1,0) copy would lose the moment the shell (or pb-woo.css, which owns
   the shop page's real .swatch-dot BUTTON) grows a rule of its own. */
.product-tile__body .product-tile__swatches {
  --swatch-size: 34px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs);
  margin: var(--space-2xs) 0 0;
  padding: 0;
  list-style: none;
}
.product-tile__body .product-tile__swatches li { display: inline-flex; align-items: center; }
.product-tile__body .product-tile__swatches .swatch-dot {
  display: block;
  flex: 0 0 auto;
  width: var(--swatch-size);
  height: var(--swatch-size);
  border-radius: var(--radius-circle);
  background: var(--sw, var(--sage));
  box-shadow: inset 0 0 0 1px rgba(35, 41, 44, 0.16);
}
/* The narrowest rail column takes the shop card's small dot. */
@media (max-width: 560px) {
  .product-tile__body .product-tile__swatches { --swatch-size: 30px; gap: var(--space-3xs) 6px; }
}

/* ==========================================================================
   SIMPLE CARD — name + chips + price, as the Size & Shape and Range rails still
   print it.
   ========================================================================== */

/* --- Category chips: quiet, hairline text chips under the product name. Not
   filled boxes — an outline + muted caps label. Extracted from home.css.
   v9b round C3 dropped the ROOM label from these cards, so the design is now a
   single fibre chip; the rule still handles more than one. --- */
.product-tile__chips {
  list-style: none;
  margin: 2px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3xs);
}
.product-tile__chips li {
  font-size: var(--fs-xs);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-muted);
  border: var(--rule);
  border-radius: var(--radius-pill);
  padding: 1px var(--space-2xs);
  line-height: 1.5;
}

/* --- SLIDER track: the New Arrivals rail is a WORKING SLIDER at every width,
   not a static 4-up. Six tiles; the scroll-snapped track shows exactly FOUR at
   desktop and overflows, so the ‹ › arrows stay live. Extracted from home.css.

   The doubled `.product-rail.product-rail--slider` is LOAD-BEARING — leave it.
   The shell's own @1024px rule is `.product-rail { grid-auto-columns: minmax(0,1fr);
   overflow: visible }` (not `.product-rail--4`, as this comment used to claim), and
   it lands on this very element. Unprefixed, the modifier ties it at (0,1,0) and
   pb-shell.css prints later, so BOTH declarations lost: the track went back to
   equal columns and — via the `overflow` shorthand beating `overflow-x` — stopped
   scrolling at all. script.js then read scrollWidth === clientWidth, set canScroll
   false and hid both arrows, leaving a squashed static row. --- */
@media (min-width: 1024px) {
  .product-rail.product-rail--slider {
    grid-auto-columns: calc((100% - 3 * var(--space-md)) / 4);
    overflow-x: auto;                 /* keep it a slider, not a static grid */
  }
}
/* scroll-padding MUST be 0 so a snapped tile's start aligns flush to the track's
   own left edge. Applies at ALL widths. (No shell counterpart, so unprefixed.) */
.product-rail--slider { scroll-padding-inline: 0; }
/* Hide the native horizontal scrollbar while keeping the element scrollable
   (wheel / touch / keyboard unaffected). Scoped to this track only. Doubled for
   the same reason as above: the shell sets `scrollbar-width: thin` on
   `.product-rail` and would otherwise win the tie. */
.product-rail.product-rail--slider {
  scrollbar-width: none;                 /* Firefox */
  -ms-overflow-style: none;              /* legacy Edge/IE */
}
.product-rail--slider::-webkit-scrollbar { width: 0; height: 0; display: none; }

/* ==========================================================================
   v9b B1 — FULL-BLEED PEEK RAIL (Home "New Arrivals"; opt-in via .rail--bleed on
   the wrapper + .product-rail--peek on the track, set by the block's `rail_style`
   field). The plain .rail / --slider 4-up above is UNCHANGED, so any capped rail
   keeps it; only the Home rail opts in here, exactly as the mockup scopes it.

   GEOMETRY. render.php moves the .rail--bleed wrapper OUT of .container, so it is
   a direct child of the .section — and neither the section nor <main> carries
   inline padding — which spans it edge to edge with no 100vw breakout (that
   construct overflows by the scrollbar width). The --peek TRACK then:
     • shows ROUGHLY THREE cards with a partial PEEK of the previous/next card at
       both edges, which is what signals scrollability;
     • uses the 10px revision gutter as BOTH the card gap and the outer edge inset,
       so the peek cards sit 10px in from the viewport edge (the 10px motif);
     • divides the viewport by ~3.25 — the .25 is what leaves the peek.
   --peek-cols is the single knob; scroll-padding-inline matches the edge inset so
   an arrow/snap landing seats the card flush to the padded start, never clipped
   under the left peek.

   SPECIFICITY IS LOAD-BEARING — do NOT drop these to the mockup's bare
   `.product-rail--peek`. Block sheets print BEFORE pb-shell.css, and the shell owns
   `.product-rail { grid-auto-columns: minmax(240px,1fr); gap: var(--space-md) }` at
   (0,1,0), so an unprefixed modifier TIES it and the later sheet takes both. The
   doubled `.product-rail.product-rail--peek` lands at (0,2,0) and out-ranks it —
   the same trap, and the same fix, as the --slider track above. That applies to the
   --peek-cols overrides too: they must match the base rule's (0,2,0) or the base
   3.25 wins at every width and the phone rail never widens its cards.
   ========================================================================== */
.product-rail.product-rail--peek {
  --rail-edge: var(--gap);               /* 10px outer inset = the peek offset (S9)  */
  --rail-gap: var(--gap);                /* 10px inter-card gap — 10px motif (S9)    */
  --peek-cols: 3.25;                     /* ~3 full cards + a peek either side       */
  gap: var(--rail-gap);
  padding-inline: var(--rail-edge);
  grid-auto-columns: calc(
    (100vw - 2 * var(--rail-edge) - (var(--peek-cols) - 1) * var(--rail-gap)) / var(--peek-cols)
  );
  scroll-padding-inline: var(--rail-edge);
}
/* Bigger cards overall (brief B1): a squarer media frame than the shell's 4:5, so
   the larger columns read as generous product frames rather than stretched
   thumbnails. Round 21 settled on 1:1 — a quarter shorter than 3:4 — so the rail
   plus its dot pager fit one viewport. (0,2,0) beats the shell's own
   `.product-tile__media { aspect-ratio: 4 / 5 }`. */
.product-rail--peek .product-tile__media { aspect-ratio: 1 / 1; }
/* Everything below the photograph is inset 10px from the card edges and spaced on
   the card's own 8px step (shop.css §5 Round 5, same numbers); the imagery still
   bleeds to the card edge. Scoped to the peek rail so a capped rail's bare tiles
   keep their flush, tighter body. Both beat the shell's (0,1,0) .product-tile /
   .product-tile__body. */
.product-rail--peek .product-tile { gap: var(--space-2xs); }
.product-rail--peek .product-tile__body {
  gap: var(--space-2xs);
  padding-inline: 10px;
}
/* The @1024 quarter-width rule above targets .product-rail.product-rail--slider and
   the Home track carries BOTH modifiers, so restate the peek sizing at the same
   breakpoint and the same (0,2,0): equal specificity, later in source, peek wins.
   overflow-x is restated for the reason the slider block records — the shell's
   @1024 `overflow: visible` SHORTHAND would otherwise stop the track scrolling. */
@media (min-width: 1024px) {
  .product-rail.product-rail--peek {
    grid-auto-columns: calc(
      (100vw - 2 * var(--rail-edge) - (var(--peek-cols) - 1) * var(--rail-gap)) / var(--peek-cols)
    );
    overflow-x: auto;
  }
}
/* Fewer, larger cards as the viewport narrows: a tablet shows ~2.2, a phone ~1.2.
   The peek cue is preserved at every width. */
@media (max-width: 900px) { .product-rail.product-rail--peek { --peek-cols: 2.2; } }
@media (max-width: 560px) { .product-rail.product-rail--peek { --peek-cols: 1.2; } }
/* B1: ~10px more air between the New Arrivals heading block and the carousel than
   the section-head's own margin-bottom gives. Scoped to the section so no other
   bleed rail inherits it. */
.new-arrivals .rail--bleed { margin-top: 10px; }

/* --- Rail wrapper + arrows: the wrapper is a positioning context for the two
   arrow buttons; the track keeps the shell .product-rail behaviour. Arrows are
   real >=44px targets that show at every width the track overflows (script.js
   hides one only when a track can't scroll that way, and disables the one at
   whichever end is reached). A SLEEK thin-stroke chevron in the GUTTER flanking
   the rail (never over a slide): no chip at rest — just the slate glyph — with a
   quiet round backing that fades in on hover/focus only. Extracted from home.css. */
.rail {
  position: relative;
  /* Make the rail a size container so the desktop gutter arrows can be centred on
     the tile IMAGE (not the taller tile incl. its text) using a WIDTH-relative
     length. One column = (100cqw - 3 gaps) / 4; the 4:5 media height = column *
     5/4; its centre = column * 5/8. */
  container-type: inline-size;
  --rail-media-mid: calc(((100cqw - 3 * var(--space-md)) / 4) * 5 / 8);
}
.rail__arrow {
  position: absolute;
  top: calc(50% - var(--tap-min) / 2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  border-radius: var(--radius-circle);
  background: transparent;             /* no chip at rest — sleek chevron only */
  color: var(--text);
  border: 0;
  cursor: pointer;
  transition: background-color var(--dur-base) var(--ease-standard),
              color var(--dur-base) var(--ease-standard),
              transform var(--dur-base) var(--ease-out);
  z-index: 2;
}
.rail__arrow svg { width: 24px; height: 24px; }
/* Subtle backing on hover/focus only — a quiet recessed disc, no border/shadow. */
.rail__arrow:hover,
.rail__arrow:focus-visible { background: var(--bone-deep); color: var(--slate-deep); }
/* Disabled end-stop: reads clearly inactive by muting the glyph (never a chip). */
.rail__arrow:disabled {
  color: var(--text-muted);
  background: transparent;
  cursor: default;
}
/* Mobile-first default position: below the desktop breakpoint the arrows ride
   ABOVE the rail as a small right-aligned control cluster (under the section
   link), nested in the section-head gap, rather than overlapping the tiles. */
.rail__arrow--prev { right: calc(var(--tap-min) + var(--space-2xs)); top: calc(-1 * var(--tap-min)); }
.rail__arrow--next { right: 0; top: calc(-1 * var(--tap-min)); }
.rail__arrow[hidden] { display: none; }

/* WIDE desktop (>=1440px): the arrows move OUT into the flanking gutter,
   vertically centred on the tile images, fully clear of the track. Gated at 1440
   (not 1024) because below the container cap the page gutter alone is thinner
   than the button offset, which would otherwise spill the viewport. */
@media (min-width: 1440px) {
  .rail__arrow { top: calc(var(--rail-media-mid) - var(--tap-min) / 2); }
  .rail__arrow--prev { left: calc(-1 * (var(--tap-min) + var(--space-2xs))); right: auto; }
  .rail__arrow--next { right: calc(-1 * (var(--tap-min) + var(--space-2xs))); left: auto; }
}

/* Narrow (<=640px): the section-head stacks and the section link moves left, so
   the above-rail cluster loses its anchor. The partial-tile scroll already
   signals swipeability, so hide the arrows and let touch/swipe carry the rail.
   Keyboard users still reach every tile by Tab. --- */
@media (max-width: 640px) {
  .rail__arrow { display: none; }
}

/* --- v9b B1: FULL-BLEED rail arrows (scoped to .rail--bleed only, so a capped
   rail's gutter / above-rail arrows above are untouched). On an edge-to-edge peek
   rail there is no flanking gutter to sit in and no capped container, so the arrows
   float IN the peek zones at the viewport edges, seated over the card imagery.
   Because they sit over PHOTOGRAPHY rather than the bone gutter they carry a soft
   translucent glass disc at rest — the same Apple-glass language as the chrome — so
   the white chevron stays legible on any image; hover/focus firms the disc. They
   are vertically centred on the MEDIA (the square frame dominates the tile height;
   the short body sits below), nudged up from the tile centre so the glyph lands on
   the image. Real >=44px targets; script.js still hides/disables them at the ends.
   All (0,2,0)/(0,3,0), so they out-rank the base .rail__arrow rules above whatever
   the source order — including the @1440 gutter placement, whose `left`/`right`
   this deliberately overrides. --- */
.rail--bleed .rail__arrow {
  top: 38%;                              /* seat on the media, above the body        */
  transform: translateY(-50%);
  left: auto; right: auto;
  width: 46px; height: 46px;
  color: var(--white);
  background: rgba(35, 41, 44, 0.32);
  -webkit-backdrop-filter: blur(8px) saturate(1.2);
  backdrop-filter: blur(8px) saturate(1.2);
  box-shadow: 0 2px 12px rgba(35, 41, 44, 0.22);
}
.rail--bleed .rail__arrow--prev { left: var(--gap); }
.rail--bleed .rail__arrow--next { right: var(--gap); }
.rail--bleed .rail__arrow:hover,
.rail--bleed .rail__arrow:focus-visible {
  background: rgba(35, 41, 44, 0.58);
  color: var(--white);
}
.rail--bleed .rail__arrow:disabled {
  color: rgba(255, 255, 255, 0.55);
  background: rgba(35, 41, 44, 0.22);
}
/* Keep the bleed arrows on tablet — the peek rail still overflows there; only truly
   small screens fall back to touch/swipe. Re-asserted against the <=640px hide rule
   above, for the bleed variant only. */
@media (min-width: 561px) and (max-width: 640px) {
  .rail--bleed .rail__arrow { display: inline-flex; }
}
@media (max-width: 560px) {
  .rail--bleed .rail__arrow { display: none; }
}

/* --- v9b R6: rail DOT PAGER. The arrows are easy to miss on a bleed rail, so a
   clickable dot pager rides under it, styled to match the Designers Edit dots
   exactly (44px targets, small woodland-sage pips) for one carousel language across
   the site. Renders only where render.php prints a [data-rail-dots] container —
   the bleed rail — and script.js builds one dot per tile, keeps the active dot in
   sync with the tile nearest the track's left edge, scrolls that tile flush on
   click, and hides the whole pager when the rail cannot scroll. --- */
.rail__dots {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--space-3xs);
  margin-top: var(--space-md);
}
.rail__dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  border: 0;
  background: transparent;
  cursor: pointer;
}
.rail__dot::before {
  content: "";
  width: 8px; height: 8px;
  border-radius: var(--radius-circle);
  border: 1px solid var(--woodland-sage-deep);
  background: transparent;
  transition: background-color var(--dur-base) var(--ease-standard),
              transform var(--dur-base) var(--ease-out);
}
.rail__dot[aria-current="true"]::before { background: var(--woodland-sage-deep); transform: scale(1.15); }
.rail__dot:hover::before { background: var(--woodland-sage); }
/* Hidden when the rail can't scroll (nothing to page through). script.js sets this. */
.rail__dots[hidden] { display: none; }

/* ==========================================================================
   UGC / BTS image carousel (Range) — a 3-tile scroll-snap rail with
   presentational ‹ › arrows on the head. Image-led, generous; snaps
   horizontally when it overflows. Extracted from range.css.
   ========================================================================== */
.ugc-rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: var(--space-sm);
}
.ugc-rail__cell { margin: 0; }
.ugc-rail__cell .ph { aspect-ratio: 4 / 3; border-radius: var(--radius-media); }  /* v4: soft rounded UGC tile */
/* Real-photography drop-in, scoped to this rail. The theme ships no global
   `.ph > img` cover rule — each block carries its own copy per section isolation,
   as pb_ec_entry_tiles and pb_ec_category_grid do — and this block never had one,
   so the shell's `.ph { display: grid; place-items: center }` was centring each
   UGC photo at its intrinsic size and clipping it instead of covering the tile.
   The slider/grid tiles were never affected: the shell owns
   `.product-tile__media img { object-fit: cover }` for those. */
.ugc-rail__cell .ph > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
@media (max-width: 720px) {
  .ugc-rail {
    grid-auto-columns: 78%;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: var(--space-2xs);
  }
  .ugc-rail::-webkit-scrollbar { display: none; }
  .ugc-rail__cell { scroll-snap-align: start; }
}

/* --- RAIL NAV — quiet presentational ‹ › arrow pair on the UGC/BTS section head
   (aria-hidden). Hairline circular buttons. Extracted from range.css. --- */
.rail-nav { display: flex; gap: var(--space-2xs); }
.rail-nav__btn {
  display: grid; place-items: center;
  width: 40px; height: 40px;
  color: var(--text-muted);
  border: var(--rule-strong);
  border-radius: var(--radius-circle);
  transition: color var(--dur-fast) var(--ease-standard), border-color var(--dur-fast);
}
.rail-nav__btn:hover { color: var(--text); border-color: var(--slate); }
