/* ============================================================================
   DAS STORE — the third instance of the `rp` store system
   ----------------------------------------------------------------------------
   Instance 1  shop.griffain.io       repo griffain-merch,  app/rp/*
   Instance 2  Off Duty rewards shop  repo odndr-web,       app/store/rp/*
   Instance 3  this                   das/web,              static HTML

   The measured token sheet both existing stores run (represent-tokens.css —
   computed styles read off a live DOM at 1280px) is carried across verbatim:
   nav 46/63 · CTA 52 · buy column 472 · radius 0 · body 16/24 · UI 12/18 at
   0.133333px tracking · micro 10/10 · chips 10/15 · header grid [1fr auto 1fr].

   TWO DELIBERATE DIFFERENCES, both Jayden's 2026-09-21 brief:

   1. THE FRAME IS 5:4 LANDSCAPE, NOT 4:5 PORTRAIT.
      "i dont like the white border at all". The other two stores use a 0.806
      portrait frame because they are shot as 4:5 apparel. DAS photography is
      LANDSCAPE — measured across 51 files: 15x 1.25, 10x 1.5, 10x square,
      8x 1.333, 2x 1.778 and only 4x 0.806. A portrait frame is what produced
      the bars. Every photo is now normalised to 1400x1120 by
      scripts/build-store-images.mjs and the frame fills with `cover`, so
      nothing letterboxes anywhere.

   2. NAVY. "add the navy colors in there thats on the signing page to keep our
      aesthetic". The ground stays white — that is what makes it the same store
      as the other two — and DAS navy carries every CTA, the hero slash, the
      PDP rails and the footer. Family per BRAND-KIT.md:
      #060E24 · #0C1840 · #16264F · #1A2E6E · #2E4FA8 · #3A5FC0 · #4E8BE8 · #9CC4F5
      (the sign-in page's literal #0E1B2E is Off Duty's blue — it was pulled
      from DAS once already this program as off-brand. One token to change
      here if that specific hex is wanted.)

   TYPEFACE: the other two run STKBureau and both carry an open gate to license
   it. This is a client's commercial storefront, so it runs DAS's own licensed
   Chivo at the same sizes and the same 0.133333px tracking. Swap --st-font and
   every metric holds.

   ⚠ COLOUR LANDMINE: this codebase's vars are INVERTED (--black is #FFFFFF,
   --gold is #1A2E6E navy). Nothing below uses them; every value is explicit.
   ========================================================================== */

:root{
  --st-font:'Chivo','Helvetica Neue',Helvetica,Arial,sans-serif;
  --st-serif:'Instrument Serif',Georgia,serif;

  --st-ink:#000;
  --st-muted:rgb(115,115,115);
  --st-chip-off:rgb(156,163,175);
  --st-sale:#ae0200;
  --st-white:#fff;
  --st-hair:rgba(0,0,0,.10);
  --st-hair-soft:rgba(0,0,0,.07);
  --st-ph:#F4F5F8;

  /* DAS navy family — BRAND-KIT.md */
  --st-navy-900:#060E24;
  --st-navy-800:#0C1840;
  --st-navy-700:#16264F;
  --st-navy:#1A2E6E;
  --st-navy-500:#2E4FA8;
  --st-navy-400:#3A5FC0;
  --st-navy-300:#4E8BE8;
  --st-navy-200:#9CC4F5;

  --st-body:16px;  --st-body-lh:24px;
  --st-ui:12px;    --st-ui-lh:18px;  --st-ui-ls:0.133333px;
  --st-micro:10px; --st-micro-lh:10px;
  --st-chip:10px;  --st-chip-lh:15px;

  --st-nav-h:80px;    /* sized to the mark; see .st-hd .mark img */
  --st-hd-search:53px;              /* the search row + its hairline */
  --st-hd-h:calc(var(--st-nav-h) + var(--st-hd-search));
  --st-cta-h:52px;
  --st-buycol:472px;
  --st-radius:0px;
  /* THE CARD FRAME — 4:5 PORTRAIT, one ratio everywhere.
     It was 5:4 landscape because a straight cover-crop into portrait destroyed
     DAS's landscape photography. The composed derivatives removed that
     constraint: a 4:5 canvas is now FILLED by the photograph's own blurred
     extension with the product whole inside it, so portrait costs nothing.
     The reference's cards are 0.75 portrait and its PDP frame matches them —
     having the grid at 1.25 and the product page at 0.8 was the kind of
     inconsistency you only notice by looking at the two pages side by side. */
  --st-frame:4 / 5;
  --st-coll-frame:3 / 2;   /* banners, not products — see .st-coll */
}
@media(max-width:1023px){ :root{ --st-nav-h:72px; } }
@media(max-width:767px){ :root{ --st-nav-h:72px; } }

/* ── reset, scoped so the rest of the site is untouched ─────────────────── */
.st, .st *, .st *::before, .st *::after{ box-sizing:border-box; border-radius:var(--st-radius); }
.st{
  font-family:var(--st-font); color:var(--st-ink); background:var(--st-white);
  font-size:var(--st-body); line-height:var(--st-body-lh);
  -webkit-font-smoothing:antialiased;
  /* The store pages do not load styles.css, so the UA's default body margin:8px
     was never reset — measured 2026-09-23 while matching the PDP to the
     reference: every store page sat 8px in from the viewport and 16px narrower
     than it should be, which is also why the 472px buy column would not centre
     in its half (224px one side, 254px the other). Full-bleed is the whole
     point of this layout. */
  margin:0;
}
.st img{ display:block; max-width:100%; }
.st a{ color:inherit; text-decoration:none; }
.st button{ font:inherit; color:inherit; background:none; border:0; cursor:pointer; }
.st ul{ list-style:none; margin:0; padding:0; }
.st h1,.st h2,.st h3,.st h4{ font-weight:500; margin:0; }
.st p{ margin:0; }
.st-ui{ font-size:var(--st-ui); line-height:var(--st-ui-lh); letter-spacing:var(--st-ui-ls); text-transform:uppercase; }
.st-micro{ font-size:var(--st-micro); line-height:var(--st-micro-lh); letter-spacing:var(--st-ui-ls); text-transform:uppercase; }

/* ── HEADER ──────────────────────────────────────────────────────────────
   Their 3-column grid. The center mark is ours; the right rail carries DAS's
   own actions (Saved / Bag) in place of the reference's country selector. */
.st-hd{
  position:sticky; top:0; z-index:40; width:100%; background:#fff;
  border-bottom:1px solid var(--st-hair); white-space:nowrap;
}
.st-hd .bar{ display:grid; grid-template-columns:1fr auto 1fr; gap:4px; align-items:center; padding:0 24px; height:var(--st-nav-h); }
.st-hd nav{ display:flex; align-items:center; height:100%; }
.st-hd .item{ position:relative; display:flex; align-items:center; justify-content:center; height:100%; padding:12px; user-select:none; }
/* their underline: 44 x 1, centred, transparent until hover */
.st-hd .item::after{
  content:""; position:absolute; bottom:0; left:50%; transform:translateX(-50%);
  height:1px; width:44px; background:transparent; transition:background-color .3s linear;
}
.st-hd .item:hover::after,.st-hd .item[aria-current]::after{ background:currentColor; }
/* THE MARK. Jayden 2026-09-23: "the logo in the top is just way to small."
   It was 22px, which on a 728x259 lockup (ratio 2.81) renders only 62px wide —
   the reference stores set a pure WORDMARK at that height, and a wordmark at
   22px is a confident 200px wide. This lockup is nearly three times shorter, so
   the same number reads as a thumbnail. Sized against the bar instead: 32 of
   46px desktop, 38 of 63px mobile, which keeps 7px of air top and bottom.

   Then 3x (96px) on request, and then "a little bit smaller, actually the
   correct size — you're the artist."

   THE CALL: 56px, rendering 157x56. The reasoning, since it is a judgment and
   not a measurement. 32px was a thumbnail. 96px was a billboard: it forced a
   112px sticky bar, which costs 11% of a 1000px viewport on every scroll and
   made the header shout over the product photography the whole page is built
   to show. This mark is a STACKED lockup — an icon beside three lines of type —
   so its legibility floor is set by those three lines, not by the whole block.
   At 56px each line lands around 10px, which is the same optical size as the
   12px nav beside it. That is the correct size: the mark reads as confidently
   as the navigation and no louder, and the bar settles at 80px with 12px of air
   — tall enough to feel considered, short enough to stay out of the way. */
/* The lockup is 728x259, so at 56px tall it wants 157px wide -- but a global
   img{max-width:100%} capped it at whatever the grid column happened to be and
   the fixed height held, which squeezes the artwork horizontally. That is the
   literal reason it read as "scrunched" on a phone: not crowded, DISTORTED.
   max-width:none lets the aspect ratio win; line-height:0 stops the whitespace
   either side of the <img> from adding two line boxes to the anchor's height,
   which was making a 64px mark occupy 107px of a 72px bar. */
/* A flex box with an explicit height, not a block that inherits one. As a
   block the anchor came out 112px tall around a 60px image and, being centred
   in a 72px bar, hung 20px above it -- the mark was clipped along its top edge
   and the anchor's white ground overlapped the search row beneath. A flex row
   with height:100% cannot do either. */
.st-hd .mark{ display:flex; align-items:center; justify-content:center;
  height:100%; line-height:0; justify-self:center; }
.st-hd .mark img{ height:56px; width:auto; max-width:none; display:block; }
.st-hd .right{ display:flex; align-items:center; justify-content:flex-end; height:100%; gap:2px; }

/* ── ICONS, NOT CAPTIONS ────────────────────────────────────────────────
   "BAG 0" and "SAVED 0" as words cost ~150px of a 375px bar, which is what
   crushed the mark between them. A glyph says the same thing in 34. */
.st-hd .item.ico{ width:38px; padding:0; }
.st-hd .item.ico .gl{ display:block; }
.st-hd .item.ico::after{ display:none; }
.st-hd .item.ico .count{
  position:absolute; top:calc(50% - 15px); right:2px; margin:0; vertical-align:baseline;
  font-size:10px; line-height:1; font-weight:700; color:var(--st-navy);
}
.st-hd .item.ico .count:not([data-has]){ color:var(--st-muted); font-weight:500; }
.st-hd .count{ font-size:var(--st-micro); line-height:var(--st-micro-lh); vertical-align:super; margin-left:3px; color:var(--st-navy); }
.st-hd .home{ gap:5px; }
.st-hd .home .gl{ flex:0 0 auto; }
@media(max-width:1023px){ .st-hd .hide{ display:none; } }

/* ── THE SEARCH ROW ─────────────────────────────────────────────────────
   Part of the sticky header on every store page. Slim on purpose: it is a
   doorway, not a section. */
.st-hd .hdsearch{ border-top:1px solid var(--st-hair); padding:0 24px;
  height:var(--st-hd-search); display:flex; align-items:center; }
.st-hd .hdsearch .st-search{ max-width:620px; margin:0 auto; }

/* ── MOBILE: GIVE THE MARK ROOM ─────────────────────────────────────────
   Jayden: "the logo on the mobile page is very scrunched. Make it full size
   and let it breathe." It was sharing a 375px bar with four text links, so the
   1fr/auto/1fr grid gave the centre column whatever the words left over --
   about 90px for a lockup that needs 180. The words became glyphs, Home became
   a chevron, and the mark got the middle of the bar back. */
@media(max-width:767px){
  /* Fixed side columns: 56 for the back chevron, 88 for two glyphs. The mark
     then owns a known 199px and sits in the middle of the bar rather than in
     the middle of whatever the links left behind. */
  .st-hd .bar{ grid-template-columns:88px 1fr 88px; padding:0 12px; height:72px; gap:0; }
  .st-hd .mark img{ height:60px; }
  .st-hd .item{ padding:10px 8px; }
  .st-hd .home{ padding-left:0; }
  .st-hd .home .lbl{ display:none; }
  .st-hd .hdsearch{ padding:0 14px; }
}
@media(max-width:480px){
  .st-hd .shopall{ display:none; }
}

/* ── CTA — 52px, square, navy ──────────────────────────────────────────
   Every rule here is prefixed .st DELIBERATELY. The reset .st a{color:inherit}
   is specificity 0-1-1 (class + element) and beats a bare .st-cta--light at
   0-1-0, so the CTAs were inheriting their parent color instead of their own —
   white text on a white button over the navy hero. It looked correct everywhere
   else only because the inherited color happened to be dark. */
.st .st-cta{
  display:inline-flex; align-items:center; justify-content:center;
  height:var(--st-cta-h); padding:0 32px;
  background:var(--st-navy); color:#fff;
  font-size:var(--st-ui); line-height:var(--st-ui-lh); letter-spacing:var(--st-ui-ls);
  text-transform:uppercase; font-weight:500; transition:background-color .18s;
}
.st .st-cta:hover{ background:var(--st-navy-800); }
.st .st-cta[disabled]{ opacity:.45; cursor:default; }
.st .st-cta--ghost{ background:transparent; color:var(--st-navy); box-shadow:inset 0 0 0 1px var(--st-navy); }
.st .st-cta--ghost:hover{ background:var(--st-navy); color:#fff; }
.st .st-cta--light{ background:#fff; color:var(--st-navy); }
.st .st-cta--light:hover{ background:var(--st-navy-200); color:var(--st-navy-900); }
.st-cta--block{ width:100%; }

/* ── HERO — the navy slash, DAS's own device ───────────────────────────── */
.st-hero{ position:relative; overflow:hidden; background:var(--st-navy-900); color:#fff; }
.st-hero .shot{ position:absolute; inset:0; }
/* SHOW THE PHOTOGRAPH. Jayden 2026-09-25: "can u get rid of this strip and
   just show the photo."
   Two things were hiding it. The .slash was a navy wedge clipped diagonally
   across the frame at 94% opacity, and the photograph underneath was ALSO
   held at 50% opacity — so the hero was mostly gradient with a ghost of an
   image behind it. Both are gone and the picture runs at full strength.
   What replaces them is a scrim, not a panel: a left-weighted wash that is
   opaque enough to carry white type where the type actually sits and fades to
   nothing across the rest of the frame, so the road and the forest read. Same
   approach as the collection banners, and measured the same way — see the
   numbers in PHOTO-ART-DIRECTION.md. */
.st-hero .shot img{ width:100%; height:100%; object-fit:cover; }
.st-hero .slash{
  position:absolute; inset:0;
  background:
    linear-gradient(100deg, rgba(6,14,36,.92) 0%, rgba(6,14,36,.82) 26%,
      rgba(8,18,44,.56) 48%, rgba(8,18,44,.22) 68%, rgba(8,18,44,0) 86%),
    linear-gradient(180deg, rgba(6,14,36,.42) 0%, rgba(6,14,36,0) 34%,
      rgba(6,14,36,0) 66%, rgba(6,14,36,.46) 100%);
}
.st-hero .guides{ position:absolute; inset:0; pointer-events:none; }
.st-hero .guides span{ position:absolute; top:0; bottom:0; border-left:1px dashed rgba(255,255,255,.12); }
.st-hero .in{ position:relative; z-index:2; padding:clamp(72px,11vw,132px) 24px clamp(40px,6vw,58px); }
.st-hero .corner{ display:flex; justify-content:space-between; gap:16px; flex-wrap:wrap; color:rgba(255,255,255,.62); margin-bottom:24px; }
.st-hero h1{
  font-size:clamp(30px,6.4vw,76px); line-height:.94; letter-spacing:-.02em;
  text-transform:uppercase; margin-bottom:16px; text-wrap:balance; max-width:18ch;
}
.st-hero h1 em{ font-style:normal; color:var(--st-navy-200); }
.st-hero .stand{ font-size:14px; line-height:22px; color:rgba(255,255,255,.78); max-width:52ch; margin-bottom:24px; }
.st-hero .ctas{ display:flex; gap:8px; flex-wrap:wrap; }

/* ── COLLECTION TILES — label on the photograph ────────────────────────── */
.st-coll{ display:grid; grid-template-columns:repeat(3,1fr); gap:1px; background:var(--st-hair); }
/* COLLECTION TILES ARE NOT PRODUCT CARDS.
   They were on var(--st-frame), so when that token went 4:5 portrait for the
   product cards these inherited it: measured 628x785 each — 78% of the screen
   height per tile, a 1570px section for six navigational banners. They also
   render the LANDSCAPE cover derivative (1.25), so a portrait frame was wrong
   twice over. Their own token now, and 3:2 because these are banners to scan,
   not products to study. */
.st-coll a{ position:relative; display:block; aspect-ratio:var(--st-coll-frame); overflow:hidden; background:var(--st-ph); }
.st-coll img{ width:100%; height:100%; object-fit:cover; transition:transform .7s cubic-bezier(.2,.8,.2,1); }
.st-coll a:hover img{ transform:scale(1.035); }
.st-coll .lab{ position:absolute; left:0; right:0; bottom:0; padding:18px; color:#fff;
  background:linear-gradient(180deg,transparent,rgba(6,14,36,.82)); }
.st-coll .lab b{ display:block; font-size:clamp(14px,1.5vw,19px); line-height:1.1; text-transform:uppercase; font-weight:500; }
.st-coll .lab span{ display:block; margin-top:4px; color:rgba(255,255,255,.7); }
@media(max-width:820px){ .st-coll{ grid-template-columns:repeat(2,1fr); } }
@media(max-width:520px){ .st-coll{ grid-template-columns:1fr; } }

/* ── SECTION + FILTER ROW ───────────────────────────────────────────────── */
.st-sec{ padding:clamp(36px,5vw,56px) 24px 0; }
.st-sec .head{ display:flex; align-items:baseline; gap:10px; margin-bottom:16px; }
.st-sec .head sup{ font-size:var(--st-micro); color:var(--st-muted); }
.st-sec .head .r{ margin-left:auto; display:flex; gap:14px; color:var(--st-muted); }
.st-sec .head .r button:hover,.st-sec .head .r button[aria-pressed="true"]{ color:var(--st-navy); }
/* ── THE FILTER RAIL ────────────────────────────────────────────────────
   On a phone these wrapped into a 330px vertical stack -- 40% of the screen
   spent on a control, before a single product. Seven chips on one scrolling
   line is the same control in 42px. It keeps flex-wrap on desktop, where
   there is width to wrap into. */
.st-chips{ display:flex; flex-wrap:wrap; gap:6px; margin-bottom:20px; }
@media(max-width:767px){
  .st-chips{
    flex-wrap:nowrap; overflow-x:auto; scroll-snap-type:x proximity;
    margin:0 -20px 16px; padding:0 20px 8px; scrollbar-width:none;
  }
  .st-chips::-webkit-scrollbar{ display:none; }
  .st-chips button{ flex:0 0 auto; scroll-snap-align:start; padding:8px 12px; }
}
/* A COLLECTION PAGE IS ALREADY FILTERED. Jayden: "why are they scrolling
   through filters when they click the Safe Miles program and on the Safe Miles
   program page?" -- because the page reused the shop's own chip rail. It has a
   breadcrumb back to Shop all; it does not need a category switcher above the
   collection it is showing.

   The body flag is st-cpage, NOT st-coll: .st-coll is already the class on the
   collection-tile grid, and `.st-coll a` there sets display:block, a 3/2
   aspect-ratio and overflow:hidden. Putting st-coll on <body> applied all of
   that to EVERY anchor on the page -- the header mark became a 108x72 clipped
   box, and every breadcrumb and product link grew a grey tile behind it. */
.st-cpage #st-chips{ display:none; }
.st-chips button{ box-shadow:inset 0 0 0 1px var(--st-hair); padding:9px 14px; transition:box-shadow .15s,background-color .15s; }
.st-chips button:hover{ box-shadow:inset 0 0 0 1px var(--st-navy); }
.st-chips button[aria-pressed="true"]{ background:var(--st-navy); color:#fff; box-shadow:inset 0 0 0 1px var(--st-navy); }

/* ── PRODUCT CARD ────────────────────────────────────────────────────────
   Rebuilt 2026-09-22 to match the merch store's card 1:1 (Jayden: "the preview
   of the product not designed 1-1 ... needs to look like griffain.io on mobile").

   What was wrong with the first pass, measured against
   odndr-web/app/store/rp/ProductCard.tsx:

     · MY CARD HAD A BORDER AND 14px OF PADDING. Theirs has neither — the card
       is a bare flex column, the photograph runs full-bleed to its edges, and
       only the text beneath carries a small side inset. The hairline grid I
       drew is not in the reference at all.
     · MY FOOTER STACKED EVERYTHING. Theirs is `flex-col` on mobile and
       `lg:flex-row lg:justify-between` on desktop — title and category on the
       left, price pushed to the right edge on one line.
     · MY "+" WAS A BORDERED 34px BOX. Theirs is a bare 12x12 plus glyph with
       p-10px, no border, no fill, sitting on the photograph.
     · MY QUANTITY GRID WAS A 4-COLUMN BLOCK. Theirs is a full-width bar across
       the bottom of the image on a translucent light ground, with the chips in
       a horizontally scrolling row and a close control.

   Kept from my version deliberately: the 5:4 frame and `cover`. Theirs is
   0.806 portrait with `contain`, which works because their catalogue is shot
   4:5 — ours is landscape, and contain in a portrait frame is exactly the
   white border he asked to remove.
   ────────────────────────────────────────────────────────────────────────── */
.st-grid{ display:grid; grid-template-columns:repeat(4,1fr); gap:0 2px; }
/* MOBILE IS FULL-BLEED. The section carries 24px of side padding, which on a
   375px phone left the two cards 163px wide with white gutters down both
   sides and between them — Jayden: "i dont like this white space ... it looks
   way too small and too blocky". Pulling the grid out to the viewport edge
   gives 187px cards, 15% larger, and removes the gutters entirely. The text
   under each card keeps its own inset so it still lines up with the section. */
@media(max-width:640px){
  .st-sec > .st-grid, .st-grid{ margin-inline:-24px; width:calc(100% + 48px); gap:0 1px; }
  .st-card .foot{ padding-left:12px; padding-right:12px; }
  /* A BLEED IS ONLY A BLEED IF THERE IS PADDING TO BLEED INTO. The shop's
     sections carry 36px 24px, so -24px lands the grid exactly on the viewport
     edge. The product page's rows carry 40px 0 -- no side padding at all --
     so the same rule pushed the grid 24px past both edges and the PDP scrolled
     sideways on every phone (375 viewport, 399 of content). */
  .pd-row > .st-grid, .pd-pane > .st-grid{ margin-inline:0; width:100%; }
}
.st-grid[data-view="2"]{ grid-template-columns:repeat(2,1fr); }
.st-grid[data-view="5"]{ grid-template-columns:repeat(5,1fr); }
/* `hidden` must actually hide. The UA sheet says [hidden]{display:none} at the
   lowest possible specificity, so ANY class rule that sets display beats it —
   .st-grid{display:grid} did exactly that, and the five "hidden" cards behind
   Load more were on screen the whole time. Measured: 10 visible before the
   click and 10 after, which is what gave it away. */
.st-grid[hidden], .pd-pane[hidden]{ display:none; }
@media(max-width:1279px){ .st-grid[data-view="5"]{ grid-template-columns:repeat(3,1fr); } }
@media(max-width:1023px){ .st-grid[data-view="5"]{ grid-template-columns:repeat(2,1fr); } }
.st-grid[data-view="3"]{ grid-template-columns:repeat(3,1fr); }
@media(max-width:1023px){ .st-grid,.st-grid[data-view="3"],.st-grid[data-view="4"]{ grid-template-columns:repeat(2,1fr); } }

.st-card{ display:flex; flex-direction:column; width:100%; position:relative; margin-bottom:28px; }
.st-card .shot{ position:relative; overflow:hidden; }
.st-card .frame{ display:block; position:relative; aspect-ratio:var(--st-frame); background:var(--st-ph); overflow:hidden; }
.st-card .frame img{ width:100%; height:100%; object-fit:cover; transition:transform .5s cubic-bezier(.2,.8,.2,1); }
.st-card:hover .frame img{ transform:scale(1.03); }

/* their badge: 10px/16px, 15px in from the top-left of the photograph */
.st-card .badge{
  position:absolute; top:15px; left:15px; z-index:10;
  font-size:10px; line-height:16px; letter-spacing:var(--st-ui-ls); text-transform:capitalize;
  background:rgba(255,255,255,.94); color:var(--st-navy); padding:2px 8px;
}
.st-card .fav{
  position:absolute; top:10px; right:10px; z-index:12; width:30px; height:30px;
  display:grid; place-items:center; color:var(--st-navy);
  background:rgba(255,255,255,.9); opacity:0; transition:opacity .18s;
}
.st-card:hover .fav,.st-card .fav.fav-active,.st-card .fav:focus-visible{ opacity:1; }
.st-card .fav.fav-active svg{ fill:currentColor; }
@media(hover:none){ .st-card .fav{ opacity:1; } }

/* their "+": a bare glyph on the photograph, bottom-right. No box, no border. */
.st-card .plus{
  position:absolute; bottom:0; right:0; z-index:20;
  padding:10px; color:var(--st-ink); line-height:0;
}
@media(min-width:1024px){ .st-card .plus{ padding:15px 13px; } }
.st-card .plus:hover{ opacity:.7; }

/* their variant bar: full width across the bottom of the image, translucent
   light ground, chips in a horizontal scroller, close control on the right */
.st-card .qtys{
  position:absolute; left:0; right:0; bottom:0; z-index:20;
  display:flex; flex-direction:row-reverse; justify-content:center; align-items:center;
  padding:12px; background:rgba(244,244,245,.9);
  opacity:0; pointer-events:none; transition:opacity .3s ease;
}
.st-card[data-open="true"] .qtys{ opacity:1; pointer-events:auto; }
.st-card .qtys .close{ padding:16px; margin-right:-12px; color:var(--st-muted); line-height:0; }
.st-card .qtys .row{ display:flex; gap:2px; overflow-x:auto; padding:1px; scrollbar-width:none; }
.st-card .qtys .row::-webkit-scrollbar{ display:none; }
.st-card .qtys button.q{
  flex:none; width:40px; height:40px; display:flex; align-items:center; justify-content:center;
  outline:1px solid #CACACA; outline-offset:-1px; background:transparent;
  font-size:10px; line-height:15px; color:var(--st-ink); user-select:none;
}
.st-card .qtys button.q:hover{ background:var(--st-ink); color:#fff; }

/* their footer: stacked on mobile, title-left / price-right on desktop */
.st-card .foot{
  display:flex; flex-direction:column; gap:4px;
  padding:16px 10px 0;
  font-size:var(--st-ui); line-height:var(--st-ui-lh); letter-spacing:var(--st-ui-ls);
}
@media(min-width:1024px){
  .st-card .foot{ flex-direction:row; justify-content:space-between; gap:16px; padding:16px 14px 0; }
}
.st-card .foot .grp{ display:flex; flex-direction:column; gap:4px; min-width:0; }
.st-card .foot .t{ font-weight:500; color:var(--st-ink); }
.st-card .foot .t:hover{ text-decoration:underline; text-underline-offset:3px; }
.st-card .foot .c{ color:var(--st-muted); font-weight:500; text-transform:capitalize; }
.st-card .foot .p{ font-weight:400; text-transform:uppercase; white-space:nowrap; }
.st-card .foot .p .gate{ color:var(--st-navy); }

/* ── PDP — sticky gallery + 472px buy column ───────────────────────────── */
.st-pdp{ display:grid; grid-template-columns:minmax(0,1fr) var(--st-buycol); align-items:start; }
@media(max-width:1023px){ .st-pdp{ grid-template-columns:minmax(0,1fr); } }
.st-pdp .gal{ position:sticky; top:var(--st-hd-h); }
@media(max-width:1023px){ .st-pdp .gal{ position:static; } }
.st-pdp .gal .main{ position:relative; aspect-ratio:var(--st-frame); background:var(--st-ph); overflow:hidden; }
.st-pdp .gal .main img{ width:100%; height:100%; object-fit:cover; }
.st-pdp .gal .n{ position:absolute; right:14px; bottom:14px; background:rgba(255,255,255,.92); padding:4px 9px; }
.st-pdp .gal .rail{ display:grid; grid-auto-flow:column; grid-auto-columns:96px; gap:6px; padding:6px; overflow-x:auto; }
.st-pdp .gal .rail button{ aspect-ratio:var(--st-frame); background:var(--st-ph); overflow:hidden; box-shadow:inset 0 0 0 1px transparent; }
.st-pdp .gal .rail button img{ width:100%; height:100%; object-fit:cover; }
.st-pdp .gal .rail button[aria-pressed="true"]{ box-shadow:inset 0 0 0 2px var(--st-navy); }
.st-pdp .buy{ padding:clamp(24px,3vw,40px); border-left:1px solid var(--st-hair); min-height:100%; }
@media(max-width:1023px){ .st-pdp .buy{ border-left:0; border-top:1px solid var(--st-hair); } }
.st-pdp .buy .cat{ color:var(--st-muted); margin-bottom:8px; }
.st-pdp .buy h1{ font-size:22px; line-height:28px; letter-spacing:-.01em; text-transform:uppercase; margin-bottom:8px; }
.st-pdp .buy .price{ font-size:var(--st-ui); letter-spacing:var(--st-ui-ls); margin-bottom:20px; }
.st-pdp .buy .lbl{ display:flex; align-items:baseline; justify-content:space-between; margin:22px 0 8px; }
.st-pdp .buy .lbl a{ color:var(--st-muted); text-decoration:underline; text-underline-offset:3px; }
/* 7-column quantity selector, their sizeSelector geometry */
.st-pdp .qty{ display:grid; grid-template-columns:repeat(4,1fr); gap:4px; }
.st-pdp .qty button{ height:44px; box-shadow:inset 0 0 0 1px var(--st-hair);
  font-size:var(--st-chip); line-height:var(--st-chip-lh); letter-spacing:var(--st-ui-ls); text-transform:uppercase; }
.st-pdp .qty button:hover{ box-shadow:inset 0 0 0 1px var(--st-navy); }
.st-pdp .qty button[aria-pressed="true"]{ background:var(--st-navy); color:#fff; box-shadow:none; }
.st-pdp .usp{ margin-top:22px; border-top:1px solid var(--st-hair-soft); }
.st-pdp .usp div{ display:flex; gap:10px; align-items:center; padding:11px 0; border-bottom:1px solid var(--st-hair-soft); color:var(--st-muted); }
.st-pdp .usp svg{ flex:none; color:var(--st-navy); }
.st-pdp details{ border-bottom:1px solid var(--st-hair-soft); }
.st-pdp summary{ display:flex; justify-content:space-between; align-items:center; padding:15px 0; cursor:pointer; list-style:none; }
.st-pdp summary::-webkit-details-marker{ display:none; }
.st-pdp summary::after{ content:"+"; font-size:15px; color:var(--st-muted); }
.st-pdp details[open] summary::after{ content:"\2212"; }
.st-pdp .bd{ padding-bottom:16px; font-size:13px; line-height:21px; color:var(--st-muted); text-transform:none; letter-spacing:0; }
.st-pdp .bd ul{ padding-left:0; }
.st-pdp .bd li{ position:relative; padding-left:16px; margin-bottom:5px; }
.st-pdp .bd li::before{ content:""; position:absolute; left:0; top:9px; width:5px; height:1px; background:var(--st-navy); }

/* ── REQUEST PRICING — the gated path ───────────────────────────────────
   DAS gates anything over $110 (js/pricing-gate.js). On a gated product the
   buy column shows this instead of a price and an Add button, so the page
   never advertises a number the visitor is not cleared to see. */
/* REQUEST PRICING — the reference's buy block, not a panel.
   Jayden 2026-09-23: "the request pricing thing needs to look identical to the
   griffain pdp". It was a filled navy card with its own padding sitting inside
   the buy column — a box within a box. The reference has no such object: its
   whole column is bare, a 12px bold label, then the control, then a full-width
   52px button flush to the column edges, with hairline rules doing the
   separating. Measured off shop.griffain.io:
       label     12px bold, sentence case, 18px below the block above
       note      10px, muted, 12px under the label
       button    100% x 52px, uppercase 12px at 0.133333px, my-4
       second    52px ghost with a 1px border, mb-3
   So the panel is gone and the parts sit in the column flow like theirs. */
/* the placeholder-photography note — quiet, but not hidden */
.pd-note--ph{ margin:14px 0 0; padding:10px 12px; background:#f7f7f7;
  color:var(--st-muted); text-transform:none; letter-spacing:0;
  font-size:var(--st-ui); line-height:17px; }

.st-req{ margin:18px 0 0; }
.st-req b{ display:block; font-size:12px; line-height:18px; letter-spacing:var(--st-ui-ls);
  font-weight:700; text-transform:none; color:var(--st-ink); margin-bottom:6px; }
.st-req p{ font-size:10px; line-height:16px; color:var(--st-muted);
  text-transform:none; letter-spacing:0; margin-bottom:16px; }
.st-req .st-cta{ width:100%; }
/* the hairline that replaces the panel's edge */
.st-req::before{ content:""; display:block; height:1px; background:var(--st-hair); margin-bottom:18px; }

/* ── THE INDEX (option D) ────────────────────────────────────────────────
   Type leads, one photograph follows the cursor. Jayden picked this from
   /store-lab. The photo panel is sized to the list rather than given an
   arbitrary min-height, so the two columns end level instead of one dangling. */
.st-index{ display:grid; grid-template-columns:1fr 1fr; align-items:stretch; }
.st-index .ix-list{ padding:4px clamp(20px,3vw,44px) 4px 24px; display:flex; flex-direction:column; justify-content:center; }
.st-index .ix-row{ display:grid; grid-template-columns:34px 1fr auto; align-items:baseline; gap:14px;
  padding:clamp(14px,1.6vw,22px) 0; border-bottom:1px solid var(--st-hair); }
.st-index .ix-row:last-child{ border-bottom:0; }
.st-index .n,.st-index .c{ font-size:var(--st-micro); line-height:15px; letter-spacing:var(--st-ui-ls);
  color:var(--st-muted); text-transform:uppercase; }
.st-index .t{ font-size:clamp(17px,2.1vw,30px); line-height:1.04; text-transform:uppercase; font-weight:500;
  color:var(--st-muted); transition:color .2s; }
.st-index .ix-row[aria-current="true"] .t,.st-index .ix-row:hover .t{ color:var(--st-ink); }
.st-index .ix-shot{ position:relative; overflow:hidden; background:var(--st-ph); }
.st-index .ix-shot img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  opacity:0; transition:opacity .35s; }
.st-index .ix-shot img.on{ opacity:1; }
@media(max-width:860px){
  .st-index{ grid-template-columns:1fr; }
  .st-index .ix-shot{ order:-1; aspect-ratio:3/2; }
  .st-index .ix-list{ padding:4px 24px; }
}

/* ── THE HOME RHYTHM ─────────────────────────────────────────────────────
   Banner, that programme's products, repeat — shop.griffain.io's arrangement,
   measured at 1900px: banner 1900x650, row 606px tall with 356x567 cards at a
   1px gap and a 12px/16px weight-500 heading. Never one long grid. */
.st-prog{ margin-top:clamp(40px,5vw,72px); }
.st-banner{ position:relative; display:block; overflow:hidden; background:var(--st-navy-900);
  height:clamp(300px,34vw,650px); }
/* A photo banner ships as <picture> so the phone gets its own crop, not a
   narrower copy of the wide one — see bannerImg() in js/das-store.js. The
   wrapper must not become a box: `.st-banner img{height:100%}` resolves
   against .st-banner, and an inline <picture> in between breaks that. */
.st-banner picture, .cl-hero picture{ display:contents; }
.st-banner img{ width:100%; height:100%; object-fit:cover;
  transition:transform .7s cubic-bezier(.2,.8,.2,1); }
.st-banner:hover img{ transform:scale(1.03); }
/* A placeholder banner already CONTAINS its own type, so it takes no caption
   overlay — two sets of words on one panel reads as a mistake. */
.st-banner .cap{ position:absolute; inset:auto 0 0 0; padding:clamp(18px,2.4vw,34px); color:#fff;
  background:linear-gradient(to top, rgba(6,14,36,.86), rgba(6,14,36,0)); }
.st-banner .cap b{ display:block; font-size:clamp(18px,1.9vw,28px); line-height:1.05;
  text-transform:uppercase; font-weight:500; }
.st-banner .cap span{ display:block; margin-top:5px; font-size:var(--st-micro); line-height:15px;
  letter-spacing:var(--st-ui-ls); text-transform:uppercase; color:rgba(255,255,255,.72); }

.st-rowhead{ display:flex; align-items:baseline; justify-content:space-between; gap:16px;
  padding:clamp(20px,2.4vw,30px) 24px 14px; }
.st-rowhead h2{ font-size:var(--st-ui); line-height:16px; letter-spacing:var(--st-ui-ls);
  font-weight:700; text-transform:uppercase; }
.st-rowhead a{ color:var(--st-muted); text-decoration:underline; text-underline-offset:3px; }
.st-rowhead a:hover{ color:var(--st-ink); }

.st-row{ display:flex; gap:1px; overflow-x:auto; scroll-snap-type:x mandatory;
  padding:0 24px 14px; }
/* A HIDDEN SCROLLBAR IS WHY NOBODY KNEW IT SCROLLED. The reference hides its
   bar, but it also never shows a row that runs off the edge without an arrow.
   Ours does, and "there's no scroller on mobile and desktop" was the result.
   A 4px rail is a real, draggable scroller on desktop and a position readout
   on a phone, and it costs the row 14px. */
.st-row::-webkit-scrollbar{ height:4px; }
.st-row::-webkit-scrollbar-track{ background:rgba(0,0,0,.06); border-radius:99px; }
.st-row::-webkit-scrollbar-thumb{ background:rgba(0,0,0,.28); border-radius:99px; }
.st-row::-webkit-scrollbar-thumb:hover{ background:rgba(0,0,0,.45); }
.st-row{ scrollbar-width:thin; scrollbar-color:rgba(0,0,0,.28) rgba(0,0,0,.06); }
.st-row .st-card{ flex:0 0 clamp(210px,19vw,356px); scroll-snap-align:start; margin-bottom:0; }
@media(max-width:640px){
  .st-row{ padding:0; }
  .st-row .st-card{ flex:0 0 68vw; }
}

/* NO MARK IN THE FOOTER. One was added on request and removed the same day:
   the first footer column heading already reads DRIVER APPRECIATION SOLUTIONS,
   so the logo above it repeated the name and simply made the footer taller.
   "Just replace the logo with the Driver Appreciation Solutions text under it,
   and keep it that same size as it was before." */

/* ── A COLLECTION PAGE ───────────────────────────────────────────────────
   Its own address, its own title, its own opening statement — "each category
   needs to have its own page ... it's like a mall". The hero reuses the home
   rhythm's banner so a collection looks like the place the home page promised,
   rather than a grid that happens to be filtered. */
.cl-hero{ position:relative; display:grid; place-items:end start; overflow:hidden;
  background:var(--st-navy-900); height:clamp(240px,26vw,420px); }
.cl-hero img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.cl-hero .cl-copy{ position:relative; padding:clamp(20px,3vw,44px); color:#fff;
  width:100%; background:linear-gradient(to top, rgba(6,14,36,.86), rgba(6,14,36,0)); }
/* a placeholder banner carries its own type, so it takes no overlay */
.cl-hero[data-placeholder="true"] .cl-copy{ background:none; }
.cl-hero[data-placeholder="true"] h1,.cl-hero[data-placeholder="true"] .k,
.cl-hero[data-placeholder="true"] .n{ display:none; }
/* ...but only where the whole 2400x820 placeholder is visible. On a phone it is
   cover-cropped to roughly its middle third, so the title baked into it arrives
   as "S PROGRAMS". Below 768 the drawn placeholder is dropped for a plain navy
   panel and the real copy comes back -- which is also exactly what happens when
   the real photograph lands, so nothing here has to change again. */
@media(max-width:767px){
  .cl-hero[data-placeholder="true"]{ background:var(--st-navy); }
  .cl-hero[data-placeholder="true"] img{ display:none; }
  .cl-hero[data-placeholder="true"] h1,.cl-hero[data-placeholder="true"] .k,
  .cl-hero[data-placeholder="true"] .n{ display:block; }
  /* With no photograph to show there is nothing to hold 240px open -- the band
     sized itself for an image it is not displaying. Let the type set the height
     until the real shot lands, at which point the clamp takes over again. */
  .cl-hero[data-placeholder="true"]{ height:auto; }
  .cl-hero{ height:clamp(180px,42vw,240px); }
  .cl-hero .cl-copy{ padding:24px 20px 26px; }
}
.cl-hero h1{ font-size:clamp(26px,3.4vw,46px); line-height:1.02; letter-spacing:-.02em;
  text-transform:uppercase; font-weight:500; }
.cl-hero .k{ color:var(--st-navy-200); margin-bottom:10px; }
.cl-hero .n{ margin-top:8px; color:rgba(255,255,255,.72); }

.cl-crumb{ display:flex; align-items:center; gap:10px; padding:16px 24px 0; color:var(--st-muted); }
.cl-crumb a{ text-decoration:underline; text-underline-offset:3px; }
.cl-crumb a:hover{ color:var(--st-ink); }

/* ── THE SEARCH ────────────────────────────────────────────
   It lives in the header now, on every store page. A suggest panel rather than
   a filter: the empty state teaches the vocabulary, typing lands on real
   destinations, and the last row always offers the conversation a lookup
   cannot have. The spark is the only ornament and it earns its place — it is
   the one signal that this field answers questions rather than matching
   strings. */
/* ── PILLS, DELIBERATELY AGAINST THE GRAIN ──────────────────────────────
   The store sets --st-radius:0 and every corner in it is square, because the
   reference is. Jayden: "i dont like how everything is so blocky and doesnt
   have a pill aesthetic like a real ai."
   He is right, and the exception is principled rather than a lapse: everything
   else here is CATALOGUE, and catalogue is a grid. This one control is a
   CONVERSATION. Rounding only the thing you talk to is what tells you, before
   you read a word, that it answers rather than filters. */
.st-search{ position:relative; width:100%; }
.st-search *{ border-radius:inherit; }
.ss-box{
  display:flex; align-items:center; gap:10px; width:100%; height:42px; padding:0 8px 0 16px;
  border-radius:999px;
  background:#fff; color:var(--st-muted);
  box-shadow:inset 0 0 0 1px var(--st-hair), 0 1px 2px rgba(16,24,40,.04);
  transition:box-shadow .18s, background-color .18s;
}
.ss-box:focus-within{
  color:var(--st-navy);
  box-shadow:inset 0 0 0 1.5px var(--st-navy), 0 4px 16px rgba(26,46,110,.13);
}
.ss-spark{ flex:0 0 auto; display:block; line-height:0; color:var(--st-navy); }
.ss-box input{
  flex:1; min-width:0; height:100%; border:0; outline:0; background:none; font:inherit;
  font-size:var(--st-ui); letter-spacing:var(--st-ui-ls); color:var(--st-ink);
}
.ss-box input::placeholder{ color:var(--st-chip-off); text-transform:none; letter-spacing:0; }
.ss-box input::-webkit-search-cancel-button{ display:none; }
.ss-clear{
  flex:0 0 auto; width:28px; height:28px; border-radius:999px; display:grid; place-items:center;
  font-size:16px; line-height:1; color:var(--st-muted); background:var(--st-ph);
}
.ss-clear:hover{ color:var(--st-ink); background:#E7ECF4; }

/* the panel */
.ss-panel{ display:none; }
.ss-open .ss-panel{
  display:block; position:absolute; left:0; right:0; top:calc(100% + 8px); z-index:60;
  background:#fff; border-radius:20px; padding:6px;
  box-shadow:0 0 0 1px var(--st-hair), 0 20px 50px rgba(16,24,40,.16);
  max-height:min(70vh,520px); overflow-y:auto; overscroll-behavior:contain;
}
.ss-head{
  display:flex; align-items:center; gap:9px; padding:11px 14px 9px; color:var(--st-muted);
  text-transform:none; letter-spacing:0;
}
.ss-ai{
  flex:0 0 auto; background:var(--st-navy); color:#fff; padding:3px 9px; border-radius:999px;
  font-size:10px; line-height:14px; letter-spacing:var(--st-ui-ls); text-transform:uppercase; font-weight:700;
}
.ss-seeds{ display:flex; flex-wrap:wrap; gap:6px; padding:12px 14px 14px; }
.ss-seed{
  border-radius:999px; padding:8px 14px; text-align:left; background:var(--st-ph);
  box-shadow:inset 0 0 0 1px transparent;
  color:var(--st-ink); text-transform:none; letter-spacing:0;
  transition:box-shadow .15s, background-color .15s;
}
.ss-seed:hover{ background:#fff; box-shadow:inset 0 0 0 1px var(--st-navy); }

.ss-row{
  display:flex; align-items:center; gap:12px; padding:8px 12px; margin:1px 0;
  border-radius:14px; color:var(--st-ink); transition:background-color .12s;
}
.ss-row:hover,.ss-row.on{ background:var(--st-ph); }
.ss-row .th{
  flex:0 0 38px; width:38px; height:47px; display:grid; place-items:center;
  border-radius:10px; background:#EEF1F6; color:var(--st-muted); overflow:hidden;
}
.ss-row .th img{ width:100%; height:100%; object-fit:cover; display:block; }
.ss-row .tx{ flex:1; min-width:0; display:block; }
.ss-row .nm{ display:block; text-transform:none; letter-spacing:0; font-size:13px; line-height:18px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.ss-row .mt{ display:block; color:var(--st-muted); font-size:10px; line-height:15px;
  letter-spacing:var(--st-ui-ls); text-transform:uppercase; }
.ss-row .pr{ flex:0 0 auto; color:var(--st-muted); font-size:11px; }

.ss-ask{
  display:flex; align-items:center; gap:9px; width:100%; padding:11px 14px; margin-top:4px;
  border-radius:16px; background:var(--st-ph); text-align:left;
  color:var(--st-ink); transition:background-color .15s;
}
.ss-ask:hover{ background:#E7ECF4; }
.ss-ask .q{ flex:1; min-width:0; color:var(--st-muted); text-transform:none; letter-spacing:0;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.ss-ask .go{ flex:0 0 auto; color:var(--st-navy); }
.ss-none{ padding:14px; color:var(--st-muted); text-transform:none; letter-spacing:0;
  font-size:var(--st-ui); line-height:18px; margin:0; }
.ss-none b{ color:var(--st-ink); font-weight:500; }

/* On a phone the panel is the screen: it drops out of the header and fills the
   width, because an 8-row list inside a 38px field is a list nobody can read. */
@media(max-width:767px){
  .ss-open .ss-panel{ position:fixed; left:0; right:0; top:var(--st-hd-h);
    max-height:calc(100vh - var(--st-hd-h)); box-shadow:0 14px 34px rgba(16,24,40,.16); }
}

/* The bag and saved pages get the same opening as a collection page. They were
   the only two store pages that began straight into content with no statement
   of what they are. */
.pg-head{ padding:clamp(18px,2.4vw,30px) 24px clamp(14px,2vw,24px); border-bottom:1px solid var(--st-hair); }
.pg-head .cl-crumb{ padding:0 0 12px; }
.pg-head h1{ font-size:clamp(26px,3.2vw,42px); line-height:1.02; letter-spacing:-.02em;
  text-transform:uppercase; font-weight:500; }
.pg-head p{ color:var(--st-muted); margin-top:8px; }

/* The hover CTA on a preview. Every card offers an action now — "+" where the
   piece can be added, "Request pricing" where its price is not public, "Choose
   level" where the server needs a milestone first. Appears on hover on a
   pointer device and is always visible on touch, where there is no hover. */
.st-card .choose{
  position:absolute; right:10px; bottom:10px; z-index:20;
  background:rgba(255,255,255,.94); color:var(--st-navy);
  font-size:var(--st-chip); line-height:var(--st-chip-lh); letter-spacing:var(--st-ui-ls);
  text-transform:uppercase; padding:6px 10px; opacity:0; transition:opacity .18s;
}
.st-card:hover .choose,.st-card .choose:focus-visible{ opacity:1; }
.st-card .choose:hover{ background:var(--st-navy); color:#fff; }
.st-card .plus{ opacity:0; transition:opacity .18s; }
.st-card:hover .plus,.st-card .plus:focus-visible{ opacity:1; }
@media(hover:none){ .st-card .choose,.st-card .plus{ opacity:1; } }

/* ── ROW SCROLL CONTROLS ─────────────────────────────────────────────────
   The rows were always overflow-x:auto, but with the scrollbar hidden there
   was nothing to say so and a mouse cannot scroll sideways at all. Arrows sit
   over the ends, appear only when the row overflows, and hide at each end. */
.st-rowwrap{ position:relative; }
.rw-arw{ position:absolute; top:calc(50% - 46px); transform:translateY(-50%); z-index:6;
  width:38px; height:38px; display:grid; place-items:center; color:var(--st-ink);
  background:rgba(255,255,255,.94); border-radius:999px; box-shadow:0 1px 6px rgba(0,0,0,.16); }
.rw-arw:hover{ background:#fff; }
.rw-arw[hidden]{ display:none; }
.rw-prev{ left:10px; } .rw-next{ right:10px; }
@media(max-width:640px){ .rw-arw{ display:none; } }   /* a finger already scrolls */

/* ── CART DRAWER — 440, free-freight tier bar, 110x138 lines ───────────── */
.st-scrim{ position:fixed; inset:0; background:rgba(6,14,36,.45); opacity:0; pointer-events:none; transition:opacity .3s; z-index:60; }
.st-scrim[data-open="true"]{ opacity:1; pointer-events:auto; }
.st-drawer{
  position:fixed; top:0; right:0; bottom:0; width:min(440px,100%); background:#fff; z-index:61;
  transform:translateX(100%); transition:transform .34s cubic-bezier(.2,.8,.2,1);
  display:flex; flex-direction:column;
}
.st-drawer[data-open="true"]{ transform:none; }
.st-drawer .dh{ display:flex; align-items:center; padding:0 20px; height:var(--st-nav-h); border-bottom:1px solid var(--st-hair); }
.st-drawer .dh button{ margin-left:auto; font-size:18px; }
.st-drawer .tier{ padding:14px 20px; border-bottom:1px solid var(--st-hair); }
.st-drawer .tier p{ margin-bottom:8px; }
.st-drawer .tier .track{ height:2px; background:var(--st-hair); }
.st-drawer .tier .track i{ display:block; height:100%; background:var(--st-navy); transition:width .3s; }
.st-drawer .lines{ flex:1; overflow-y:auto; padding:0 20px; }
.st-drawer .line{ display:grid; grid-template-columns:110px minmax(0,1fr); gap:14px; padding:18px 0; border-bottom:1px solid var(--st-hair-soft); }
.st-drawer .line .ph{ width:110px; height:138px; background:var(--st-ph); overflow:hidden; }
.st-drawer .line .ph img{ width:100%; height:100%; object-fit:cover; }
.st-drawer .line .c{ color:var(--st-muted); }
.st-drawer .line .rm{ color:var(--st-muted); text-decoration:underline; text-underline-offset:3px; margin-top:6px; }
.st-drawer .line .rm:hover{ color:var(--st-sale); }
.st-drawer .sub{ padding:16px 20px; border-top:1px solid var(--st-hair); }
.st-drawer .sub .row{ display:flex; justify-content:space-between; margin-bottom:4px; }
.st-drawer .sub .note{ color:var(--st-muted); margin:6px 0 12px; }
.st-drawer .empty{ padding:40px 20px; color:var(--st-muted); }

@media(prefers-reduced-motion:reduce){ .st *{ transition:none!important; } }

/* ── CART PAGE + SAVED PAGE ─────────────────────────────────────────────── */
.sc-wrap{ display:grid; grid-template-columns:minmax(0,1fr) 400px; gap:56px; padding:clamp(28px,4vw,48px) 24px; align-items:start; max-width:1400px; margin:0 auto; }
@media(max-width:1023px){ .sc-wrap{ grid-template-columns:minmax(0,1fr); gap:32px; } }
.sc-head{ display:flex; align-items:baseline; gap:10px; padding-bottom:14px; border-bottom:1px solid var(--st-hair); margin-bottom:6px; }
.sc-head h1{ font-size:20px; line-height:26px; text-transform:uppercase; }
.sc-head sup{ vertical-align:super; margin-left:5px; }

.sc-line{ display:grid; grid-template-columns:132px minmax(0,1fr); gap:18px; padding:22px 0; border-bottom:1px solid var(--st-hair-soft); }
.sc-line .ph{ display:block; width:132px; aspect-ratio:var(--st-frame); background:var(--st-ph); overflow:hidden; }
.sc-line .ph img{ width:100%; height:100%; object-fit:cover; }
.sc-line .top{ display:flex; justify-content:space-between; gap:14px; align-items:baseline; }
.sc-line .t{ font-weight:500; }
.sc-line .t:hover{ text-decoration:underline; text-underline-offset:3px; }
.sc-line .lp{ flex:none; font-weight:500; }
.sc-line .c{ color:var(--st-muted); margin-top:3px; }
.sc-line .ctl{ display:flex; align-items:center; gap:16px; margin-top:12px; }
.sc-line .step{ display:inline-flex; align-items:center; box-shadow:inset 0 0 0 1px var(--st-hair); height:38px; }
.sc-line .step button{ width:36px; height:100%; display:grid; place-items:center; font-size:15px; }
.sc-line .step button:hover{ background:var(--st-navy); color:#fff; }
.sc-line .step input{ width:52px; height:100%; border:0; background:none; text-align:center; font:inherit; font-weight:500; -moz-appearance:textfield; }
.sc-line .step input::-webkit-outer-spin-button,.sc-line .step input::-webkit-inner-spin-button{ -webkit-appearance:none; margin:0; }
.sc-line .rm{ color:var(--st-muted); text-decoration:underline; text-underline-offset:3px; }
.sc-line .rm:hover{ color:var(--st-sale); }
@media(max-width:560px){ .sc-line{ grid-template-columns:96px minmax(0,1fr); gap:14px; } .sc-line .ph{ width:96px; } }

/* the honest next-add prompt */
.sc-nudge{ display:flex; align-items:center; justify-content:space-between; gap:18px; flex-wrap:wrap;
  background:#F4F7FD; padding:16px 18px; margin-top:20px; }
.sc-nudge p{ color:var(--st-navy-700); max-width:52ch; text-transform:none; letter-spacing:0; font-size:13px; line-height:20px; }
.sc-nudge b{ text-transform:uppercase; letter-spacing:var(--st-ui-ls); font-size:var(--st-ui); }

/* summary rail */
.sc-sum{ position:sticky; top:calc(var(--st-hd-h) + 20px); box-shadow:inset 0 0 0 1px var(--st-hair); padding:22px; }
@media(max-width:1023px){ .sc-sum{ position:static; } }
.sc-sum h2{ font-size:var(--st-ui); letter-spacing:var(--st-ui-ls); text-transform:uppercase; color:var(--st-muted); margin-bottom:16px; }
.sc-sum .row{ display:flex; justify-content:space-between; padding:6px 0; }
.sc-sum .row.total{ border-top:1px solid var(--st-hair); margin-top:10px; padding-top:14px; font-size:19px; }
.sc-sum .freight{ margin:14px 0 18px; }
.sc-sum .freight p{ margin-bottom:8px; }
.sc-sum .track{ height:3px; background:var(--st-hair); }
.sc-sum .track i{ display:block; height:100%; background:var(--st-navy); transition:width .35s ease; }
.sc-sum .reassure{ margin-top:16px; }
.sc-sum .reassure div{ display:flex; gap:9px; align-items:flex-start; padding:7px 0; color:var(--st-muted); }
.sc-sum .reassure svg{ flex:none; margin-top:3px; color:var(--st-navy); }
.sc-sum .alt{ display:block; text-align:center; margin-top:12px; color:var(--st-muted); text-decoration:underline; text-underline-offset:3px; }
.sc-sum .alt:hover{ color:var(--st-navy); }

.sc-empty{ padding:clamp(40px,7vw,80px) 0; }

/* saved page actions */
.sv-actions{ display:flex; gap:10px; flex-wrap:wrap; padding:0 24px 8px; }

/* ════════════════════════════════════════════════════════════════════════
   PDP v2 — the reference's real gallery behaviour
   ------------------------------------------------------------------------
   v1 showed ONE image with a thumb rail beneath. That is not what Represent
   or shop.griffain.io do: the gallery is a STACKED COLUMN of every photograph
   that scrolls past a buy box pinned beside it. On a catalogue where a kit has
   four or five shots, that difference is most of the page.
   ════════════════════════════════════════════════════════════════════════ */
/* TWO EQUAL HALVES, measured off the reference: at a 1900px viewport its
   gallery column is 950px — exactly 50% — and the 472px buy column sits
   CENTRED in the other half (239px of margin either side), not flush against
   the gallery. My first pass gave the gallery `1fr` and pinned the buy column
   hard right, which is why the two never matched. */
.st-pdp2{ display:grid; grid-template-columns:1fr 1fr; align-items:start; }
@media(max-width:1023px){ .st-pdp2{ grid-template-columns:minmax(0,1fr); } }

/* the stacked gallery */
/* ── THE GALLERY — 1:1 PORT OF shop.griffain.io's PDP ────────────────────
   Jayden 2026-09-23: "why is there so much white space can we just do a
   identical copy of what the griffain io".

   The white space was mine. Avoiding a crop, I sized the figure by height
   against the fold, so a portrait shot sat 731px wide in a 1397px column with
   two 333px gutters of nothing. He is right that that is worse than the
   problem it solved. The reference never has gutters because its image FILLS
   the frame with object-fit:cover.

   MEASURED off the live page at 1900x1000, and reproduced below verbatim:
       gallery column  950px  == exactly 50% of the viewport
       frame           950 x 1188, cover, ground #f7f7f7
       image width     calc(100% + 1px)  <- their rule; kills the snap seam
       buy column      472px, sticky, min-height 100dvh, centred in its half
       counter         12px at .54 opacity on white, 27px in, 28px up
       dots            3px tall, active 16px solid, rest 6px at 30%
       arrows          20px in, white at 80%, round, soft shadow

   THE ONE DEVIATION: --st-pdp-frame. Theirs is 4:5 PORTRAIT because Represent
   shoots 4:5 apparel. Of DAS's 54 primary shots, 50 are landscape or square
   and 4 are portrait — cover-fitting a 1.5 landscape kit photo into 4:5 crops
   47% of its WIDTH. So the frame is DAS's own modal 1.25, matching the card
   grid. Change this one token to 4/5 for a literal copy; either value fills
   the frame completely, which is the part that was actually wrong. */
:root{ --st-pdp-frame:0.8; }

.st-pdp2 .pd-gal{
  position:relative; background:#f7f7f7;
  aspect-ratio:var(--st-pdp-frame); overflow:hidden;
}
.pd-track{
  display:flex; height:100%; overflow-x:auto; overflow-y:hidden;
  scroll-snap-type:x mandatory; scrollbar-width:none; -ms-overflow-style:none;
}
.pd-track::-webkit-scrollbar{ display:none; }
.pd-slide{ flex:0 0 100%; width:100%; height:100%; margin:0; scroll-snap-align:start; }
/* calc(100% + 1px) is the reference's own value — at fractional column widths a
   flat 100% leaves a hairline of the #f7f7f7 ground showing at the snap edge. */
.pd-slide img{ display:block; width:calc(100% + 1px); height:100%; object-fit:cover; max-width:none;
  transition:transform .6s cubic-bezier(.2,.8,.2,1); }
.pd-gal[data-zoom="true"] .pd-slide img{ transform:scale(1.55); cursor:zoom-out; }

.pd-arw{
  position:absolute; top:50%; transform:translateY(-50%); z-index:2;
  padding:12px; color:#000; line-height:0;
  background:rgba(255,255,255,.8); border-radius:999px;
  box-shadow:0 1px 4px rgba(0,0,0,.15);
}
.pd-arw:hover{ opacity:.75; }
.pd-prev{ left:8px; } .pd-next{ right:8px; }
@media(min-width:1024px){ .pd-prev{ left:20px; } .pd-next{ right:20px; } }

/* NOT .pd-bar — that class already belongs to the sticky add-to-cart bar
   (position:fixed; display:none until mobile). Naming this one the same made
   the whole control strip — counter, dots and zoom — display:none on desktop,
   i.e. invisible to every user while still clickable from script. Caught only
   because the dots measured 0x0. */
.pd-gbar{ position:absolute; left:0; right:0; bottom:0; z-index:10;
  display:flex; align-items:center; justify-content:flex-start; gap:6px; margin-bottom:4px; }
@media(min-width:1024px){ .pd-gbar{ bottom:28px; margin-bottom:0; } }
.pd-count{ display:flex; align-items:center; gap:2px; margin-left:12px;
  padding:4px 8px; background:#fff; color:#000; opacity:.54;
  font-size:12px; font-variant-numeric:tabular-nums; letter-spacing:0; }
@media(min-width:1024px){ .pd-count{ margin-left:27px; } }
.pd-dots{ display:flex; align-items:center; gap:5px; padding:4px 8px; background:#fff; }
.pd-dot{ display:block; height:3px; width:6px; border-radius:999px; background:rgba(0,0,0,.3); transition:all .2s; }
.pd-dot.on{ width:16px; background:#000; }
.pd-zoom{ margin-left:auto; padding:12px; color:#000; line-height:0; }
@media(min-width:1024px){ .pd-zoom{ padding:16px; padding-right:28px; } }


/* the pinned buy column */
/* 472px, centred in its half, sticky, and min-height:100dvh — all four are
   the reference's own measured values. The border-left is gone: theirs has no
   rule between the halves, the photograph's own edge is the divider. */
.pd-buy{
  position:sticky; top:var(--st-hd-h);
  width:100%; max-width:var(--st-buycol); margin-inline:auto;
  min-height:100dvh; padding:32px 0 33px;
}
@media(max-width:1023px){
  .pd-buy{ position:static; min-height:0; max-width:none; padding:28px 15px 33px;
    border-top:1px solid var(--st-hair); }
}
/* ── THE FLAT COLUMN ─────────────────────────────────────────────────────
   Jayden 2026-09-23: "u should think as a artist when ur doing design with me."
   He is right, and measuring was not the same as looking. Reading the numbers
   off the reference told me the column was 472px; it did not tell me WHY the
   reference looks the way it does.

   What looking at it shows: the reference column is deliberately QUIET.
   Its product title is 12px/18px weight 500 — the same UI type as everything
   else on the page — with the price right-aligned on that same line, and there
   is not a single border anywhere in the column. Controls are filled #f7f7f7
   chips, nothing else. The flat column is what lets the PHOTOGRAPH carry the
   whole page.

   What I had built instead: a 30px uppercase title and three bordered boxes
   stacked down the column, each one competing for the same attention the photo
   wants. That is a SaaS product page, not this. Flattened to their system. */
.pd-buy .head{ display:flex; align-items:baseline; justify-content:space-between; gap:20px; }
/* THE PRODUCT NAME — 3x, on Jayden's call. It was 12px because that is what
   the reference does, and the reference can afford it: shop.griffain.io sells
   six garments a visitor already came for, so the photograph is the headline.
   DAS sells 54 pieces across six programs to a buyer who arrived from a
   category, and the name is doing real work — "250,000 Safe Service Miles —
   Executive Collection" is information, not a label. 12 -> 36px, same face,
   line-height pulled in and tracking tightened so it reads as a heading rather
   than enlarged UI text. The price stays 12px and right-aligned, which now
   reads as a caption to the title instead of competing with it. */
.pd-buy h1{ font-size:clamp(26px,2.6vw,36px); line-height:1.04; letter-spacing:-.015em;
  font-weight:500; text-transform:none; }
.pd-buy .eyebrow{ color:var(--st-muted); font-size:var(--st-micro); line-height:16px; margin-top:6px; }
.pd-buy .price{ font-size:var(--st-ui); line-height:var(--st-ui-lh); letter-spacing:var(--st-ui-ls);
  white-space:nowrap; text-transform:uppercase; }
.pd-buy .price small{ color:var(--st-muted); font-size:var(--st-micro); }
.pd-buy .blurb{ font-size:var(--st-ui); line-height:18px; color:var(--st-muted);
  text-transform:none; letter-spacing:0; margin:17px 0 32px; }

/* program chip — replaces the reference's fit chips */
.st .pd-prog{ display:inline-flex; align-items:center; gap:8px; margin-bottom:24px;
  padding:0; color:var(--st-ink); text-decoration:underline; text-underline-offset:3px; }
.st .pd-prog:hover{ color:var(--st-navy); }

.pd-lbl{ display:flex; align-items:baseline; justify-content:space-between; margin:20px 0 8px; }
.pd-lbl a{ color:var(--st-muted); text-decoration:underline; text-underline-offset:3px; }
.pd-qty{ display:grid; grid-template-columns:repeat(4,1fr); gap:4px; }
.pd-qty button{ height:46px; background:#f7f7f7; display:grid; place-items:center; line-height:1.2; }
.pd-qty button small{ display:block; font-size:9px; color:var(--st-muted); letter-spacing:var(--st-ui-ls); }
.pd-qty button:hover{ background:#ededed; }
.pd-qty button[aria-pressed="true"]{ background:var(--st-navy); color:#fff; }
.pd-qty button[aria-pressed="true"] small{ color:rgba(255,255,255,.7); }

/* logistics strip — the three questions a fleet buyer asks before quantity */
.pd-logi{ display:flex; flex-direction:column; margin:0 0 4px; }
.pd-logi div{ display:flex; align-items:center; gap:15px; padding:13px 0; border-top:1px solid var(--st-hair); }
.pd-logi b{ width:96px; flex:none; color:var(--st-ink); }
.pd-logi span{ color:var(--st-muted); }

.pd-usp{ border-top:1px solid var(--st-hair-soft); margin-top:22px; }
.pd-usp div{ display:flex; gap:10px; align-items:flex-start; padding:11px 0; border-bottom:1px solid var(--st-hair-soft); color:var(--st-muted); }
.pd-usp svg{ flex:none; margin-top:3px; color:var(--st-navy); }
.st-pdp2 details{ border-bottom:1px solid var(--st-hair-soft); }
.st-pdp2 summary{ display:flex; justify-content:space-between; align-items:center; padding:15px 0; cursor:pointer; list-style:none; }
.st-pdp2 summary::-webkit-details-marker{ display:none; }
.st-pdp2 summary::after{ content:"+"; font-size:15px; color:var(--st-muted); }
.st-pdp2 details[open] summary::after{ content:"\2212"; }
.st-pdp2 .bd{ padding-bottom:16px; font-size:13px; line-height:21px; color:var(--st-muted); text-transform:none; letter-spacing:0; }
.st-pdp2 .bd li{ position:relative; padding-left:16px; margin-bottom:5px; }
.st-pdp2 .bd li::before{ content:""; position:absolute; left:0; top:9px; width:5px; height:1px; background:var(--st-navy); }

/* sticky mobile buy bar — the single biggest mobile conversion device */
.pd-bar{ position:fixed; left:0; right:0; bottom:0; z-index:50; display:none;
  background:#fff; border-top:1px solid var(--st-hair); padding:10px 14px;
  padding-bottom:calc(10px + env(safe-area-inset-bottom,0px));
  gap:10px; align-items:center; }
@media(max-width:1023px){ .pd-bar{ display:flex; } body.st{ padding-bottom:78px; } }
.pd-bar .n{ flex:1; min-width:0; }
.pd-bar .n b{ display:block; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.pd-bar .n span{ color:var(--st-muted); }
.pd-bar .st .st-cta{ flex:none; padding:0 20px; height:46px; }

/* program band under the fold */
/* SECTION HEADS UNDER THE PRODUCT — the reference's scale.
   Jayden 2026-09-23: "and everything under it aswell the different products
   collections etc the same look". Measured on shop.griffain.io, its
   "The Kit — Employees" and related-product heads are 12px/16px, weight 700,
   uppercase, 0.133333px tracking — the same UI type as everything else in the
   system, not a display size. DAS's related row was rendering at 18px/500,
   which read as a page heading competing with the product title rather than a
   quiet label above a row. */
#pd-also .head h2{
  font-size:var(--st-ui); line-height:var(--st-ui-lh); letter-spacing:var(--st-ui-ls);
  font-weight:700; text-transform:uppercase;
}
#pd-also .head sup{ font-size:8px; }

/* ── THE CLOSING BAND — the reference's First Edition panel ────────────────
   Jayden 2026-09-23: "the first edition thing at the bottom is Join the
   waitlist with the photo. We need to do something similar to that one,
   one-to-one identical, but use the green trees photo ... CTA Build the
   program."

   Theirs is a two-up panel: a full-bleed photograph on one side, and on the
   other a quiet editorial column — small uppercase eyebrow, a two-line display
   line, one line of copy, one full-width button. It is the only place on the
   page that uses a display size, which is exactly why it lands. The photograph
   is the forest band already on the shop page, so the store closes on the same
   image it opens with. */
.pd-band{ background:var(--st-navy-900); color:#fff; margin-top:0;
  display:grid; grid-template-columns:1fr 1fr; align-items:stretch; }
@media(max-width:900px){ .pd-band{ grid-template-columns:1fr; } }
.pd-band .fb-media{ position:relative; overflow:hidden; min-height:clamp(420px,46vw,620px); }
.pd-band .fb-media img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
@media(max-width:900px){ .pd-band .fb-media{ min-height:300px; position:relative; }
  .pd-band .fb-media img{ position:absolute; } }
.pd-band .fb-copy{ display:flex; flex-direction:column; justify-content:center;
  padding:clamp(40px,5vw,72px) clamp(24px,4vw,64px); }
.pd-band .fb-copy .k{ color:var(--st-navy-200); margin-bottom:18px; }
.pd-band .fb-copy h2{ font-size:clamp(28px,3.4vw,44px); line-height:1.04; letter-spacing:-.02em;
  text-transform:uppercase; margin-bottom:16px; }
.pd-band .fb-lede{ font-size:14px; line-height:22px; color:rgba(255,255,255,.72);
  max-width:46ch; text-transform:none; letter-spacing:0; margin-bottom:28px; }
.pd-band .st-cta{ max-width:320px; }

/* ── ROWS UNDER THE PRODUCT: the kit, you-may-also-like, recently viewed ──
   One card, one heading treatment, three jobs — measured off the reference:
   12px/16px weight 700 uppercase, and its also-like head is CENTRED with the
   tab row beneath it. Five across, which at 1900px gives the reference's own
   ~380px card. */
.pd-row, .pd-also{ padding:clamp(40px,4vw,64px) 0 0; }
.pd-rowhead{ padding:0 14px 14px; }
.pd-rowhead h2{ font-size:var(--st-ui); line-height:16px; letter-spacing:var(--st-ui-ls);
  font-weight:700; text-transform:uppercase; }
.pd-rowhead--center{ text-align:center; padding-bottom:10px; }

.pd-tabs{ display:flex; justify-content:center; gap:28px; margin-bottom:22px; }
.pd-tab{ position:relative; padding:4px 0; color:var(--st-muted); font-weight:500; }
.pd-tab.on{ color:var(--st-ink); }
.pd-tab::after{ content:""; position:absolute; left:0; right:0; bottom:0; height:1px;
  background:transparent; transition:background-color .2s; }
.pd-tab.on::after{ background:var(--st-ink); }
.pd-tab:hover{ color:var(--st-ink); }

.pd-more{ display:flex; justify-content:center; padding:26px 0 0; }
.pd-loadmore{ height:36px; padding:0 22px; box-shadow:inset 0 0 0 1px var(--st-hair);
  background:#fff; font-weight:500; }
.pd-loadmore:hover{ box-shadow:inset 0 0 0 1px var(--st-ink); }

/* ── Skip link ───────────────────────────────────────────────────────────
   The store pages do not load styles.css, which is where the site's
   .skip-link lives — so the link rendered as visible body text at the top of
   every store page. Off-screen until focused, which is the point of it. */
.st .skip-link{
  position:absolute; left:-9999px; top:0; z-index:100;
  background:var(--st-navy); color:#fff; padding:12px 18px;
  font-size:var(--st-ui); line-height:var(--st-ui-lh); letter-spacing:var(--st-ui-ls);
  text-transform:uppercase;
}
.st .skip-link:focus{ left:0; }

/* ── PDP variant selects — milestone level and kit build ─────────────────
   Square, 1px, same 12px UI type as every other control here. These carry a
   SERVER CONTRACT: create-checkout validates the milestone key and rejects the
   order without it, so they are never decorative. */
.st .pd-select{
  width:100%; height:46px; padding:0 34px 0 12px;
  background:#fff; color:var(--st-ink);
  box-shadow:inset 0 0 0 1px var(--st-hair);
  font-family:var(--st-font); font-size:var(--st-ui); line-height:var(--st-ui-lh);
  letter-spacing:var(--st-ui-ls); text-transform:uppercase;
  appearance:none; border:0; cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%236B7280' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:right 12px center;
}
.st .pd-select:hover{ box-shadow:inset 0 0 0 1px var(--st-navy); }
.st .pd-select:focus{ outline:2px solid var(--st-navy); outline-offset:1px; }
.st .pd-note{
  margin-top:8px; font-size:11px; line-height:16px; color:var(--st-muted);
  text-transform:none; letter-spacing:0;
}
/* A piece that needs a variant chosen cannot be quick-added from the grid —
   the "+" is replaced by a link into the product page. */
.st-card .choose{
  position:absolute; bottom:0; right:0; z-index:20; padding:10px;
  font-size:10px; line-height:16px; letter-spacing:var(--st-ui-ls);
  text-transform:uppercase; color:var(--st-ink); background:rgba(255,255,255,.92);
}
.st-card .choose:hover{ background:var(--st-navy); color:#fff; }

/* ── Executive Collection cross-link ─────────────────────────────────────
   A premium upgrade ON a Safe Service Miles medal, never on a career one.
   Brass-free on purpose: the upgrade is an upsell, not an earned metal. */
.pd-exec{ margin:24px 0; border-top:1px solid var(--st-hair); }
.pd-exec .k{ display:block; padding:14px 0 8px; color:var(--st-muted); font-weight:700; }
.pd-exec .row{
  display:flex; align-items:baseline; justify-content:space-between; gap:12px;
  padding:11px 14px; border-top:1px solid var(--st-hair-soft); color:var(--st-ink);
}
.pd-exec .row:hover{ background:var(--st-navy); color:#fff; }
.pd-exec .row .up{ flex:none; color:var(--st-navy); font-weight:500; }
.pd-exec .row:hover .up{ color:#fff; }

/* == SHOP BY PROGRAM: the full-bleed parallax ==============================
   Copied from shop.griffain.io's closing section. The mechanism is one CSS
   grid cell holding two children: a stack of 100vh photographs and a sticky
   block of type. The row is as tall as the photographs, so the type stays
   pinned at 40vh through all of them and swaps as each panel crosses the line.
   No scroll library, on their page or ours.

   Panels are placeholders until the photography exists; the two crops each
   program needs are in PHOTO-SHOT-LIST-PARALLAX.md. */
.st-px{
  position:relative; display:grid; grid-template-columns:1fr;
  color:#fff; background:var(--st-navy-900); overflow:clip;
}
.st-px > *{ grid-column:1; grid-row:1; }

.px-panel{ position:relative; height:100vh; height:100svh; }
.px-panel a{ display:block; width:100%; height:100%; }
.px-panel picture{ display:block; width:100%; height:100%; overflow:hidden; }
.px-panel img{ display:block; width:100%; height:100%; object-fit:cover; }

/* A SCRIM, SO LEGIBILITY NEVER DEPENDS ON AN EXPOSURE.
   The first test frame measured 17.7% of its type band above 200 luminance --
   white type would have dropped out in patches over the bright sky. Directing
   darker photographs fixes that frame; it does not stop the NEXT photograph
   from being bright, and these get swapped. So the panel darkens itself where
   the type actually sits: a soft ellipse through the middle, plus a little at
   the top and bottom edges where the header and the next section meet it.
   The photograph stays readable everywhere the type is not. */
.px-panel::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:
    radial-gradient(125% 78% at 50% 56%,
      rgba(5,10,28,.62) 0%, rgba(5,10,28,.40) 38%,
      rgba(5,10,28,.16) 66%, rgba(5,10,28,0) 86%),
    linear-gradient(180deg,
      rgba(5,10,28,.30) 0%, rgba(5,10,28,0) 26%,
      rgba(5,10,28,0) 74%, rgba(5,10,28,.34) 100%);
}

.px-content{ position:relative; z-index:10; pointer-events:none; }
/* CENTRED ON THE VIEWPORT, not offset from its top. The reference pins its
   block at top:40vh, which works for its FOUR names. Ours carries six, so the
   block runs 496px tall and a 40vh offset pushed it off the bottom of an 800px
   screen -- the CTA ended up hard against the edge. A full-height sticky box
   with align-content:center keeps the type optically centred at any viewport
   height and any number of programs. */
.px-in{
  position:sticky; top:0; min-height:100vh; min-height:100svh;
  padding:40px 24px; box-sizing:border-box;
  display:grid; align-content:center; gap:44px; justify-items:center;
  text-align:center; text-transform:uppercase; pointer-events:auto;
}
.px-eyebrow{ font-size:11px; line-height:15px; font-weight:500; letter-spacing:var(--st-ui-ls); margin:0; }
.px-list{ display:grid; justify-self:center; gap:0; justify-items:stretch; }
.px-list h3{ margin:0; }
/* width:100% matters. A <button> sizes to its content even at display:block,
   so each name was only as wide as its own text and they all stacked against
   the left edge of the list -- centred as a block, left-aligned inside it.
   Filling the column lets the button's own centred text actually centre. */
.px-list button{
  display:block; width:100%; color:#fff; font-size:30px; line-height:1;
  font-weight:700; letter-spacing:-1.5px; text-transform:none; opacity:.3;
  transition:opacity .3s; padding:2px 0; text-align:center;
}
.px-list button:hover{ opacity:.5; }
.px-list button[aria-current="true"]{ opacity:1; }
@media(min-width:1024px){ .px-list button{ font-size:32px; } }

.px-go{
  display:inline-flex; align-items:center; gap:4px; color:#fff;
  font-size:11px; line-height:15px; letter-spacing:var(--st-ui-ls);
  border-bottom:1px solid currentColor; padding-bottom:2px;
}
.px-go:hover{ opacity:.7; }

/* A phone's 100vh jumps as the browser chrome hides, which drags the sticky
   type with it. svh above pins it; this keeps the panels from swallowing the
   whole screen on a short viewport. */
@media(max-width:767px){
  .px-in{ padding:44px 20px; gap:28px; }
  .px-list button{ font-size:26px; letter-spacing:-1px; }
}
@media (prefers-reduced-motion:reduce){
  .px-in{ position:static; margin-top:0; }
  .px-panel{ height:62vh; }
}

/* ── iOS AUTO-ZOOM GUARD ─────────────────────────────────────────────────
   Jayden 2026-09-24: "The screen can be zoomed in and zoomed out, so it's not
   sticky."

   This is not a sticky bug. Safari on iOS zooms the page in whenever a form
   control smaller than 16px takes focus, and it does NOT zoom back out. The
   store search field was 12px, the bag's quantity input 12px, and contact's
   selects and textarea 15px -- so tapping any of them left the whole page
   magnified, with the header apparently detached because a sticky element
   pins to the layout viewport while a pinch-zoomed view scrolls the visual
   one. One tap on the search box and the site looked broken.

   16px is the threshold, not a preference, so this is set rather than
   suggested. !important is deliberate: page-scoped rules set these sizes and
   this has to beat all of them, and it is a platform-behaviour guard rather
   than a design choice. Disabling zoom with user-scalable=no would "fix" it
   by taking pinch-zoom away from everyone, which is an accessibility
   regression and one Safari ignores anyway. */
@media(max-width:767px){
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  select, textarea{ font-size:16px !important; }
}

/* ── SCOUT'S ANSWER, ON EVERY SEARCH ────────────────────────────────────
   The matches appear instantly from the local index; this fills in underneath
   when Scout replies. It never blocks the list and it never moves it. */
.ss-scout{
  display:flex; gap:10px; align-items:flex-start; margin:2px 4px 6px; padding:12px 14px;
  border-radius:16px; background:linear-gradient(180deg,#F4F7FD 0%,#EEF2FA 100%);
  box-shadow:inset 0 0 0 1px rgba(26,46,110,.09);
  font-size:13px; line-height:1.5; color:var(--st-ink);
  text-transform:none; letter-spacing:0;
}
.ss-scout .av{
  flex:0 0 22px; width:22px; height:22px; border-radius:999px; margin-top:1px;
  display:grid; place-items:center; background:var(--st-navy); color:#fff;
}
.ss-scout p{ margin:0; }
.ss-scout .who{ display:block; font-size:10px; font-weight:700; letter-spacing:var(--st-ui-ls);
  text-transform:uppercase; color:var(--st-navy); margin-bottom:3px; }
.ss-scout.thinking .dots{ display:inline-flex; gap:3px; vertical-align:middle; }
.ss-scout.thinking .dots i{
  width:4px; height:4px; border-radius:999px; background:var(--st-navy); opacity:.35;
  animation:ssPulse 1.1s ease-in-out infinite;
}
.ss-scout.thinking .dots i:nth-child(2){ animation-delay:.16s }
.ss-scout.thinking .dots i:nth-child(3){ animation-delay:.32s }
@keyframes ssPulse{ 0%,100%{opacity:.25;transform:translateY(0)} 50%{opacity:.9;transform:translateY(-2px)} }
@media (prefers-reduced-motion:reduce){ .ss-scout.thinking .dots i{ animation:none } }

/* ── "SCOUT BROUGHT YOU HERE" ───────────────────────────────────────────
   A jump from the search used to land silently: right page, no explanation,
   indistinguishable from a random redirect. This is the receipt. It appears
   once, on the page you landed on, and carries Scout's answer with it. */
.ss-came{
  display:flex; align-items:flex-start; gap:11px;
  margin:0 auto; max-width:1180px; padding:12px 16px;
  border-radius:0 0 18px 18px;
  background:linear-gradient(180deg,#F4F7FD 0%,#EDF1FA 100%);
  box-shadow:inset 0 0 0 1px rgba(26,46,110,.10);
  font-size:13px; line-height:1.5; color:var(--st-ink);
  text-transform:none; letter-spacing:0;
  animation:ssCame .34s cubic-bezier(.2,.8,.2,1) both;
}
@keyframes ssCame{ from{ opacity:0; transform:translateY(-8px) } }
@media (prefers-reduced-motion:reduce){ .ss-came{ animation:none } }
.ss-came .av{
  flex:0 0 22px; width:22px; height:22px; border-radius:999px; margin-top:1px;
  display:grid; place-items:center; background:var(--st-navy); color:#fff;
}
.ss-came .tx{ flex:1; min-width:0; }
.ss-came b{ color:var(--st-navy); font-weight:700; }
.ss-came .say{ display:block; margin-top:4px; color:var(--st-muted); }
.ss-came .say.dots{ display:inline-flex; gap:3px; align-items:center; height:18px; }
.ss-came .say.dots i{
  width:4px; height:4px; border-radius:999px; background:var(--st-navy); opacity:.35;
  animation:ssPulse 1.1s ease-in-out infinite;
}
.ss-came .say.dots i:nth-child(2){ animation-delay:.16s }
.ss-came .say.dots i:nth-child(3){ animation-delay:.32s }
.ss-came-x{
  flex:0 0 auto; width:26px; height:26px; border-radius:999px; display:grid; place-items:center;
  font-size:16px; line-height:1; color:var(--st-muted); background:transparent;
}
.ss-came-x:hover{ color:var(--st-ink); background:rgba(26,46,110,.08); }
@media(max-width:767px){ .ss-came{ margin:0; border-radius:0; padding:11px 14px; } }
