/* mygirlgotglamour - shared styles */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* Reserve the scrollbar's width whether or not one is showing.
   Without this, a page sitting within a few pixels of the viewport height
   can oscillate: content overflows, a scrollbar appears and takes ~15px of
   width, the landing wordmark's fitter re-measures the narrower box and
   sizes down, the page then fits, the scrollbar disappears, and it starts
   over - which reads as the screen shaking. Reserving the gutter removes
   the width change that drives the loop, so the layout cannot feed back
   into itself no matter what the artwork's proportions are. */
html { scrollbar-gutter: stable; }

/* The UA rule for [hidden] is only `display: none` at user-agent origin, so
   ANY author display declaration beats it. .brand-sort sets inline-flex,
   which meant the currency picker rendered as an empty dropdown whenever
   rates had not arrived - i.e. permanently, if the rate service is blocked. */
[hidden] { display: none !important; }

/* The hand-drawn sizing alphabet, traced from the Procreate sheet into a
   real font by tools/make-hand-font.py. It covers ONLY s m l x (both cases),
   0-9 and space - so it must never be declared alone. Anything it lacks
   silently falls back per-character, which would mix two faces inside one
   word; .size-mark below only opts in when the whole string is covered. */
@font-face {
  font-family: 'MGGG Hand';
  src: url('/fonts/mggg-hand.woff2') format('woff2'),
       url('/fonts/mggg-hand.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  --black: #111;
  --grey: #757575; /* AA contrast on white (4.6:1) */
  --light-grey: #e5e5e5;
  --sale: #c1272d;  /* deep red for discounted prices - 6:1 on white */
  --sans: 'Space Grotesk', "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: 'Share Tech Mono', 'OCR A Std', monospace;

  /* Height ÷ width of images/ui/shop_all_sign.png. The landing page reserves
     vertical space for the sign from this, so it MUST match the exported art
     - tools/make-procreate-art.py prints the correct figure and warns when
     this one has gone stale. */
  --shop-sign-aspect: 0.488;

  /* The sign's width, in one place. .landing-shop img sizes itself from
     these and .landing-signs subtracts the matching height, so the two can
     never drift apart the way they did when the width was written twice. */
  --shop-sign-w-min: 140px;
  --shop-sign-w-vw:  19vw;
  --shop-sign-w-max: 290px;
}

body {
  background: #fff;
  color: var(--black);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }

/* prevents the ~300ms double-tap-zoom delay on tap-heavy controls */
a, button { touch-action: manipulation; }

/* keyboard focus - deliberate, visible, aesthetic-consistent */
:focus-visible {
  outline: 1px solid var(--black);
  outline-offset: 3px;
}

/* screen-reader-only text */
/* Skip link. Thirteen controls sit between the top of /shop and the first
   product; landmarks cover screen-reader users, but a keyboard-only visitor
   without AT has no way past them. Off-screen until focused. */
.skip-link {
  position: absolute;
  left: 8px;
  top: -60px;
  z-index: 100;
  background: var(--black);
  color: #fff;
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 12px 16px;
  transition: top 0.12s ease;
}
.skip-link:focus { top: 8px; }
@media (prefers-reduced-motion: reduce) { .skip-link { transition: none; } }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* collapse animation for users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

/* ── HEADER ── */
.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
  gap: 10px;
  padding: 14px 16px;
  background: rgba(255,255,255,0.92);
  backdrop-filter: blur(4px);
}

.header-clock {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.05em;
  white-space: nowrap;
}

.header-logo {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-align: center;
  white-space: nowrap;
  /* the text is only ~13px tall, so the link needs padding of its own to
     reach a 24px target - it is the home link on every page */
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 5px 4px;
}
.header-logo:hover { color: var(--grey); }

/* Tap target: the padding grows the hit area, the negative margin keeps the
   visual position. Do NOT add a second `padding` below - a later declaration
   in the same rule silently wins and leaves the margin pulling the control
   out of place with no compensating padding. */
.header-cart {
  padding: 8px 0 8px 10px;
  margin: -8px 0 -8px -10px;
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: right;
  background: none;
  border: none;
  cursor: pointer;
  justify-self: end;
}
.header-cart:hover { color: var(--grey); }

.header-left {
  display: flex;
  align-items: baseline;
  gap: 14px;
}

/* menu button - mobile only; desktop shows everything inline */
.header-menu {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--black);
}
.header-menu:hover { color: var(--grey); }

/* mobile header: menu replaces the clock (clock lives inside the menu) */
@media (max-width: 560px) {
  .site-header { padding: 12px 10px; gap: 6px; }
  .header-menu { display: block; padding: 6px 8px 6px 0; }
  .header-clock { display: none; }
  .header-logo { font-size: 10px; letter-spacing: 0.14em; }
  .header-cart { font-size: 10px; }
}

/* ── MOBILE MENU OVERLAY ── */
.menu-overlay {
  position: fixed;
  inset: 0;
  z-index: 300;
  background: #fff;
  display: flex;
  flex-direction: column;
  padding: 12px 16px;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.2s ease, visibility 0s linear 0.2s;
}
.menu-overlay.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.2s ease;
}
/* Backstop only. The real lock is MGGGModal in site.js pinning the body
   with position:fixed - `overflow: hidden` does not stop touch scrolling in
   iOS Safari, which is why the grid used to scroll behind the open menu. */
body.menu-open { overflow: hidden; }

.menu-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 48px;
}
.menu-clock {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.05em;
}
.menu-close {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 22px;
  line-height: 1;
  padding: 4px 8px;
  color: var(--black);
}

.menu-links {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.menu-links a {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 10px 0;
}
.menu-links a:hover { color: var(--grey); }

/* ── MAIN GRID ── */
main { padding: 72px 16px 60px; }
@media (max-width: 560px) { main { padding: 60px 10px 40px; } }

.product-grid {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  column-gap: 12px;
  row-gap: 44px;
}
@media (max-width: 1100px) {
  .product-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 760px) {
  .product-grid { grid-template-columns: repeat(2, 1fr); column-gap: 8px; row-gap: 32px; }
}

/* ── PRODUCT CARD ── */
.card { position: relative; }

.card-media {
  position: relative;
  aspect-ratio: 3 / 4;
  background: #f7f7f7;
  overflow: hidden;
}
/* the link covers the image only - the add-to-cart button sits beside it,
   never inside it, so we don't nest a button within an anchor */
.card-media-link {
  position: absolute;
  inset: 0;
  display: block;
}
.card-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 4%;
  transition: opacity 0.25s ease;
}
.card-media .img-detail { opacity: 0; }
/* The crossfade only runs once the detail photo has actually decoded.
   Without the .detail-ready gate the fade started at the same instant the
   download did, so the first hover on every card faded the visible photo
   out to an empty box for as long as the fetch took. */
.card.detail-ready:hover .card-media .img-detail { opacity: 1; }
.card.detail-ready:hover .card-media .img-main.has-detail { opacity: 0; }

/* size/condition tags - hover reveal on desktop */
.card-hoverinfo {
  position: absolute;
  left: 10px;
  bottom: 10px;
  z-index: 2;
  display: flex;
  gap: 6px;
  opacity: 0;
  transition: opacity 0.2s ease;
  pointer-events: none;
}
.card:hover .card-hoverinfo { opacity: 1; }
.card-hoverinfo span {
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--black);
  padding: 0;
}

/* touch devices have no hover - always show the tags
   (pointer: coarse catches devices that misreport hover support) */
@media (hover: none), (pointer: coarse) {
  .card-hoverinfo { opacity: 1; }
  .card-hoverinfo span { font-size: 11px; padding: 0; }
  .card-hoverinfo .size-word { height: 18px; }
}

/* SOLD badge - always visible */
.sold-badge {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  background: var(--black);
  color: #fff;
  padding: 4px 9px;
}
/* Dim sold items with `filter`, not `opacity` - the crossfade owns the
   opacity property, and an opacity rule here outranks `.img-detail { opacity: 0 }`
   and leaves both photos stacked on top of each other. */
.card.is-sold .card-media img { filter: opacity(0.45); }

/* ── ADD TO CART (hand-drawn cart, beside the item's name) ──
   Always visible rather than hover-revealed: it's the primary action on
   the card and hiding it would make it undiscoverable on touch. */
.card-add {
  position: relative;
  flex: 0 0 auto;
  padding: 4px;
  background: none;
  border: none;
  cursor: pointer;
  line-height: 0;
  opacity: 0.8;
  transition: opacity 0.18s ease, transform 0.18s ease;
}
.card-add img {
  width: 32px;
  height: auto;
  display: block;
  /* tipped back on its rear wheels - the cart pulling a wheelie.
     Rotation lives on the image so the button is free to scale on hover
     without the two transforms fighting. */
  transform: rotate(-14deg);
  transform-origin: 30% 85%;      /* pivot on the back wheel */
  transition: transform 0.18s ease;
}
.card-add:hover { opacity: 1; transform: scale(1.1); }
.card-add:hover img { transform: rotate(-22deg); }   /* pop the wheelie further */
.card-add:active { transform: scale(0.94); }
.card-add.is-added { opacity: 1; }
.card-add.is-added::after {
  content: '';
  position: absolute;
  right: 0;
  top: 0;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--sale);
}

@media (max-width: 560px) {
  .card-add img { width: 25px; }
}
@media (prefers-reduced-motion: reduce) {
  .card-add img, .card-add:hover img { transition: none; }
}

/* the photo ghost that flies to the cart on add */
.fly-ghost {
  position: fixed;
  z-index: 400;
  object-fit: contain;
  pointer-events: none;
  transition: transform 0.62s cubic-bezier(0.45, 0.05, 0.3, 1), opacity 0.62s ease-in;
  will-change: transform, opacity;
}

/* small acknowledgement on the cart button when a ghost lands */
@keyframes cart-bump {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.22); }
  100% { transform: scale(1); }
}
.header-cart.is-bumped { animation: cart-bump 0.36s ease; }

@media (prefers-reduced-motion: reduce) {
  .fly-ghost { display: none; }
  .header-cart.is-bumped { animation: none; }
}

/* ── CARD TEXT ── */
/* text block and the cart button sit on one row; the text still centres
   within the space it's given */
.card-info {
  padding-top: 10px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.card-text {
  flex: 1;
  min-width: 0;
  text-align: center;
}

.card-brand {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: 3px;
}
/* An <h2> so the grid can be navigated by heading in a screen reader.
   Weight is reset because a heading would otherwise come out bold. */
.card-title {
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.05em;
  margin-bottom: 6px;
}
.card-price {
  font-size: 11px;
  letter-spacing: 0.08em;
  /* Not --grey. At this size that computed to 4.61:1, clearing AA by 0.11 -
     too fine a margin for the one number a shopper is actually looking for.
     #5c5c5c takes it to about 7:1 while staying quieter than the title. */
  color: #5c5c5c;
}
/* sold: price is dropped entirely, name struck through */
.card.is-sold .card-brand,
.card.is-sold .card-title { text-decoration: line-through; }

/* ── SALE PRICING ──
   Old price struck through in grey, new price in red. Red is reserved
   entirely for discounts here - the rest of the site stays monochrome,
   which is what lets a single sale item catch the eye in the grid.
   Change --sale in :root to restyle every discount at once. */
.card-price.is-sale .price-was,
.pdp-price.is-sale .price-was {
  text-decoration: line-through;
  color: var(--grey);
  margin-right: 8px;
}
.card-price.is-sale .price-now,
.pdp-price.is-sale .price-now {
  color: var(--sale);
}

/* optional corner badge - enabled by SALE_BADGE in shop.html.
   Red so it never reads as the black SOLD badge at a glance. */
.sale-badge {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  background: var(--sale);
  color: #fff;
  padding: 4px 9px;
}

@media (max-width: 560px) {
  .card-brand { font-size: 10px; letter-spacing: 0.1em; }
  .card-title, .card-price { font-size: 10px; }
}

/* ── LANDING PAGE ──
   top-aligned, left-aligned: clock, huge wordmark, Shop →,
   credits list, brand marquee anchoring the bottom */
.landing {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 18px 20px 0;
  overflow-x: hidden; /* marquee is full-bleed via negative margins */
}

/* top row: clock left, credits right */
.landing-top {
  align-self: stretch;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  margin-bottom: 8px;
}

.landing-top-left {
  display: flex;
  align-items: baseline;
}

.landing-clock {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.05em;
}

/* sized to run nearly edge-to-edge on any viewport */
.landing-wordmark {
  margin: 0;
  align-self: stretch;
  font-family: var(--sans);
  font-size: clamp(30px, 9.6vw, 300px);
  font-weight: 700;
  letter-spacing: -0.035em;
  /* a touch of room: the rotating faces have taller ascenders and deeper
     descenders than Space Grotesk and would otherwise clip */
  line-height: 1.02;
  white-space: nowrap;
  /* the rotating faces each fill the width at a different size; JS pins a
     min-height to the tallest and this keeps the line centred within it */
  display: flex;
  align-items: center;
}
.landing-wordmark a:hover { color: var(--grey); }

/* hand-drawn "shop all" tag under the wordmark */
.landing-shop {
  display: inline-block;
  margin-left: 2px;
  padding: 10px 12px 10px 0;   /* comfortable tap target */
  line-height: 0;
  transition: opacity 0.18s ease;
}
.landing-shop img {
  /* Was clamp(180px, 24vw, 360px). Reduced across the board once the sign
     was redrawn with a heavier stroke - it carries at a smaller size now,
     and the extra height of the new lettering was crowding the page.
     .landing-signs derives its own allowance from these same three numbers,
     so they are kept in step by --shop-sign-w-* below. */
  width: clamp(var(--shop-sign-w-min), var(--shop-sign-w-vw), var(--shop-sign-w-max));
  height: auto;
  display: block;
}
.landing-shop:hover { opacity: 0.55; }

/* the two hand-drawn door signs - womenswear first, as asked.
   Centred in the page and sized off both vw and vh so a tall pair can
   never push the footer or marquee off a short screen. */
.landing-signs {
  align-self: center;
  display: flex;
  gap: clamp(20px, 5vw, 72px);
  align-items: center;
  justify-content: center;
}
.landing-signs a {
  display: block;
  line-height: 0;
  transition: transform 0.2s ease, opacity 0.2s ease;
}
/* The signs want to be as big as the page can spare, so rather than guess a
   vh fraction the height is the room actually left over: the viewport minus
   the fixed furniture (18px page padding + 34px top row + 8px gap + 51px
   footer + 47px marquee + 20px "shop all" padding = 178px), minus the two
   blocks that scale with width - the wordmark at 9.6vw (x1.07 for its line
   box) and the "shop all" tag at 24vw capped at 360px (x0.326 for its
   aspect). The 93.5vh instead of 100vh holds back 6.5vh of breathing room
   so the pair never sits flush against the wordmark or the footer. */
.landing-signs img {
  /* vh first as the fallback, then the same figure in dvh.
     .landing measures itself in dvh (small viewport, i.e. with the iOS
     toolbar showing) while this was sizing against vh, which is always the
     LARGE viewport - so on iPhone Safari the signs were sized for a page
     60-100px taller than actually existed and pushed the footer under the
     fold. Browsers without dvh simply ignore the second declaration. */
  /* The "shop all" allowance is derived from --shop-sign-aspect rather than
     hardcoded. It used to be the literal 7.84vw / 118px, which was 0.326 -
     the aspect of the sign drawn in August. Swapping in a taller sign left
     the formula reserving 32px too little, the signs grew into the gap, and
     the page tipped just past the viewport: a scrollbar appeared, the fitter
     re-measured a narrower box, the page fitted again, and the whole thing
     shook in time with the wordmark. Update the ONE variable when the sign
     is redrawn and this follows. */
  /* The allowance mirrors the sign's OWN width rule - clamp(180px, 24vw,
     360px) - times its aspect, so it is exact at every width. Using
     min(24vw, 360px) instead ignored the 180px FLOOR, which is what phones
     actually hit: it reserved 44px for something 88px tall. */
  height: clamp(160px, min(40vw, calc(95vh - 178px - 10.26vw
           - calc(clamp(var(--shop-sign-w-min), var(--shop-sign-w-vw), var(--shop-sign-w-max))
                  * var(--shop-sign-aspect)))), 700px);
  height: clamp(160px, min(40vw, calc(95dvh - 178px - 10.26vw
           - calc(clamp(var(--shop-sign-w-min), var(--shop-sign-w-vw), var(--shop-sign-w-max))
                  * var(--shop-sign-aspect)))), 700px);
  width: auto;
  display: block;
}
.landing-signs a:hover {
  transform: translateY(-3px) rotate(-1deg);
  opacity: 0.8;
}

@media (prefers-reduced-motion: reduce) {
  .landing-signs a:hover { transform: none; }
}

/* flex:1 centres the signs in whatever room is left; the min-height is only
   a floor for short screens, so keep it small or it steals space the signs
   could be using */
.landing-spacer { flex: 1; min-height: 10px; }

/* Sits opposite the clock, and set in the clock's mono face so the two top
   corners read as one instrument panel rather than two unrelated notes. */
/* Desktop keeps these in the footer, where they read as part of the set.
   The phone rules further down turn this on and hide the footer copies. */
.landing-policy { display: none; }

.landing-url {
  font-family: var(--mono);
  text-align: right;
  font-size: 11px;
  letter-spacing: 0.04em;
  line-height: 1.5;
  white-space: nowrap;
  color: var(--grey);
}

/* landing keeps the left-aligned composition.
   Double class so this wins over the base .site-footer defined further down. */
.site-footer.site-footer--landing {
  justify-content: flex-start;
  padding: 0 0 22px;
  text-align: left;
}

/* ── INFO PAGE (shipping / returns / contact) ──
   A reading page, so it gets a measure rather than the full grid width. */
.info-page {
  max-width: 62ch;
  margin: 0 auto;
}
.info-title {
  font-size: clamp(24px, 5vw, 38px);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.1;
  margin-bottom: 14px;
}
.info-lede {
  font-size: 15px;
  line-height: 1.65;
  color: var(--black);
  margin-bottom: 8px;
}
.info-section {
  margin-top: 40px;
  padding-top: 22px;
  border-top: 1px solid var(--light-grey);
}
.info-section h2 {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  margin-bottom: 14px;
}
.info-section p {
  font-size: 14px;
  line-height: 1.7;
  color: var(--black);
  margin-bottom: 12px;
}
.info-section p:last-child { margin-bottom: 0; }

.info-grades {
  margin: 0 0 16px;
  font-size: 14px;
  line-height: 1.7;
}
.info-grades dt {
  font-weight: 700;
  letter-spacing: 0.04em;
  margin-top: 10px;
}
.info-grades dd {
  margin: 0;
  color: var(--grey);
}

.info-contact {
  list-style: none;
  font-size: 14px;
  line-height: 2;
}
.info-contact a { border-bottom: 1px solid var(--light-grey); }
.info-contact a:hover { border-color: var(--black); }

@media (max-width: 560px) {
  .info-section { margin-top: 30px; }
}

/* ── CORNER STITCHES ──  AWAITING ARTWORK
   Four hand-drawn stitch marks, one per corner of a grid photo. Grid only:
   the product page shows the garment full size and corner marks there would
   fight the photograph.

   The markup and positioning are already in place. To switch it on, drop the
   scan in as images/ui/stitch.png and delete the `display: none` below - the
   single mark is rotated into all four corners, so one drawing covers it. */
.card-media .stitch {
  position: absolute;
  z-index: 3;
  width: 14px;
  height: 14px;
  background: var(--stitch, none) center / contain no-repeat;
  pointer-events: none;
  display: none;              /* remove once images/ui/stitch.png exists */
}
.card-media .stitch--tl { top: 5px;    left: 5px;  }
.card-media .stitch--tr { top: 5px;    right: 5px; transform: rotate(90deg); }
.card-media .stitch--br { bottom: 5px; right: 5px; transform: rotate(180deg); }
.card-media .stitch--bl { bottom: 5px; left: 5px;  transform: rotate(270deg); }

@media (max-width: 560px) {
  .card-media .stitch { width: 10px; height: 10px; }
}

/* ── SIZE GLYPH ──  AWAITING ARTWORK
   The hand-drawn size alphabet (XS-XL, FREE, ADJUSTABLE, 0-4). Until the
   scans land, `.size-mark` simply renders the size as text in the site face,
   which is exactly what it did before - so nothing looks unfinished in the
   meantime. When the art arrives, give .size-mark a background image keyed
   off its data-size attribute and hide the text. */
/* Sizes. `.is-hand` is added by JS only when every character exists in the
   drawn face - see sizeMarkup(). Without that check a size like ADJUSTABLE
   would render its S and L in the handwriting and the rest in Space
   Grotesk, which looks like a bug rather than a flourish. */
.size-mark {
  display: inline-block;
  font-weight: 700;
  letter-spacing: 0.08em;
}
/* The drawn words. Sized by HEIGHT so they sit at the same optical weight
   as the font-set sizes beside them rather than at some arbitrary pixel
   width, and the ink is already the site black so no filter is needed. */
.card-media .size-word,
.pdp-row-value .size-word,
.size-word {
  /* The hover tag lives INSIDE .card-media, whose `img` rule absolutely
     positions product photos and stretches them to 100%/100% with padding.
     That rule is more specific than a bare .size-word, so without these
     resets the word inherits inset:0 + width:100% and collapses to zero
     width - which is exactly what happened first time round. */
  position: static;
  inset: auto;
  width: auto;
  padding: 0;
  object-fit: fill;
  display: block;
  height: 1.45em;
}
.card-hoverinfo .size-word { height: 20px; }
.pdp-row-value .size-word { height: 22px; display: inline-block; vertical-align: -5px; }

/* Drawn "n/a" for a measurement the drawn table lists but this garment has
   no figure for. Sized off the row's own text so it sits at the same optical
   weight as the numbers above and below it, and given the same explicit
   resets as .size-word - it is an <img> in a context where other rules
   stretch images to fill their box. */
.pdp-row-value .na-mark,
.na-mark {
  position: static;
  inset: auto;
  width: auto;
  /* 1.8em, not 1.15em: the row is set at 11px, and drawn marks need more
     height than typeset text to read as clearly at the same size - the same
     reason .size-word sits at 22px against 12px labels. */
  height: 1.8em;
  padding: 0;
  object-fit: fill;
  display: inline-block;
  vertical-align: -5px;
  /* reads as secondary without dropping under AA: 0.68 over white lands
     around #7a7a7a, close to the site's own --grey */
  opacity: 0.68;
}

.size-mark.is-hand {
  font-family: 'MGGG Hand', var(--sans);
  font-weight: 400;
  /* the drawn glyphs have a smaller apparent x-height than Space Grotesk,
     so they need a size bump to hold the same weight on the page */
  font-size: 1.5em;
  line-height: 0.8;
  letter-spacing: 0.06em;
}

/* ── CONDITION ──
   The five-point scale is stored as a number but shown as a word - a
   numeric score reads as a mark out of five, which is the wrong register
   for second-hand archive clothing. */
.pdp-row--grade .pdp-row-value {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  justify-content: flex-end;
}
.grade-link {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  border-bottom: 1px solid var(--light-grey);
  padding-bottom: 1px;
}
.grade-link:hover { border-color: var(--black); }
.grade-word { letter-spacing: 0.03em; }
.grade-note {
  flex: 1 0 100%;
  text-align: right;
  font-size: 11px;
  color: var(--grey);
}

/* ── HEADER CURRENCY ──
   Set in the clock's mono face so the left side of the header reads as one
   instrument panel rather than a clock plus a bolted-on form control. */
.header-currency {
  display: inline-flex;
  align-items: baseline;
}
.header-currency select {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.05em;
  color: var(--grey);
  background: none;
  border: none;
  border-bottom: 1px solid var(--light-grey);
  /* measured 40x22 - two short of the 24px floor, so the padding grows and
     the negative margin holds the baseline where it was. Do NOT add a
     second `padding` below this: a later declaration in the same rule wins
     silently and leaves the margin pulling the control out of place. */
  padding: 6px 0 5px;
  margin: -6px 0 -5px;
  cursor: pointer;
}
.header-currency select:hover { color: var(--black); border-color: var(--black); }

/* ── MAKE AN OFFER ──
   Secondary to Add to cart: outlined rather than filled, so the primary
   action still reads first. */
.pdp-offer {
  display: block;
  margin-top: 10px;
  padding: 13px 16px;
  border: 1px solid var(--black);
  background: none;
  color: var(--black);
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-align: center;
  transition: background 0.15s ease, color 0.15s ease;
}
.pdp-offer:hover { background: var(--black); color: #fff; }

/* ── SOLD ARCHIVE ── a lookbook of what has already gone */
.archive-toggle { margin-left: auto; }
.archive-toggle.is-active { color: var(--black); }
body.is-archive .card.is-sold .card-media img { filter: none; }
body.is-archive .sold-badge { background: var(--grey); }

/* ── MOTION TOGGLE ──
   The wordmark changes typeface 2.5 times a second for as long as the page
   is open. WCAG 2.2.2 wants an in-page way to stop anything that moves for
   more than five seconds, and an OS-level reduced-motion setting is not
   one. Sits beside the clock, in the clock's own type, so it reads as part
   of the instrument panel rather than a bolted-on accessibility control. */
.landing-motion {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.05em;
  background: none;
  border: none;
  /* This is the WCAG 2.2.2 pause control for the animated wordmark, so it
     of all things has to clear the 24px target floor - it measured 38x21. */
  min-height: 24px;
  padding: 6px 8px 6px 0;
  margin-left: 10px;
  color: var(--grey);
  cursor: pointer;
}
.landing-motion:hover { color: var(--black); }

/* ── BRAND MARQUEE ── */
.landing-marquee {
  align-self: stretch;
  margin: 0 -20px; /* full bleed past .landing padding */
  padding: 15px 0;
  border-top: 1px solid var(--light-grey);
  overflow: hidden;
}

.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee-scroll 48s linear infinite;
}
.landing-marquee:hover .marquee-track,
.landing-marquee:focus-within .marquee-track { animation-play-state: paused; }

.marquee-group { display: flex; flex: 0 0 auto; }

.marquee-item,
.marquee-dot {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  white-space: nowrap;
}
.marquee-dot { padding: 0 18px; color: var(--grey); }

@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); } /* exactly one duplicated group */
}

/* the global reduced-motion rule shortens durations, which would spin an
   infinite loop - stop it outright instead */
@media (prefers-reduced-motion: reduce) {
  .marquee-track { animation: none !important; }
}

@media (max-width: 560px) {
  .landing { padding: 14px 12px 0; }
  .landing-wordmark {
    white-space: normal;
    font-size: clamp(30px, 13.5vw, 60px);
    letter-spacing: -0.02em;
    line-height: 1.02;
  }
  .landing-url { font-size: 9px; letter-spacing: 0.02em; }

  /* Policy links move above the wordmark on phones, set to match the URL
     opposite them so the two read as one line of small print across the
     top. The footer copies go, so each link exists once. */
  .landing-policy {
    display: flex;
    align-self: stretch;
    justify-content: flex-start;
    flex-wrap: wrap;
    column-gap: 12px;
    row-gap: 2px;
    margin-bottom: 6px;
    font-family: var(--mono);
    font-size: 9px;
    letter-spacing: 0.02em;
    color: var(--grey);
  }
  .landing-policy a {
    color: inherit;
    /* 9px type is ~11px tall, so it needs real padding to clear the 24px
       target floor - at 4px it measured 18. Do NOT add a second `padding`
       below this: a later declaration in the same rule wins silently. */
    display: inline-flex;
    align-items: center;
    min-height: 24px;
    padding: 6px 0;
  }
  .landing-policy a:hover { color: var(--black); }
  .site-footer--landing .footer-policy { display: none; }
  .landing-signs { gap: 16px; }
  /* phones have height to spare here, so width is the binding constraint:
     the pair measures 1.38x their height plus the 16px gap, and 62vw keeps
     that inside the 24px page padding even on a 320px screen */
  /* Phones are left alone deliberately - the user confirmed this size is
     right. The desktop rule above is the one that grew. */
  .landing-signs img { height: min(36vh, 62vw, 235px); }
  .landing-signs img { height: min(36dvh, 62vw, 235px); }
}

/* SHORT phones only. The rule above is the approved size and stays put on a
   normal handset, but on a 640-700px screen the page ran past the fold once
   the "shop all" sign was redrawn taller - the sign is pinned at its 180px
   minimum width there, so a taller drawing costs real vertical space that
   62vw signs cannot give back. This tier trims them just on the screens
   where the room genuinely is not there. */
@media (max-width: 700px) and (max-height: 700px) {
  .landing-signs img { height: min(27vh, 50vw, 185px); }
  .landing-signs img { height: min(27dvh, 50vw, 185px); }
  .site-footer.site-footer--landing { column-gap: 14px; row-gap: 2px; padding: 0 0 16px; }
  .site-footer--landing a,
  .site-footer--landing .footer-copy { font-size: 9px; padding: 4px 0; }
  /* Six items in a 296px-wide row stack to eight lines on a 320px screen
     and eat 150px of a 568px page. Tightening the gap and the tap padding
     gets it back to three lines without shrinking the type any further -
     these are already at 9px. */
  @media (max-width: 400px) {
    .site-footer.site-footer--landing { column-gap: 9px; row-gap: 0; }
    .site-footer--landing a,
    .site-footer--landing .footer-copy { padding: 2px 0; letter-spacing: 0.02em; }
  }
  .landing-marquee { margin: 0 -12px; padding: 12px 0; }
  .marquee-item, .marquee-dot { font-size: 11px; }
  .marquee-dot { padding: 0 14px; }
}

/* ── BRAND SORT DROPDOWN ── */
.brand-sort {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}
.brand-sort-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey);
}
.brand-sort select {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--black);
  border-radius: 0;
  /* 24px minimum target height; these measured 23 */
  min-height: 24px;
  padding: 5px 18px 5px 2px;
  font-family: inherit;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--black);
  cursor: pointer;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5'%3E%3Cpath d='M0 0l4 5 4-5z' fill='%23111'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 2px center;
}
.brand-sort select:focus { border-bottom-color: var(--grey); }

/* ── SHOP TOOLBAR (filters / search / density) ── */
.shop-toolbar {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: 32px;
}

.filter-row {
  display: flex;
  gap: 20px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;      /* firefox */
  -ms-overflow-style: none;   /* old edge */
  white-space: nowrap;
}
.filter-row::-webkit-scrollbar { display: none; }

.filter-btn {
  /* 3px of the bottom padding is the gap above the active underline.
     min-width keeps short labels (ALL) at the 24px WCAG 2.5.8 minimum
     without adding horizontal padding that would widen the row.

     NO negative margin here, unlike the other padded tap targets. These
     buttons live inside .filter-row, which sets overflow-x for horizontal
     scrolling - and a non-visible overflow on one axis forces the other to
     `auto` too. The row sized itself to the buttons' 17px MARGIN box while
     the buttons' 31px BORDER box overflowed it, so the tops and bottoms of
     ALL / MENSWEAR / WOMENSWEAR were cropped. Letting the row take the full
     31px fixes it; .toolbar-lower is baseline-aligned, so the labels still
     line up with BRAND, SORT and SEARCH. */
  min-width: 24px;
  /* Weighted to the TOP: the bottom padding is the gap between the label and
     its active underline, which the design wants tight (it was 3px before
     the hit area was enlarged). Total is still 31px. */
  padding: 13px 0 4px;
  flex: 0 0 auto;
  background: none;
  border: none;
  border-bottom: 1px solid transparent;
  cursor: pointer;
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--grey);
}
.filter-btn:hover { color: var(--black); }
.filter-btn.is-active { color: var(--black); border-bottom-color: var(--black); }

.toolbar-lower {
  display: flex;
  align-items: baseline;
  gap: 24px;
  flex-wrap: wrap;
}
.toolbar-lower .filter-row--gender { flex: 0 1 auto; }

/* iOS otherwise paints native search-field chrome over the underline */
.shop-search {
  -webkit-appearance: none;
  appearance: none;
  flex: 0 0 auto;
  width: 150px;
  background: none;
  border: none;
  border-bottom: 1px solid var(--light-grey);
  border-radius: 0;
  /* 24px minimum target height; this measured 19 */
  min-height: 24px;
  padding: 3px 0 5px;
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--black);
}
.shop-search:focus:not(:focus-visible) { outline: none; }
.shop-search::placeholder {
  color: var(--grey);
  text-transform: uppercase;
  font-size: 10px;
  letter-spacing: 0.12em;
}
.shop-search:focus { border-bottom-color: var(--black); }

.grid-density {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-left: auto;
}
.grid-density button {
  background: none;
  border: none;
  padding: 10px 12px; /* comfortable tap target around a small glyph */
  margin: -10px -6px;
  cursor: pointer;
  font-family: var(--sans);
  font-size: 13px;
  line-height: 1;
  color: var(--grey);
}
.grid-density button:hover { color: var(--black); }
.grid-density .cols-value {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  color: var(--black);
  min-width: 1ch;
  text-align: center;
}

.results-count {
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--grey);
}

/* empty state inside the grid */
.grid-empty {
  grid-column: 1 / -1;
  list-style: none;
  text-align: center;
  padding: 70px 0;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey);
}
.grid-empty p { margin: 0 0 10px; }
.grid-empty p:last-child { margin-bottom: 0; }

/* the empty state's way out - a button that reads as a link, but stays a
   real button so it is announced and operated as one */
.link-btn {
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: var(--black);
  background: none;
  border: 0;
  border-bottom: 1px solid currentColor;
  padding: 6px 2px;          /* keeps the tap target off the 24px floor */
  cursor: pointer;
}
.link-btn:hover { color: var(--grey); }

@media (max-width: 760px) {
  .shop-toolbar { gap: 12px; margin-bottom: 24px; }
  .toolbar-lower { gap: 16px; row-gap: 12px; }
  .shop-search { width: 140px; }
  .grid-density { margin-left: 0; }
}

/* iOS zooms the page when focusing inputs under 16px - keep form
   controls at 16px on touch devices to prevent it */
@media (hover: none), (pointer: coarse) {
  .shop-search { font-size: 16px; letter-spacing: 0.02em; }
  .brand-sort select { font-size: 16px; letter-spacing: 0.02em; }
  .header-currency select { font-size: 16px; }
}

.noscript-note {
  max-width: 52ch;
  margin: 40px auto;
  padding: 16px;
  border: 1px solid var(--light-grey);
  font-size: 13px;
  line-height: 1.6;
  text-align: center;
}
.noscript-note a { border-bottom: 1px solid var(--grey); }

/* ── FOOTER ── */
.site-footer {
  padding: 60px 16px 28px;
  text-align: center;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: baseline;
  column-gap: 22px;
  row-gap: 6px;
}
.site-footer a,
.site-footer .footer-copy {
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey);
  padding: 8px 0; /* tap target */
}
.site-footer a:hover { color: var(--black); }

/* ── PRODUCT DETAIL PAGE ── */
.product-page { padding: 72px 16px 60px; }

.pdp {
  display: grid;
  grid-template-columns: 1fr 380px;
  gap: 48px;
  max-width: 1200px;
  margin: 0 auto;
}

.pdp-photos {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
}
.pdp-photo {
  background: #f7f7f7;
  aspect-ratio: 3 / 4;
}
.pdp-photo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 4%;
  display: block;
}

.pdp-info-wrap { min-width: 0; }
.pdp-info {
  position: sticky;
  top: 72px;
}

.pdp-back {
  padding: 8px 8px 8px 0;
  margin: -8px -8px 10px 0;   /* -8 top/right, +18 visual bottom gap */
  display: inline-block;
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--grey);
}
.pdp-back:hover { color: var(--black); }

.pdp-brand {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: 6px;
}
.pdp-title {
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.05em;
  margin-bottom: 10px;
}
.pdp-price {
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--grey);
  margin-bottom: 24px;
}
/* sold: price omitted, name struck through */
.pdp.is-sold .pdp-brand,
.pdp.is-sold .pdp-title { text-decoration: line-through; }

.pdp-specs {
  border-top: 1px solid var(--light-grey);
  margin-bottom: 24px;
}
.pdp-row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 9px 0;
  border-bottom: 1px solid var(--light-grey);
  font-size: 11px;
  letter-spacing: 0.06em;
}
.pdp-row-label {
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 10px;
  color: var(--grey);
  flex-shrink: 0;
}
.pdp-row-value { text-align: right; }

.pdp-description {
  font-size: 12px;
  line-height: 1.7;
  letter-spacing: 0.02em;
  margin-bottom: 24px;
}

.pdp-measurements { margin-bottom: 24px; }
.pdp-label {
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey);
  margin-bottom: 8px;
}
.pdp-measurements .pdp-row:first-of-type { border-top: 1px solid var(--light-grey); }

/* ── the drawn measurement table ─────────────────────────────────────
   The table is artwork; the figures are positioned over it as a
   percentage of the box, so the whole thing scales as one piece.
   aspect-ratio is set inline per table (they were drawn at different
   proportions) and holds the box before the PNG arrives, so the numbers
   never land on a collapsed container and then jump. */
.measure-table {
  position: relative;
  width: 100%;
  max-width: 460px;
  margin: 0 0 4px;
}
.measure-table img {
  width: 100%;
  height: 100%;
  display: block;
  /* the drawn tables are black ink on transparent; nothing to tint */
}
.mt-num {
  position: absolute;
  transform: translate(-50%, -50%);
  font-family: 'MGGG Hand', var(--sans);
  font-weight: 400;
  /* scales with the table rather than the page: the drawn rows are a fixed
     share of the box height, so a fixed px size would overflow them on a
     narrow screen and swim in them on a wide one */
  /* Sized so the drawn numerals sit at roughly 60% of a row's height. They
     carry far more ink than a typeset digit at the same nominal size - at
     the first value tried they filled 89% of the row and touched the rules.
     Tied to the table's WIDTH (cqw) because that is what the geometry is
     expressed in; a row is ~9% of the box width once the heading is cropped
     off, so this lands a little under two thirds of that. */
  font-size: 6.8cqw;
  line-height: 1;
  color: var(--black);
  white-space: nowrap;
  pointer-events: none;
}
/* container query units need a container to measure against */
.measure-table { container-type: inline-size; }

/* The drawn "n/a" sitting in a table cell that has no figure.
   Selector is scoped to beat `.measure-table img`, which stretches the table
   artwork to 100%/100%: a bare `.mt-na` (0,1,0) loses to it (0,1,1) and the
   mark was being blown up to fill the whole table. Same cascade trap as
   `.size-word` inside `.card-media img` - scope it, do not just declare it. */
.measure-table img.mt-na {
  position: absolute;
  transform: translate(-50%, -50%);
  height: 5.4cqw;
  width: auto;
  display: block;
  opacity: 0.62;
  pointer-events: none;
}
@supports not (height: 1cqw) {
  .measure-table img.mt-na { height: clamp(10px, 2.3vw, 25px); }
}

/* No container-query support: fall back to viewport-relative sizing, capped
   so it cannot outgrow the row it sits in. */
@supports not (font-size: 1cqw) {
  .mt-num { font-size: clamp(12px, 2.9vw, 31px); }
}

.pdp-add {
  width: 100%;
  padding: 14px 0;
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  background: var(--black);
  color: #fff;
  border: 1px solid var(--black);
  cursor: pointer;
}
.pdp-add:hover { background: #fff; color: var(--black); }
.pdp-add--link { display: block; text-align: center; }
.pdp-add.is-sold,
.pdp-add[aria-disabled="true"],
.pdp-add:disabled {
  background: #fff;
  color: var(--grey);
  border-color: var(--light-grey);
  cursor: not-allowed;
}

/* Said in words, because the strikethrough on the title is decoration and
   is announced by nothing. Sits directly above the Sold button. */
.pdp-sold-note {
  margin: 0 0 10px;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--black);
}

.pdp-notfound {
  min-height: 60vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.pdp-notfound a {
  border-bottom: 1px solid var(--black);
  padding-bottom: 2px;
}
.pdp-notfound a:hover { color: var(--grey); border-color: var(--grey); }

/* mobile: photos become a horizontal swipe strip, info below */
@media (max-width: 760px) {
  .product-page { padding: 60px 0 40px; }
  .pdp {
    grid-template-columns: 1fr;
    gap: 24px;
  }
  .pdp-photos {
    flex-direction: row;
    gap: 6px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
  }
  .pdp-photo {
    flex: 0 0 88%;
    scroll-snap-align: center;
  }
  .pdp-info-wrap { padding: 0 16px; }
  .pdp-info { position: static; }
}

/* ── CART DRAWER ── */
.cart-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(0, 0, 0, 0.5);
}

.cart-drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 201;
  width: 400px;
  max-width: 100%;
  background: #fff;
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform 0.25s ease;
  border-left: 1px solid var(--light-grey);
  overscroll-behavior: contain;
}

/* page behind the drawer must not scroll */
body.cart-open { overflow: hidden; }
.cart-drawer.is-open { transform: translateX(0); }

.cart-top {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px;
  border-bottom: 1px solid var(--light-grey);
}
.cart-heading {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.cart-feedback {
  flex: 1;
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--grey);
  text-align: right;
}
.cart-close {
  padding: 8px 12px;
  margin: -8px -12px;
  background: none;
  border: none;
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  color: var(--black);
}
.cart-close:hover { color: var(--grey); }

.cart-items {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 16px;
}
.cart-empty {
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--grey);
  text-align: center;
  padding: 40px 0;
}

.cart-item {
  display: flex;
  gap: 14px;
  padding-bottom: 16px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--light-grey);
}
.cart-item:last-child { margin-bottom: 0; }
.cart-item-thumb {
  flex-shrink: 0;
  width: 84px;
  height: 112px;
  background: #f7f7f7;
  display: block;
}
.cart-item-thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 6%;
  display: block;
}
.cart-item-info { min-width: 0; }
.cart-item-brand {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-bottom: 3px;
}
.cart-item-title {
  font-size: 11px;
  letter-spacing: 0.04em;
  margin-bottom: 6px;
}
.cart-item-price {
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--grey);
  margin-bottom: 8px;
}
/* Padded hit areas. These were 12-18px tall - fine with a mouse, a
   fat-finger miss on a phone. The negative margins keep the visual
   position identical, the same trick .grid-density button already used. */
.cart-item-remove {
  background: none;
  border: none;
  cursor: pointer;
  padding: 6px 8px 6px 0;
  margin: -6px -8px -6px 0;
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--grey);
  border-bottom: 1px solid var(--light-grey);
}
.cart-item-remove:hover { color: var(--black); border-color: var(--black); }

/* The site never said what currency it was quoting. */
/* #e5e5e5 on white is ~1.2:1 - below the 3:1 WCAG 1.4.11 needs for the
   visible boundary of a control. --grey is 4.6:1. */
.shop-search { border-bottom-color: var(--grey); }

.cart-currency {
  font-size: 9px;
  letter-spacing: 0.12em;
  color: var(--grey);
  margin-left: 4px;
}

/* A one-of-one selling while it sits in someone's cart is the normal case,
   not an edge case. The row stays - vanishing silently is worse - but it is
   visibly struck out and its price is replaced, so nothing quotes a figure
   for a piece that can no longer be bought. Dimming uses `filter` so the
   thumbnail keeps whatever opacity the crossfade rules gave it. */
.cart-item.is-unavailable .cart-item-thumb { filter: opacity(0.4); }
.cart-item.is-unavailable .cart-item-brand,
.cart-item.is-unavailable .cart-item-title {
  text-decoration: line-through;
  color: var(--grey);
}
.cart-item-gone {
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--sale);
  margin-bottom: 8px;
}
.cart-gone-note {
  font-size: 10.5px;
  line-height: 1.5;
  letter-spacing: 0.04em;
  color: var(--grey);
  border-top: 1px solid var(--light-grey);
  padding-top: 12px;
  margin-top: 4px;
}

.cart-foot {
  padding: 16px;
  border-top: 1px solid var(--light-grey);
}
.cart-subtotal {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-bottom: 10px;
}
.cart-note {
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--grey);
  margin-bottom: 14px;
}
.cart-note-link {
  color: var(--black);
  border-bottom: 1px solid var(--black);
}
.cart-note-link:hover { color: var(--grey); border-color: var(--grey); }
.cart-checkout {
  width: 100%;
  padding: 14px 0;
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  background: #fff;
  color: var(--grey);
  border: 1px solid var(--light-grey);
  cursor: not-allowed;
}

@media (max-width: 560px) {
  .cart-drawer { width: 100%; border-left: none; }
}

/* ── CUSTOM CURSOR: mono dot ────────────────────────────────────────
   A filled dot for everything, an open ring for anything clickable, so
   "this responds" reads at a glance. Both carry a white rim so they stay
   legible over dark garment photos as well as the white ground.

   Drawn as inline SVG - no files to fetch, no JS, no lag: the OS renders
   these exactly like a native cursor. The two trailing numbers are the
   hotspot (the pixel that actually clicks), centred on the shape.

   Deliberately LAST in this file: several components set their own
   `cursor: pointer` above, and this section is meant to win.
   Desktop only - touch devices have no cursor to replace.
──────────────────────────────────────────────────────────────────── */
@media (hover: hover) and (pointer: fine) {
  :root {
    --cur-dot: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18'%3E%3Ccircle cx='9' cy='9' r='4' fill='%23111' stroke='%23fff' stroke-width='2'/%3E%3C/svg%3E") 9 9;
    --cur-ring: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='26'%3E%3Ccircle cx='13' cy='13' r='8' fill='none' stroke='%23fff' stroke-width='4'/%3E%3Ccircle cx='13' cy='13' r='8' fill='none' stroke='%23111' stroke-width='1.6'/%3E%3C/svg%3E") 13 13;
  }

  body { cursor: var(--cur-dot), auto; }

  /* anything you can act on gets the ring */
  a,
  button:not(:disabled),
  select,
  summary,
  [role="button"],
  .card-media,
  .filter-btn,
  .brand-sort select,
  .grid-density button,
  .cart-item-remove,
  .cart-close,
  .menu-close,
  .menu-links a {
    cursor: var(--cur-ring), pointer;
  }

  /* meanings that already exist stay intact */
  input[type="text"],
  input[type="search"],
  .shop-search { cursor: text; }

  button:disabled,
  .pdp-add.is-sold,
  .cart-checkout { cursor: not-allowed; }
}
