/* THE PRODUCT DETAIL TEMPLATE — /shop/p2/, rendered by assets/js/kc-pdp.js.
   ===========================================================================
   Nike's anatomy, KEEP CALM's design system. Kaʻo, 2026-08-22: "nearly exactly
   like Nike but with our design system (not black buttons etc)". So the
   proportions, the rhythm, the sticky buy column and the order of the controls
   follow Nike; every colour and the typeface come from the site's own tokens,
   which is why this works in both themes without a second palette.

   THIS IS ITS OWN STYLESHEET ON PURPOSE. assets/cdo-watchtower.css is one
   sheet for the whole site and a careless selector there reaches 128 other
   pages — which has cost real hours before. Everything here is prefixed .pdp
   and loaded only by the product page, so the blast radius is one page.

   TOKENS USED, all defined in cdo-watchtower.css and tracked per theme:
     --wt-ink / --wt-ink-soft / --wt-ink-quiet   text, in three weights
     --wt-rule                                    hairline BETWEEN blocks only
     --wt-field-border                            the edge of a real control
     --wt-accent / --wt-link                      the green, and the mint
     --wt-btn-bg / --wt-btn-ink                   the primary button
     --wt-font-ui                                 Montserrat
   --wt-rule is 1.33:1 and is right for a divider and wrong as the edge of
   something you click; anything interactive uses --wt-field-border, which is
   measured at 3:1+ in both themes (WCAG 1.4.11). Do not swap them.
   =========================================================================== */

:root {
  /* THE NEUTRAL CARD. Every image sits on it, which is the one rule that fixes
     the white-box bug: the print partner's mockups have a baked white
     background, so in dark mode a product page that fell back to mockups
     showed a glaring white rectangle. Nike puts every photograph on the same
     soft panel; doing the same makes a white mockup and a full-bleed
     photograph look like they belong to one store, and costs no image work. */
  --pdp-canvas:      #f0ede6;
  --pdp-canvas-line: #e2dccf;
  --pdp-lift:        0 1px 2px rgba(38, 48, 43, .05);
}
html[data-mode="batman"] {
  --pdp-canvas:      #252c29;
  --pdp-canvas-line: #333c37;
  --pdp-lift:        none;
}

.kc-pd-wrap { font-family: var(--wt-font-ui); color: var(--wt-ink); }

.pdp-status { max-width: 1360px; margin: 40px auto; padding: 0 20px; text-align: center; color: var(--wt-ink-soft); }

/* ---------- breadcrumb ---------- */
.pdp-crumbs {
  max-width: 1360px; margin: 0 auto; padding: 18px 20px 10px;
  font-size: 13px; color: var(--wt-ink-quiet); display: flex; gap: 8px; flex-wrap: wrap;
}
.pdp-crumbs a { color: var(--wt-ink-quiet); text-decoration: none; }
.pdp-crumbs a:hover { color: var(--wt-ink); text-decoration: underline; }
.pdp-crumbs span[aria-hidden] { opacity: .5; }

/* =====================================================================
   THE TWO COLUMNS
   Nike's split: the pictures take the room, the buy column is a fixed,
   comfortable measure that never grows past what is readable.
   ===================================================================== */
.pdp {
  max-width: 1360px; margin: 0 auto; padding: 0 20px 8px;
  display: grid; grid-template-columns: minmax(0, 1fr) 400px; gap: 44px; align-items: start;
}

/* ---------- gallery ----------
   NIKE'S SCROLLING PARADIGM, WHICH IS THE OPPOSITE OF THE OBVIOUS ONE.
   Kaʻo, 2026-08-23: "Start scrolling... left and right side scroll up in
   unison. Then the left anchors to the top and the right starts scrolling...
   as the right side starts getting towards the end, the elements below the
   left and right side come into view. Then the related products come into
   view."

   That is a sticky PICTURE, not a sticky buy column. Nike's own imagery
   carousel carries `position:sticky; top:40px` (read from their page,
   2026-08-23). Both columns rise together until the picture reaches the top
   offset; from then the picture holds while the buy column keeps going, and
   because the picture is shorter than the column of copy beside it, the page
   below arrives naturally when the buy column runs out.

   It only makes sense on a screen tall and wide enough to hold the picture
   beside the copy, so it is switched off with the two-column layout. */
.pdp-media { position: sticky; top: 40px; }
/* --pdp-stage-w caps the picture in PIXELS. A 2:3 photograph at the full width
   of a wide column would be over a thousand pixels tall and could not be seen
   without scrolling, so the gallery stops growing and centres instead. */
:root { --pdp-stage-w: 560px; }
.pdp-media {
  display: grid; grid-template-columns: 76px minmax(0, var(--pdp-stage-w));
  gap: 14px; align-items: start; justify-content: center;
}

/* One picture means no rail, so the grid drops the rail's column instead of
   leaving the stage sitting in a 76px slot. */
.pdp-media--norail { grid-template-columns: minmax(0, var(--pdp-stage-w)); }

.pdp-rail { display: flex; flex-direction: column; gap: 10px; }
.pdp-th {
  /* 2:3 is exactly right for a commissioned frame, which is always 2:3. */
  aspect-ratio: 2 / 3; width: 100%; padding: 0; border: 0; cursor: pointer;
  background: var(--pdp-canvas); border-radius: 8px; overflow: hidden;
  outline: 2px solid transparent; outline-offset: -2px; transition: outline-color .12s;
}
/* The thumbnails are shown whole too, for the same reason as the stage: a
   commissioned frame is 2:3 and so is the tile, so `contain` and `cover` agree
   — but `contain` also stays correct if a frame ever arrives at another ratio,
   where `cover` would silently trim it. */
.pdp-th img { width: 100%; height: 100%; object-fit: contain; display: block; filter: var(--wt-img-filter); }
.pdp-th:hover { outline-color: var(--pdp-canvas-line); }
/* The selected state is a ring INSIDE the tile. Drawn outside it is clipped by
   the neighbouring thumbnails and reads as lopsided, which is the exact thing
   Kaʻo called "weird off balance" on the old rail. */
.pdp-th.is-on { outline-color: var(--wt-accent); }
.pdp-th:focus-visible { outline: 2px solid var(--wt-link); outline-offset: 2px; }

/* THE FALLBACK RAIL IS SQUARE, AND CONTAINS. When a product has no people
   photography every tile is a print-partner mockup, which is square: cropping
   it to 2:3 cuts a third off the garment's top and bottom. */
.pdp-rail--product .pdp-th { aspect-ratio: 1 / 1; }
.pdp-rail--product .pdp-th img { object-fit: contain; }

/* THE PHOTOGRAPH IS SHOWN WHOLE, AND AT A SIZE THAT DOES NOT MOVE.
   Kaʻo, 2026-08-23: "The main image should be the exact aspect ratio of the
   photos. I can see that is cropped off... It also does a weird thing where
   more of the image gets cropped off when the window is smaller. Nike shows the
   full aspect ratio of the image and also doesn't change when the window size
   changes."

   Both faults had one cause. The frame was `aspect-ratio: 2/3` with a
   `max-height: 78vh` cap, and `object-fit: cover` on the image. On a short
   window the vh cap won, the box became shorter than 2:3, and cover ate the
   difference off the top and bottom — so the crop grew as the window shrank.

   Now: the box is the photograph's own 2:3, the image is `contain` so it can
   never be cropped whatever it is, and the size is capped in PIXELS rather than
   viewport units, which is what Nike does (their carousel is a fixed 669px
   tall). Resizing the window no longer changes the framing at all. */
.pdp-stage { position: relative; }
.pdp-frame {
  display: block; width: 100%; padding: 0; border: 0;
  background: var(--pdp-canvas); border-radius: 12px; overflow: hidden;
  aspect-ratio: 2 / 3; position: relative;
}
.pdp-frame img { width: 100%; height: 100%; object-fit: contain; display: block; filter: var(--wt-img-filter); }
/* THE ONE PLACE A CROP IS WANTED. Kaʻo, 2026-08-24: on a page that HAS
   photographs of people, "have the product photos zoomed/cropped in to be the
   same aspect ratio as the people photos". The stage on such a page is the
   photographs' 2:3, and a square mockup contained inside it sat in two dead
   bands above and below. Cropping it to fill is better than letterboxing it.
   This class is only ever set on a page that has photography; where there is
   none the stage is already the mockup's own square and nothing is cropped,
   which is what he asked to leave as it is for now. */
.pdp-frame.is-crop img { object-fit: cover; }

/* A MOCKUP IS SQUARE. A 2:3 stage either crops a third off it or letterboxes
   it inside two dead bands, and the letterbox is what a page with no people
   photography was showing: a small shirt marooned in a tall empty frame. So
   when the gallery has fallen back to mockups the stage is square too, and the
   product fills the space it is given. */
.pdp-media--product .pdp-frame { aspect-ratio: 1 / 1; }

/* THE MOCKUPS CARRY THEIR OWN WHITE BACKGROUND, baked into the pixels, so a
   neutral card behind them cannot reach it. In dark mode that is a bright
   rectangle on a dark page. Dimming the mockup — and ONLY the mockup, never a
   commissioned photograph, and never in light mode — takes that white down to
   a soft grey while leaving the garment's own colour readable. It is the one
   fix available without reprocessing the whole catalog's imagery. */
html[data-mode="batman"] .pdp-media--product .pdp-frame img,
html[data-mode="batman"] .pdp-rail--product .pdp-th img,
html[data-mode="batman"] .pdp-swipe--product img,
html[data-mode="batman"] .pdp-card__m img { filter: brightness(.84) contrast(1.03); }
/* NIKE'S ARROWS: a pair of circles at the foot of the picture, over the image
   rather than beside it, so the gallery keeps its full width. They never carry
   a disabled state because they wrap. */
.pdp-arrows { position: absolute; right: 14px; bottom: 14px; display: flex; gap: 10px; }
.pdp-arrows button {
  width: 44px; height: 44px; border-radius: 999px; cursor: pointer;
  display: grid; place-items: center;
  background: var(--wt-surface); color: var(--wt-ink);
  border: 1px solid var(--pdp-canvas-line); box-shadow: var(--pdp-lift);
  transition: background .12s, transform .1s;
}
.pdp-arrows button:hover { background: var(--pdp-canvas); }
.pdp-arrows button:active { transform: scale(.94); }
.pdp-arrows button:focus-visible { outline: 3px solid var(--wt-link); outline-offset: 2px; }
.pdp-arrows svg { width: 21px; height: 21px; }
/* OPTICAL CENTRING, NOT GEOMETRIC. Kaʻo, 2026-08-24: "move them slightly
   outwards in the circle so they are visually centered."
   A chevron is geometrically centred in its box already, but its visual mass
   sits toward the open arms rather than the point, so a left chevron reads as
   pushed right and a right chevron as pushed left. Nudging each one outwards by
   a pixel and a half puts the POINT nearer the middle, which is what the eye
   reads as centred. The same correction applies to the rail's arrows below,
   which use the same two glyphs. */
.pdp-arrows button[data-pdp-step="-1"] svg,
.pdp-rel__nav button[data-pdp-scroll="-1"] svg { transform: translateX(-1.5px); }
.pdp-arrows button[data-pdp-step="1"] svg,
.pdp-rel__nav button[data-pdp-scroll="1"] svg { transform: translateX(1.5px); }

/* The phone's swipe track. Hidden on a wide screen; it IS the gallery on a
   narrow one, because a rail of 76px thumbnails on a phone is a row of stamps. */
.pdp-swipe { display: none; }
.pdp-dots { display: none; }

/* =====================================================================
   THE BUY COLUMN
   ===================================================================== */
.pdp-buy { min-width: 0; }
.pdp-buy__in { position: static; }

.pdp-title {
  font: 700 clamp(21px, 1.7vw, 25px)/1.24 var(--wt-font-ui);
  color: var(--wt-ink); margin: 0; letter-spacing: -.005em;
}
/* The gray line under the title is the garment, by its real name, so a shopper
   can tell a women's tri-blend from a unisex jersey without opening anything. */
.pdp-sub { font-size: 15.5px; line-height: 1.45; color: var(--wt-ink-quiet); margin: 5px 0 0; }
.pdp-price { font: 600 17px/1.4 var(--wt-font-ui); color: var(--wt-ink); margin: 16px 0 0; }

/* The two savings lines sit where Nike puts financing: directly under the
   price, before anything is chosen, because that is when somebody decides
   whether this is for them. */
.pdp-save { margin: 8px 0 0; }
.pdp-save__row { font-size: 13.5px; line-height: 1.55; color: var(--wt-ink-soft); margin: 2px 0 0; }
.pdp-save__row b { color: var(--wt-ink); font-weight: 700; }
.pdp-save__row a { color: var(--wt-link); text-decoration: underline; text-underline-offset: 2px; }
.pdp-save__row a:hover { color: var(--wt-link-hover); }
.pdp-save__q { color: var(--wt-ink-quiet); }

/* ---------- an option row ---------- */
.pdp-opt { margin-top: 26px; }
.pdp-opt__hd { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 11px; }
.pdp-opt__lab { font: 600 15px/1.3 var(--wt-font-ui); color: var(--wt-ink); }
.pdp-opt__pick { font-size: 14px; color: var(--wt-ink-quiet); text-align: right; }
/* The colour row reads as one phrase, so its two halves sit together on the
   left. The size row keeps space-between, because its right-hand half is the
   Size guide control rather than an answer to the label. */
.pdp-opt__hd--inline { justify-content: flex-start; gap: 6px; }
.pdp-opt__hd--inline .pdp-opt__pick { text-align: left; font-size: 15px; }

/* ---------- colour swatches ---------- */
/* NINE TO A ROW, ALWAYS. Kaʻo, 2026-08-24: "show 2 full rows of 9, no gaps."
   Wrapping flex fitted as many as the width allowed, which happened to be nine
   at this column width but left the second row ragged at sixteen and would
   silently become eight or ten if the column ever changed. A nine-column grid
   makes the count a decision rather than a coincidence, and the swatches size
   themselves to fill the row exactly. */
.pdp-sws { display: grid; grid-template-columns: repeat(9, minmax(0, 1fr)); gap: 10px; }
/* 53 colours is more range than Nike shows anywhere, and worth showing — but as
   one wall it becomes the tallest thing in the column and pushes Add to bag
   under the fold. So 16 are open and the rest are one control away. */
.pdp-sws:not(.is-open) .pdp-sw--extra { display: none; }
.pdp-sw {
  width: 100%; aspect-ratio: 1; height: auto; min-width: 26px;
  padding: 0; cursor: pointer; border-radius: 999px;
  background: var(--sw); color: var(--sw-ink);
  /* A hairline in the swatch's own ink keeps White and Soft Cream from
     disappearing into the page. */
  border: 1px solid rgba(38, 48, 43, .22);
  display: grid; place-items: center; position: relative;
  transition: transform .1s, box-shadow .12s;
}
html[data-mode="batman"] .pdp-sw { border-color: rgba(236, 231, 220, .26); }
.pdp-sw:hover { transform: scale(1.06); }
/* SELECTED IS A RING PLUS A TICK, and the tick carries its own ink. Kaʻo,
   2026-08-20: "Selecting a color should be obvious that it is selected.
   Checkmark in high contrast to background." A fixed white tick vanishes on
   Silver and a fixed dark one vanishes on Black, so kc-pdp.js computes each
   swatch's ink from its own relative luminance by the WCAG formula. */
.pdp-sw.is-on { box-shadow: 0 0 0 2px var(--wt-page-bg), 0 0 0 4px var(--wt-accent); }
.pdp-sw__t { width: 13px; height: 13px; display: block; }
.pdp-sw.is-on .pdp-sw__t {
  background: currentColor;
  -webkit-mask: no-repeat center/13px url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round' d='M5 13l4.5 4.5L19 7'/%3E%3C/svg%3E");
  mask: no-repeat center/13px url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round' d='M5 13l4.5 4.5L19 7'/%3E%3C/svg%3E");
}
.pdp-sw:focus-visible { outline: 2px solid var(--wt-link); outline-offset: 3px; }

/* ---------- sizes ---------- */
.pdp-sizes { display: grid; grid-template-columns: repeat(auto-fill, minmax(78px, 1fr)); gap: 9px; }
.pdp-size {
  min-height: 48px; padding: 12px 8px; cursor: pointer;
  font: 500 14.5px/1.2 var(--wt-font-ui); color: var(--wt-ink);
  background: transparent; border: 1px solid var(--wt-field-border); border-radius: 6px;
  transition: border-color .12s, background .12s;
}
.pdp-size:hover { border-color: var(--wt-ink); }
/* Chosen is a heavier edge in the accent plus a tint, which is a different
   visual language from the focus ring below, so the two states never read as
   the same thing stacked twice. */
.pdp-size.is-on { border-color: var(--wt-accent); border-width: 2px; background: var(--wt-panel-bg); font-weight: 700; padding: 11px 7px; }
.pdp-size:focus-visible { outline: 2px solid var(--wt-link); outline-offset: 2px; }

/* ---------- the quiet text link Nike uses everywhere ---------- */
.pdp-link {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: 600 13.5px/1.4 var(--wt-font-ui); color: var(--wt-ink);
  text-decoration: underline; text-underline-offset: 3px;
  display: inline-flex; align-items: center; gap: 6px;
}
.pdp-link:hover { color: var(--wt-link); }
.pdp-link:focus-visible { outline: 2px solid var(--wt-link); outline-offset: 3px; border-radius: 3px; }
/* SIZE GUIDE SITS ON THE HEADER'S BASELINE, AND IS NOT AN UNDERLINED LINK.
   Kaʻo, 2026-08-24: "have the words be on the same baseline as the header and
   not an underlined link... keep the hover state." So it matches the label's
   size and weight, drops the rule under it, and keeps colour on hover. The icon
   is reordered in front of the text by CSS rather than in the markup, because
   an inline-flex box takes its baseline from its FIRST flex item and an SVG has
   none: icon-first put the whole control off the baseline. */
.pdp-link--guide {
  font-size: 15px; text-decoration: none; align-items: baseline;
}
.pdp-link--guide svg { width: 22px; height: 22px; order: -1; align-self: center; }
.pdp-link--guide:hover { color: var(--wt-link); }
.pdp-link--guide:hover span { text-decoration: underline; text-underline-offset: 3px; }
.pdp-link--more { margin-top: 12px; }
.pdp-link--details { margin-top: 14px; }

/* ---------- Klarna ---------- */
/* Nike's financing line: centred, two lines, the wordmark sitting on the
   baseline between "with" and the link. The measure is capped so it breaks
   where Nike's breaks instead of running the full width of the column. */
/* ---------- buy now, pay later ----------
   Renamed from .pdp-klarna on 2026-08-25: the provider is Shop Pay now, and a
   class named after a vendor we do not use is a trap for the next person. */
.pdp-bnpl {
  font-size: 13.5px; line-height: 1.7; color: var(--wt-ink-soft);
  margin: 22px auto 0; text-align: center; max-width: 36ch;
}
.pdp-bnpl b { color: var(--wt-ink); font-weight: 700; }

/* THE SHOP PAY MARK TAKES THE PAGE INK. Kaʻo, 2026-08-25: "purple is too
   distracting. White on dark and black on light." Shopify's lockup is white on
   #5a31f4, which against a product page reads as a button rather than as part
   of a sentence. The letterforms are Shopify's, untouched; only the colour
   changes, which is what a monochrome brand version is.

   currentColor does the whole job. The "shop" lettering takes the ink, and the
   "Pay" chip's path draws its rounded box and knocks the letters out of it, so
   the chip takes the ink and the page shows through the letters. One asset,
   both themes, no switch. A logotype carries no contrast requirement under
   WCAG 1.4.3, but it lands on --wt-ink-soft either way and clears it anyway.

   Vertical alignment is set against the text baseline rather than the line box
   so it sits ON the sentence instead of floating above it. */
.pdp-bnpl__logo {
  height: 1.35em; width: auto; vertical-align: -0.28em; margin: 0 3px;
  color: inherit; fill: currentColor;
}
/* Klarna's wordmark is a single path and DOES need currentColor: it is ink in
   day mode and paper in batman rather than a black glyph on a dark page.
   Retained because Klarna reaches the US in 2026. */
.pdp-klarna__logo {
  height: .95em; width: auto; vertical-align: -0.08em; margin: 0 2px;
  color: var(--wt-ink); fill: currentColor;
}
.pdp-bnpl__cta {
  color: var(--wt-ink); text-decoration: underline; text-underline-offset: 3px;
  white-space: nowrap;
}
.pdp-bnpl__cta:hover { color: var(--wt-link); }
.pdp-bnpl__cta:focus-visible { outline: 2px solid var(--wt-link); outline-offset: 2px; border-radius: 3px; }

/* ---------- the two buttons ----------
   Nike's stack, our colours: a filled primary and an outlined secondary, both
   full width, both a real pill. NOT black — the green IS the design system. */
.pdp-cta {
  display: block; width: 100%; margin-top: 20px; cursor: pointer;
  min-height: 58px; padding: 17px 24px; border: 0; border-radius: 999px;
  font: 700 16px/1.2 var(--wt-font-ui);
  background: var(--wt-btn-bg); color: var(--wt-btn-ink);
  transition: background .12s;
}
.pdp-cta:hover:not(:disabled) { background: var(--wt-btn-bg-hover); }
.pdp-cta:focus-visible { outline: 3px solid var(--wt-link); outline-offset: 3px; }
/* Disabled is quiet, not invisible: it still has to be readable, because it is
   what somebody is looking at while they work out what is missing. The needs
   line underneath tells them. */
.pdp-cta:disabled { cursor: not-allowed; background: var(--pdp-canvas); color: var(--wt-ink-quiet); box-shadow: inset 0 0 0 1px var(--pdp-canvas-line); }

.pdp-fav {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  width: 100%; margin-top: 11px; cursor: pointer;
  min-height: 58px; padding: 17px 24px; border-radius: 999px;
  border: 1.5px solid var(--wt-field-border); background: transparent;
  font: 600 16px/1.2 var(--wt-font-ui); color: var(--wt-ink);
  transition: border-color .12s;
}
.pdp-fav:hover { border-color: var(--wt-ink); }
.pdp-fav:focus-visible { outline: 3px solid var(--wt-link); outline-offset: 3px; }
/* THE SAME HEART AS THE POSTERS WALL. Kaʻo, 2026-08-24: "Have this be the same
   exact color/shape for the heart on hover/clicked... maintain this button shape
   but have the red come through in light and dark mode."

   #e23b54 is lifted from .kc-fav--heart in cdo-watchtower.css, which is what the
   posters wall uses, so the two surfaces cannot drift. It is a fixed red rather
   than a token on purpose: a heart that turned green in one theme and red in the
   other would not be the same heart. Measured on both grounds: 4.6:1 on the warm
   paper and 5.2:1 on the batman page, so it carries its own weight as a control
   colour in either mode.

   The BUTTON keeps its shape and its label; only the heart and the edge take the
   red, which is exactly the posters-wall behaviour scaled up to a pill. */
.pdp-fav svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.7px; }
/* THE LABEL DOES NOT TURN RED. #e23b54 measures 3.84:1 on the warm paper and
   4.17:1 on the batman page: fine for a control edge or an icon, which owe 3:1,
   and short of the 4.5:1 that the word "Favorite" owes as text. The posters wall
   sets `color` red because its control is an icon with no words in it; this one
   has a label, so only the heart and the edge take the red. */
.pdp-fav:hover { border-color: #e23b54; }
.pdp-fav:hover svg { stroke: #e23b54; }
.pdp-fav.is-on { border-color: #e23b54; }
.pdp-fav.is-on svg { fill: #e23b54; stroke: #e23b54; }

.pdp-needs { font-size: 13.5px; line-height: 1.5; color: var(--wt-ink-soft); margin: 11px 0 0; text-align: center; min-height: 1px; }

/* ---------- shipping and returns ----------
   Nike's Shipping / Free Pickup pair. We have no stores, so the second block is
   Returns — which until now had no link a shopper could reach, on a shop that
   takes real money. */
.pdp-ship { margin-top: 30px; padding-top: 26px; border-top: 1px solid var(--wt-rule); display: grid; gap: 18px; }
.pdp-ship b { display: block; font: 600 15px/1.4 var(--wt-font-ui); color: var(--wt-ink); }
.pdp-ship span { display: block; font-size: 14px; line-height: 1.55; color: var(--wt-ink-soft); margin-top: 3px; }
.pdp-ship a { color: var(--wt-link); text-decoration: underline; text-underline-offset: 2px; }

/* ---------- description ---------- */
.pdp-desc { margin-top: 30px; font-size: 14.5px; line-height: 1.6; color: var(--wt-ink-soft); }
.pdp-desc p { margin: 0; }
.pdp-desc ul { margin: 14px 0 0; padding-left: 18px; }
.pdp-desc li { margin-top: 4px; }
.pdp-desc b { color: var(--wt-ink); font-weight: 600; }

/* ---------- accordions ---------- */
.pdp-accs { margin-top: 26px; }
.pdp-acc { border-top: 1px solid var(--wt-rule); }
.pdp-acc:last-child { border-bottom: 1px solid var(--wt-rule); }
.pdp-acc > summary {
  list-style: none; cursor: pointer; padding: 19px 0;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  font: 600 15.5px/1.3 var(--wt-font-ui); color: var(--wt-ink);
}
.pdp-acc > summary::-webkit-details-marker { display: none; }
.pdp-acc > summary:focus-visible { outline: 2px solid var(--wt-link); outline-offset: -2px; border-radius: 4px; }
.pdp-acc > summary svg { width: 20px; height: 20px; flex: 0 0 auto; transition: transform .18s; color: var(--wt-ink-soft); }
.pdp-acc[open] > summary svg { transform: rotate(180deg); }
.pdp-acc__b { padding: 0 0 20px; font-size: 14.5px; line-height: 1.6; color: var(--wt-ink-soft); }
.pdp-acc__b p { margin: 0 0 10px; }
.pdp-acc__b p:last-child { margin-bottom: 0; }
.pdp-acc__b b { color: var(--wt-ink); font-weight: 600; }
.pdp-acc__b a { color: var(--wt-link); text-decoration: underline; text-underline-offset: 2px; }

/* =====================================================================
   THE RAILS
   Two, because they answer different questions: "I want this phrase, but as a
   hoodie" and "show me something else".
   ===================================================================== */
.pdp-rel { max-width: 1360px; margin: 56px auto 0; padding: 0 20px; }
.pdp-rel__hd { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 18px; }
.pdp-rel__hd h2 { font: 700 clamp(18px, 1.5vw, 22px)/1.3 var(--wt-font-ui); color: var(--wt-ink); margin: 0; }
.pdp-rel__nav { display: flex; gap: 8px; }
.pdp-rel__nav button {
  width: 42px; height: 42px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--wt-field-border); background: transparent; color: var(--wt-ink);
  display: grid; place-items: center;
}
.pdp-rel__nav button:hover { background: var(--pdp-canvas); }
.pdp-rel__nav button:focus-visible { outline: 2px solid var(--wt-link); outline-offset: 2px; }
.pdp-rel__nav svg { width: 20px; height: 20px; }
/* A SCROLLING TRACK'S COLUMNS MUST NOT BE ALLOWED TO SHRINK. With
   `minmax(0, …)` the grid satisfies twelve cards inside the container by
   collapsing every one of them toward zero instead of overflowing, so the
   twelve-card rail rendered as a row of thumbnails 68px wide while the
   four-card rail above it looked right. A single track size cannot shrink, so
   the row overflows and scrolls, which is the point of a carousel. */
.pdp-rel__track {
  display: grid; grid-auto-flow: column; grid-auto-columns: 230px;
  gap: 16px; overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; padding-bottom: 4px;
}
.pdp-rel__track::-webkit-scrollbar { display: none; }
@media (min-width: 1100px) { .pdp-rel__track { grid-auto-columns: calc(25% - 12px); } }

.pdp-card { scroll-snap-align: start; text-decoration: none; color: inherit; display: block; }
/* THE RAIL SHOWS THE WHOLE PHOTOGRAPH, LIKE EVERYTHING ELSE ON THIS PAGE.
   Kaʻo, 2026-08-24: "These need to be full height." The cards were a 1:1 box
   with object-fit:cover holding 2:3 portraits, so a third of every photograph
   was thrown away: heads cropped at the top, legs at the bottom. The same
   mistake the main stage had, in a different place.

   So the card is the photograph's own 2:3 and the image is contained. `contain`
   rather than `cover` because the rail can also be fed square print-partner
   mockups when the co-purchase list returns one, and those must not be trimmed
   either; they sit on the neutral card the way they do in the gallery. */
.pdp-card__m {
  display: block; aspect-ratio: 2 / 3; background: var(--pdp-canvas);
  border-radius: 10px; overflow: hidden; margin-bottom: 9px;
}
.pdp-card__m img { width: 100%; height: 100%; object-fit: contain; display: block; filter: var(--wt-img-filter); transition: transform .3s; }
/* The zoom on hover would push the picture past the edges it is contained
   inside, which is the crop coming back in another form. */
.pdp-card:hover .pdp-card__m img { transform: none; }
.pdp-card:hover .pdp-card__t { text-decoration: underline; text-underline-offset: 3px; }
/* Two lines, then an ellipsis: a phrase like KEEP CALM AND FIND YOUR PEOPLE
   runs to four lines in a 230px card and shoves the price out of line with
   every other card in the row. */
/* NO RESERVED SECOND LINE. Kaʻo, 2026-08-24: "Let's move the prices up for the
   carousel." The title reserved two lines so prices lined up across cards, but
   almost every phrase fits on one, so the reservation showed as a hole under
   every title. The clamp stays, so a long phrase still stops at two lines
   rather than pushing the card out of shape; only the empty reservation goes. */
.pdp-card__t {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  font: 600 14.5px/1.35 var(--wt-font-ui); color: var(--wt-ink);
}
.pdp-card__p { display: block; font-size: 14px; color: var(--wt-ink-quiet); margin-top: 2px; }
.pdp-card:focus-visible { outline: 3px solid var(--wt-link); outline-offset: 4px; border-radius: 12px; }

/* =====================================================================
   THE FLOATING BAR (phones only)
   It appears once the real Add to bag has scrolled off, so nothing covers the
   photographs while somebody is looking at them.
   ===================================================================== */
.pdp-bar { display: none; }

/* =====================================================================
   DIALOGS
   ===================================================================== */
/* EVERY OVERLAY IS IN OUR TYPE. Kaʻo, 2026-08-24: "Make sure all overlays are
   using all of our fonts. No deviations across the entire experience."

   The size guide was rendering in Times. This site's body sets NO font-family
   on purpose, so anything appended to document.body inherits nothing and falls
   to the browser default serif. A dialog is appended to body precisely so it
   can sit above everything, which is exactly what put it outside the shell that
   carries the type. It therefore has to name the family itself, and the tokens
   too, because those are scoped to .wt-shell for the same reason.

   Any future overlay this page adds must set --wt-* and the family here, or it
   will land in Times as well. */
.pdp-guide, .pdp-guide * { font-family: var(--wt-font-ui, "Montserrat", system-ui, sans-serif); }
.pdp-guide {
  --wt-font-ui: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.pdp-guide {
  position: fixed; inset: 0; z-index: 2147483000; display: none;
  background: rgba(20, 24, 22, .82); backdrop-filter: blur(2px);
  padding: 24px; place-items: center;
}
.pdp-guide.is-on { display: grid; }
.pdp-guide__x {
  position: absolute; top: 18px; right: 18px; width: 46px; height: 46px; cursor: pointer;
  border-radius: 999px; border: 1px solid var(--pdp-canvas-line);
  background: var(--wt-surface); color: var(--wt-ink); display: grid; place-items: center;
}
.pdp-guide__x svg { width: 21px; height: 21px; }
.pdp-guide__x:focus-visible { outline: 3px solid var(--wt-link); outline-offset: 2px; }

.pdp-guide__box {
  position: relative; background: var(--wt-surface); color: var(--wt-ink);
  border-radius: 14px; padding: 34px 30px 30px; max-width: 560px; width: 100%;
  max-height: 88vh; overflow: auto; font-size: 14.5px; line-height: 1.6;
}
.pdp-guide__box h2 { font: 700 21px/1.3 var(--wt-font-ui); margin: 0 0 6px; }
.pdp-guide__g { color: var(--wt-ink-quiet); margin: 0 0 18px; font-size: 14px; }
.pdp-guide__n { color: var(--wt-ink-soft); font-size: 13.5px; margin: 14px 0 0; }
.pdp-guide__box > p { color: var(--wt-ink-soft); margin: 12px 0 0; }
.pdp-guide__x { top: 14px; right: 14px; }

.pdp-chart { width: 100%; border-collapse: collapse; margin-top: 6px; }
.pdp-chart th, .pdp-chart td { text-align: left; padding: 10px 8px; border-bottom: 1px solid var(--wt-rule); }
.pdp-chart th { font: 600 13px/1.3 var(--wt-font-ui); color: var(--wt-ink-quiet); text-transform: uppercase; letter-spacing: .04em; }
.pdp-chart__s { font-weight: 700; }

/* =====================================================================
   NARROW SCREENS
   Nike stacks; we stack AND swipe AND float the buy button, because most of
   this traffic is a phone and reaching back up a long page to buy is the most
   common reason a filled bag never happens.
   ===================================================================== */
/* THE TWO COLUMN LAYOUT IS ONLY USED WHERE THE PICTURE FITS AT FULL SIZE.
   Kaʻo, 2026-08-23: the picture "doesn't change when the window size changes".
   Cropping was the real fault and is fixed, but below about 1140px the grid was
   still squeezing the stage smaller (measured: 560 wide at 1280, 438 at 1100,
   362 at 1024). The two column view needs 20 + 76 rail + 14 gap + 560 stage +
   44 gap + 400 buy + 20 = 1134px to hold the picture at its intended size, so
   that is where it stops. Narrower than that gets the stacked layout, which
   shows the photograph full width instead of a shrunken one beside squeezed
   copy. Above it, the picture is 560x840 at every single width. */
@media (max-width: 1140px) {
  .pdp { grid-template-columns: 1fr; gap: 28px; padding: 0 0 8px; }
  .pdp-crumbs { padding-left: 20px; padding-right: 20px; }

  .pdp-media { grid-template-columns: 1fr; gap: 0; max-width: none; position: static; }
  /* The thumbnail rail and the single stage are the desktop gallery. */
  .pdp-rail, .pdp-frame { display: none; }

  .pdp-swipe {
    display: grid; grid-auto-flow: column; grid-auto-columns: 100%;
    overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none;
    background: var(--pdp-canvas);
  }
  .pdp-swipe::-webkit-scrollbar { display: none; }
  /* Same rule as the desktop stage: the photograph is never cropped, on any
     screen. */
  .pdp-swipe img {
    width: 100%; aspect-ratio: 2 / 3; object-fit: contain; display: block;
    scroll-snap-align: center; filter: var(--wt-img-filter);
  }
  .pdp-swipe--product img { aspect-ratio: 1 / 1; }

  .pdp-dots { display: flex; justify-content: center; gap: 7px; padding: 12px 0 0; }
  .pdp-dots i { width: 7px; height: 7px; border-radius: 999px; background: var(--wt-ink-quiet); opacity: .35; transition: opacity .15s; }
  .pdp-dots i.is-on { opacity: 1; background: var(--wt-accent); }

  .pdp-buy { padding: 0 20px; }
  /* Nothing sticks on a phone: there is no room beside the content for it to
     stick to, and the floating bar does this job instead. */
  .pdp-buy__in { position: static; }

  .pdp-rel { margin-top: 44px; }
  .pdp-rel__nav { display: none; }
  .pdp-rel__track { grid-auto-columns: 62%; }

  .pdp-bar {
    display: flex; align-items: center; gap: 12px;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
    padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
    background: var(--wt-surface); border-top: 1px solid var(--wt-rule);
    box-shadow: 0 -6px 20px rgba(20, 24, 22, .10);
  }
  .pdp-bar[hidden] { display: none; }
  .pdp-bar__p { font: 700 16px/1.2 var(--wt-font-ui); color: var(--wt-ink); flex: 0 0 auto; }
  .pdp-cta--bar { margin-top: 0; flex: 1 1 auto; min-height: 52px; padding: 15px 20px; }
  /* The bar sits over the foot of the page, so the last rail needs room to
     clear it rather than hiding behind it. */
  .pdp-rel:last-of-type { padding-bottom: 84px; }
}

/* A PHONE WANTS THE PICTURE FULL BLEED. A 1100px WINDOW DOES NOT.
   The stacked layout is used from 1140px down, so on a small desktop window it
   was rendering the photograph 1012px wide and 1518px tall, which is most of a
   screen's worth of scrolling for one image. Below 600px, which is a real
   phone, full bleed is right and stays. Between the two, the gallery holds the
   same 560px it has in the two column view and centres. Nothing is cropped in
   either case; only the width changes. */
@media (min-width: 601px) and (max-width: 1140px) {
  .pdp-media { max-width: 560px; margin-left: auto; margin-right: auto; }
  .pdp-swipe { border-radius: 12px; overflow-x: auto; }
  .pdp-buy { max-width: 560px; margin-left: auto; margin-right: auto; }
  .pdp-rel { max-width: 640px; margin-left: auto; margin-right: auto; }
}

/* Nine to a row still, but a tighter gap on a phone so each swatch stays a
   comfortable target rather than shrinking to make room for the gaps. */
@media (max-width: 600px) {
  .pdp-sws { gap: 7px; }
}

@media (max-width: 420px) {
  .pdp-sizes { grid-template-columns: repeat(auto-fill, minmax(64px, 1fr)); }
}

/* Somebody who asked their system not to animate gets no animation. */
@media (prefers-reduced-motion: reduce) {
  .pdp-sw, .pdp-card__m img, .pdp-acc > summary svg, .pdp-cta, .pdp-th { transition: none; }
  .pdp-sw:hover, .pdp-card:hover .pdp-card__m img { transform: none; }
}


/* =====================================================================
   THE GENERATED-MODEL LINE
   Kaʻo, 2026-08-25 chose the quiet treatment: nothing but the sentence, at the
   smallest size the page uses, left aligned on the page's own content edge,
   below the carousel.
   ===================================================================== */
/* THE DISCLOSURE SITS BACK. Kaʻo, 2026-08-25: "Make this a darker shade in
   dark mode and lighter shade in light mode so it is not so prominent."
   Its own token rather than --wt-ink-quiet, which is shared with eyebrows and
   captions across the site and should not be dimmed for all of them.

   These two values are the quietest this line can legally be. It is 12.5px, so
   WCAG asks 4.5:1 against the page, and a disclosure is the last text on a page
   that should be hard to read. Measured: #677167 on #f7f4ee is 4.63:1 and
   #7b867b on #161a18 is 4.63:1. Dark mode carries the visible change, dropping
   from 6.44:1. Going quieter than this fails AA.

   SIZE IS THE OTHER LEVER, and it is the one doing the work now. Colour ran out
   of room at the AA floor and the line still read too present, so it dropped to
   11px on 2026-08-25. Fine print reads as fine print because it is small and
   set apart, not because it is faint, and size costs no contrast. */
/* IT FLOATS IN THE DEAD SPACE. Kaʻo, 2026-08-25: "make it lower so it is
   floating in the empty space between the carousel and the footer."
   The page's own bottom padding leaves 112px between this line and the footer,
   at every width. Matching the top margin to it centres the line in that dead
   space, so it reads as a line sitting on its own rather than a caption
   belonging to the row of products above it. Measured, not guessed: 112 above
   and 112 below at 1440, 1200, 900 and 480. If the page's bottom padding ever
   changes, this number follows it. */
.pdp-disc {
  --pdp-disc-ink: #677167;
  max-width: 1360px; margin: 112px auto 0; padding: 0 20px 8px;
  font-size: 11px; line-height: 1.6; color: var(--pdp-disc-ink);
}

html[data-mode="batman"] .pdp-disc { --pdp-disc-ink: #7b867b; }

@media (max-width: 1140px) {
  .pdp-disc { max-width: 640px; }
}

/* THE SERVER-WRITTEN HERO. /api/product-page puts the product's h1, garment and
   price into the HTML so anything that does not run JavaScript still gets the
   content rather than the word "Loading". kc-pdp.js replaces it wholesale on
   render, so this styling is only ever seen for the moment before that, on a
   slow connection, or by a reader whose script failed. It is styled like the
   real hero rather than hidden: hiding it would defeat the point for the
   readers it exists for, and Google treats display:none text as suppressed. */
.pdp-seo-hero {
  max-width: 1360px; margin: 0 auto; padding: 28px 20px 0;
}
.pdp-seo-hero h1 {
  font-size: clamp(26px, 4vw, 40px); line-height: 1.1; margin: 0 0 6px;
  color: var(--wt-ink); letter-spacing: -0.01em;
}
.pdp-seo-hero p {
  margin: 0 0 4px; font-size: 15px; color: var(--wt-ink-soft);
}
