/* ============================================================================
 * KTSD Shop - design system (client "ktsd-shop-m4s" / Yeezy-Supply minimalism)
 * Canonical spec: docs/design/ktsd-shop-design-spec.md
 * Monochrome, zero-radius, thin Helvetica Neue, hairline rules. No color/shadow.
 *
 * Redefines the EXISTING shop class vocabulary so the shell (header, lightbox,
 * cart drawer, toasts) AND every page that already uses these classes restyle
 * together, with the layout's JS (which reads IDs/classes) untouched.
 * ==========================================================================*/

:root {
  /* new semantic tokens */
  /* Text colours were too light to read comfortably (reported by Kang/Jia).
     The old values failed WCAG AA on white: --muted #999 was ~2.8:1 and
     --faint #bbb ~1.9:1, against the 4.5:1 minimum for body text. These are
     darkened to pass while keeping the monochrome hierarchy - each token is
     still visibly lighter than the one above it. */
  --ink: #1a1a1a;
  --paper: #ffffff;
  --faint: #6b6b6b;      /* was #bbbbbb - 5.7:1 */
  --faintest: #7a7a7a;   /* was #cccccc - 4.9:1 */
  --line: #e8e8e8;
  --line-soft: #f0f0f0;
  --wash: #f7f7f7;
  --shop-font: "Helvetica Neue", Helvetica, Arial, sans-serif;
  /* legacy aliases (referenced by existing markup + the layout's inline JS) */
  --bg: #ffffff;
  --surface: #f7f7f7;
  --text: #1a1a1a;
  --muted: #565656;      /* was #999999 - now 7.2:1, comfortably readable */
  --border: #e8e8e8;
  --danger: #cc0000;
  --accent: #1a1a1a;
}

/* ---- base / reset (scoped to .shop-body) ---- */
.shop-body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--shop-font);
  /* 300 was thin enough to wash out at these sizes; 400 reads far better on
     white without changing the typeface's character. */
  font-weight: 400;
  font-size: 15px;   /* was 13px */
  line-height: 1.6;  /* was 1.5 - a little more air helps small copy */
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
.shop-body *, .shop-body *::before, .shop-body *::after { box-sizing: border-box; }
.shop-body h1, .shop-body h2, .shop-body h3, .shop-body h4 { font-family: var(--shop-font); font-weight: 300; line-height: 1.15; margin: 0; }
.shop-body a { color: inherit; text-decoration: none; transition: color .15s; }
.shop-body img { display: block; max-width: 100%; }
.shop-body p { margin: 0; }
.shop-body input::placeholder, .shop-body textarea::placeholder { color: var(--faint); }
.shop-body input[type=number]::-webkit-inner-spin-button, .shop-body input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.shop-body input[type=number] { -moz-appearance: textfield; }
.shop-body ::-webkit-scrollbar { width: 4px; height: 4px; }
.shop-body ::-webkit-scrollbar-track { background: var(--paper); }
.shop-body ::-webkit-scrollbar-thumb { background: var(--line); }

/* ---- layout primitives ---- */
.container { max-width: 1200px; margin: 0 auto; padding: 0 24px; }
.shop-narrow { max-width: 640px; margin: 0 auto; padding: 0 24px; }
.section { padding: 48px 0; }
.page-header { padding: 40px 0 8px; }
.page-header h1 { font-size: clamp(24px, 4vw, 34px); font-weight: 300; }
.empty-state { padding: 80px 24px; text-align: center; color: var(--muted); font-size: 12px; letter-spacing: .04em; }
.shop-rule { border: 0; border-top: 1px solid var(--line); margin: 0; }
hr { border: 0; border-top: 1px solid var(--line); }
.shop-main { padding-top: 44px; min-height: calc(100vh - 180px); } /* offset under fixed navbar */

/* ---- header / navbar (3-col: logo | links | actions) ---- */
.shop-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  background: var(--paper); border-bottom: 1px solid var(--line);
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  height: 44px; padding: 0 20px;
}
.shop-header__logo { display: flex; align-items: center; }
.shop-header__logo img { height: 30px; width: auto; object-fit: contain; }
.shop-header__nav { display: flex; gap: 28px; align-items: center; justify-content: center; }
.shop-header__nav a {
  font-size: 11px; font-weight: 400; text-transform: uppercase; letter-spacing: .08em;
  color: var(--muted); border-bottom: 1px solid transparent; padding-bottom: 1px; white-space: nowrap;
}
.shop-header__nav a:hover { color: var(--ink); }
.shop-header__nav a.is-active { color: var(--ink); border-bottom-color: var(--ink); }
.shop-header__actions { display: flex; justify-content: flex-end; align-items: center; gap: 20px; }
.shop-header__actions a, .shop-header__cart {
  font-size: 11px; font-weight: 400; text-transform: uppercase; letter-spacing: .08em;
  color: var(--muted); background: none; border: none; cursor: pointer; padding: 0;
  display: flex; align-items: center; gap: 5px; font-family: var(--shop-font); white-space: nowrap;
}
.shop-header__actions a:hover, .shop-header__cart:hover { color: var(--ink); }
.shop-header__cart { color: var(--ink); }
.shop-header__cart-count { font-size: 11px; color: var(--ink); }
@media (max-width: 720px) { .shop-header__nav { display: none; } }

/* ---- footer ---- */
.shop-foot { border-top: 1px solid var(--line); padding: 32px 24px; max-width: 1200px; margin: 56px auto 0; }
.shop-foot__row { display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; gap: 24px; }
.shop-foot__brand { display: flex; align-items: center; gap: 12px; }
.shop-foot__brand img { height: 22px; width: auto; object-fit: contain; opacity: .45; }
.shop-foot__copy { font-size: 10px; color: var(--faint); letter-spacing: .04em; }
.shop-foot__links { display: flex; gap: 24px; }
.shop-foot__links a { font-size: 10px; letter-spacing: .06em; color: var(--faint); }
.shop-foot__links a:hover { color: var(--ink); }

/* ---- buttons ---- */
.btn {
  display: inline-block; font-family: var(--shop-font); font-weight: 300; font-size: 11px;
  letter-spacing: .12em; text-transform: uppercase; text-align: center; cursor: pointer;
  background: transparent; color: var(--ink); border: 1px solid var(--ink); border-radius: 0;
  padding: 12px 22px; transition: background .15s, color .15s, border-color .15s;
}
.btn:hover { background: var(--wash); }
/* Anchor buttons need the a-selector variants: `.shop-body a` (0-1-1)
   out-specifies bare `.btn-primary` (0-1-0), turning <a> buttons ink-on-ink. */
.btn-primary, .shop-body a.btn-primary { background: var(--ink); color: #fff; border-color: var(--ink); }
.btn-primary:hover, .shop-body a.btn-primary:hover { background: #333; border-color: #333; color: #fff; }
.btn-outline { background: transparent; color: var(--ink); border-color: var(--ink); }
.btn-outline:hover { background: var(--wash); }
.btn-full { display: block; width: 100%; }
.btn[disabled], .btn-primary[disabled] { background: #888; border-color: #888; color: #fff; cursor: not-allowed; }
/* In-flight state: keep the label markup (screen readers still announce it)
   but paint it transparent and overlay a spinner. Pairs with [disabled]. */
.btn.btn-loading, .btn.btn-loading[disabled] { position: relative; color: transparent; pointer-events: none; }
.btn.btn-loading::after {
  content: ""; position: absolute; top: 50%; left: 50%; width: 14px; height: 14px;
  margin: -8px 0 0 -8px; border: 2px solid rgba(255, 255, 255, .35); border-top-color: #fff;
  border-radius: 50%; animation: btn-spin .6s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .btn.btn-loading::after { animation-duration: 1.5s; } }
.btn-text { background: none; border: none; padding: 0; color: var(--muted); text-transform: uppercase; letter-spacing: .08em; font-size: 11px; cursor: pointer; }
.btn-text:hover { color: var(--ink); }

/* ---- product grid + card ---- */
/* Hairlines: a right line on every card that is NOT in the last column, and
   a top line on every card below row one.
   Keying the vertical line to the COLUMN (:not(:nth-child(4n))) rather than to
   the last card means a partial row still closes off its final card - with
   three cards in a four-column grid the third used to butt straight into the
   empty cell, which read as a missing divider inside the grid's outer border.
   The last column is left open on purpose: that edge is the outer border.
   The vertical line is a BORDER, not a box-shadow. A shadow with a positive
   x-offset paints outside the card, underneath its right-hand neighbour -
   and every card has an opaque background and paints later in DOM order, so
   the neighbour covers it and only the final card's line survives. A border
   is part of the card's own box, so nothing can paint over it. (box-sizing:
   border-box is set globally, so the 1px sits inside the column and the
   grid stays even.)
   Rules are scoped to non-overlapping ranges matching the column breakpoints.
   (The original grey-gap technique painted empty cells as grey blocks, which
   is why nothing here fills a cell - only hairlines are drawn.) */
/* Card width at the widest layout: the .container is 1200px with 24px of
   padding either side, so four columns land on 288px each. Capping the grid
   at columns x this keeps a full row pixel-identical to before while letting
   a SHORT grid shrink instead of stretching. */
.product-grid { --card-max: 288px; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); background: var(--paper); border: 1px solid var(--line); max-width: calc(4 * var(--card-max)); }

/* Fewer cards than columns: shrink the box to fit them rather than stretching
   the cards and leaving an empty cell inside the border. Only possible when
   the grid is SHORT overall - a partial last row of a multi-row grid cannot
   shrink, since the box is one rectangle. Each case also clears the trailing
   card's hairline, because it is now in the last column and that edge is the
   grid's own border. */
.product-grid > * { background: var(--paper); }
@media (min-width: 901px) {
  .product-grid > :not(:nth-child(4n)) { border-right: 1px solid var(--line); }
  .product-grid > :nth-child(n+5) { box-shadow: 0 -1px 0 var(--line); }
  .product-grid:has(> :first-child:last-child) { grid-template-columns: minmax(0, 1fr); max-width: calc(1 * var(--card-max)); }
  .product-grid:has(> :first-child:last-child) > * { border-right: 0; }
  .product-grid:has(> :nth-child(2):last-child) { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: calc(2 * var(--card-max)); }
  .product-grid:has(> :nth-child(2):last-child) > :nth-child(2) { border-right: 0; }
  .product-grid:has(> :nth-child(3):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); max-width: calc(3 * var(--card-max)); }
  .product-grid:has(> :nth-child(3):last-child) > :nth-child(3) { border-right: 0; }
}
@media (max-width: 900px) and (min-width: 601px) {
  .product-grid > :not(:nth-child(3n)) { border-right: 1px solid var(--line); }
  .product-grid > :nth-child(n+4) { box-shadow: 0 -1px 0 var(--line); }
  .product-grid:has(> :first-child:last-child) { grid-template-columns: minmax(0, 1fr); max-width: calc(1 * var(--card-max)); }
  .product-grid:has(> :first-child:last-child) > * { border-right: 0; }
  .product-grid:has(> :nth-child(2):last-child) { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: calc(2 * var(--card-max)); }
  .product-grid:has(> :nth-child(2):last-child) > :nth-child(2) { border-right: 0; }
}
@media (max-width: 600px) {
  .product-grid > :not(:nth-child(2n)) { border-right: 1px solid var(--line); }
  .product-grid > :nth-child(n+3) { box-shadow: 0 -1px 0 var(--line); }
  .product-grid:has(> :first-child:last-child) { grid-template-columns: minmax(0, 1fr); max-width: calc(1 * var(--card-max)); }
  .product-grid:has(> :first-child:last-child) > * { border-right: 0; }
}
@media (max-width: 900px) { .product-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 600px) { .product-grid { grid-template-columns: repeat(2, 1fr); } }
.product-card { display: block; padding: 16px; background: var(--paper); position: relative; }
.product-card__img, .product-card__placeholder {
  position: relative; aspect-ratio: 1 / 1;
  display: flex; align-items: center; justify-content: center; padding: 10px; margin-bottom: 12px; overflow: hidden;
}
/* #127: the image must FILL its square box, scaling UP as well as down.
   It used to be `width:auto; height:auto` with only max- constraints, which
   meant any source image SMALLER than the box rendered at its natural size and
   floated in whitespace, while oversized ones scaled down to fit. Two products
   photographed at different resolutions therefore looked wildly different
   sizes on the same row - Kang's "the image still didn't auto-adjust to a
   suitable size". object-fit: contain keeps the aspect ratio intact, so
   nothing stretches or crops. */
.product-card__img img { width: 100%; height: 100%; object-fit: contain; transition: opacity .2s; }
.product-card:hover .product-card__img img { opacity: .82; }
.product-card__placeholder { color: var(--faintest); font-size: 10px; text-transform: uppercase; letter-spacing: .1em; }
.product-card__name { font-size: 13px; font-weight: 400; color: var(--ink); margin-bottom: 3px; }
.product-card__price { font-size: 11px; font-weight: 300; color: var(--ink); }
.product-card__oos-badge {
  position: absolute; top: 8px; left: 8px; font-size: 9px; font-weight: 400; text-transform: uppercase;
  letter-spacing: .08em; color: var(--muted); background: var(--paper); border: 1px solid var(--line); padding: 2px 6px;
}
.product-card--oos .product-card__img img { opacity: .5; }

/* ---- product detail ---- */
.product-detail { display: grid; grid-template-columns: 1fr 1fr; gap: 48px; padding: 32px 0; }
@media (max-width: 760px) { .product-detail { grid-template-columns: 1fr; gap: 24px; } }
/* align-self: start is load-bearing, not cosmetic.
   A grid item stretches to the row height by default, and this box also has
   aspect-ratio 1/1 - so a tall info column made the box tall, and the ratio
   then made it equally WIDE. A long product description (3293px tall) grew
   this box to 1619px across, which broke the 1fr 1fr track sizing to
   "1618px 162px", crushed the copy into a 163px column and pushed the page
   into horizontal scroll. Sizing from the column width instead keeps the
   square square no matter how much copy sits beside it. */
.product-detail__image { border: 1px solid var(--line-soft); aspect-ratio: 1 / 1; align-self: start; display: flex; align-items: center; justify-content: center; padding: 24px; max-height: 70vh; }
/* Same #127 fix as the card: fill the box rather than sit at natural size.
   The 70vh cap moved to the CONTAINER above - capping the IMG instead let the
   box stay square and tall while the picture inside shrank away from it. */
.product-detail__image img,
.product-pdp__img { width: 100%; height: 100%; object-fit: contain; display: block; }
/* Placeholder fills the same square, so a listing with no image occupies the
   identical footprint and the grid does not jump. */
.product-detail__placeholder {
  width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;
  color: var(--faintest); font-size: 11px; text-transform: uppercase; letter-spacing: .1em;
}
.product-detail__name { font-size: 22px; font-weight: 300; text-transform: uppercase; letter-spacing: .04em; margin-bottom: 12px; }
.product-detail__price { font-size: 16px; color: var(--ink); margin-bottom: 20px; }
.product-detail__meta { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: 16px 0; display: flex; flex-direction: column; gap: 8px; }
.product-detail__meta-row { display: flex; justify-content: space-between; font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }

/* Accessible label that stays available to screen readers but off-screen. */
.u-visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---- listings toolbar (sort + only-available + search) ---- */
.toolbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 16px 0; flex-wrap: wrap; border-bottom: 1px solid var(--line); }
.toolbar__group { display: flex; align-items: center; gap: 14px; }
.toolbar__group--search { flex: 1 1 320px; min-width: 0; }
.toolbar__group--search .form-input { width: auto; flex: 1 1 auto; min-width: 0; padding: 6px 10px; font-size: 12px; }
.toolbar__group--search .btn { flex-shrink: 0; }

/* landing-page search, sits under the hero copy */
.landing-hero__search { display: flex; align-items: center; gap: 10px; margin-top: 26px; max-width: 460px; }
.landing-hero__search .form-input { flex: 1 1 auto; min-width: 0; }
.landing-hero__search .btn { flex-shrink: 0; }
.landing-hero--with-image .landing-hero__search .form-input {
  background: rgba(255, 255, 255, 0.92); border-color: rgba(255, 255, 255, 0.6);
}
.landing-hero--with-image .landing-hero__search .btn { background: rgba(255, 255, 255, 0.92); }
.toolbar .form-select { width: auto; padding: 6px 24px 6px 10px; font-size: 11px; text-transform: uppercase; letter-spacing: .06em; }
.checkbox-sq { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 11px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); }
.checkbox-sq input { appearance: none; -webkit-appearance: none; width: 13px; height: 13px; border: 1px solid var(--ink); border-radius: 0; background: var(--paper); cursor: pointer; position: relative; flex-shrink: 0; }
.checkbox-sq input:checked { background: var(--ink); }
.checkbox-sq input:checked::after { content: ""; position: absolute; inset: 3px; background: var(--paper); }

/* ---- product stock status badge ----
   The status used to be small grey uppercase text wedged under the
   description, which read as an afterthought rather than a status. A pill
   with a status colour separates it from the copy and makes availability
   scannable at a glance. */
.stock-badge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px; border-radius: 999px;
  font-size: 11px; font-weight: 500; text-transform: uppercase; letter-spacing: .08em;
  margin: 14px 0 16px;
}
.stock-badge::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.stock-badge--in    { background: #e7f6ec; color: #17663a; }
.stock-badge--low   { background: #fdf3e3; color: #8a5a12; }
.stock-badge--out   { background: #fdeaea; color: #a12222; }

/* ---- forms ---- */
.shop-form { max-width: 560px; }
.form-group { margin-bottom: 18px; }
.form-label { display: block; font-size: 10px; font-weight: 400; text-transform: uppercase; letter-spacing: .1em; color: var(--muted); margin-bottom: 7px; }
.form-input, .form-select, textarea.form-input {
  width: 100%; font-family: var(--shop-font); font-weight: 300; font-size: 13px; color: var(--ink);
  background: var(--paper); border: 1px solid var(--line); border-radius: 0; padding: 11px 12px; transition: border-color .15s;
}
.form-input:focus, .form-select:focus, textarea.form-input:focus { outline: none; border-color: var(--ink); }
textarea.form-input { resize: vertical; min-height: 110px; }

/* auth tabs (sign in / register) */
.auth-page { max-width: 420px; margin: 40px auto; padding: 0 24px; }
.auth-tabs { display: flex; border: 1px solid var(--line); margin-bottom: 24px; }
.auth-tab { flex: 1; text-align: center; padding: 12px; font-size: 11px; text-transform: uppercase; letter-spacing: .1em; color: var(--muted); cursor: pointer; background: var(--paper); }
.auth-tab.active { background: var(--ink); color: #fff; }

/* ---- checkout ---- */
.checkout-layout { display: grid; grid-template-columns: 1fr 360px; gap: 48px; padding: 32px 0; }
@media (max-width: 820px) { .checkout-layout { grid-template-columns: 1fr; gap: 28px; } }
.checkout-section-title { font-size: 12px; text-transform: uppercase; letter-spacing: .12em; color: var(--muted); margin-bottom: 16px; padding-bottom: 8px; border-bottom: 1px solid var(--line); }
.checkout-summary { border: 1px solid var(--line); padding: 20px; align-self: start; }
.cart-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.cart-table th { font-size: 10px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); font-weight: 400; text-align: left; padding: 10px 8px; border-bottom: 1px solid var(--line); }
.cart-table td { padding: 12px 8px; border-bottom: 1px solid var(--line); }
.confirmation-page { max-width: 560px; margin: 60px auto; text-align: center; }
.order-number { font-size: 13px; letter-spacing: .1em; text-transform: uppercase; }

/* ---- flash banners ---- */
.shop-flash {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  letter-spacing: .04em;
  padding: 14px 18px;
  border: 1px solid var(--line);
  margin: 12px auto;
  max-width: 1200px;
}
.shop-flash svg { flex-shrink: 0; }
.shop-flash--notice { background: #f0fdf4; border-color: #a7d7b4; color: #14532d; }
.shop-flash--alert  { background: #fef2f2; border-color: #f3b4b4; color: #991b1b; }

/* ---- lightbox (product quick-view; IDs/structure preserved, JS-driven) ---- */
.lb { position: fixed; inset: 0; z-index: 200; display: none; }
.lb.is-open { display: block; }
.lb__backdrop { position: absolute; inset: 0; background: rgba(0,0,0,.5); }
.lb__close { position: absolute; top: 16px; right: 18px; z-index: 2; background: none; border: none; font-size: 18px; color: var(--ink); cursor: pointer; }
.lb__panel { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: min(880px, 94vw); max-height: 90vh; overflow: auto; background: var(--paper); border: 1px solid var(--line); display: grid; grid-template-columns: 1fr 1fr; }
@media (max-width: 720px) {
  /* #2: on mobile the panel stacks, so a 1:1 image would fill the screen and
     push Add to Cart below the fold. Cap the image to a band and move its
     divider to the bottom edge. */
  .lb__panel { grid-template-columns: 1fr; }
  .lb__img-wrap { aspect-ratio: auto; max-height: 34vh; border-right: none; border-bottom: 1px solid var(--line); padding: 16px; }
}
.lb__img-wrap { aspect-ratio: 1 / 1; border-right: 1px solid var(--line); display: flex; align-items: center; justify-content: center; padding: 28px; }
.lb__img { max-width: 100%; max-height: 100%; object-fit: contain; }
.lb__no-img { color: var(--faintest); font-size: 11px; text-transform: uppercase; letter-spacing: .1em; }
.lb__side { padding: 32px; display: flex; flex-direction: column; gap: 16px; }

/* ---- cart drawer (IDs/structure preserved, JS-driven) ---- */
.cd { position: fixed; inset: 0; z-index: 100; display: none; }
.cd.is-open { display: block; }
.cd__backdrop { position: absolute; inset: 0; }
.cd__panel { position: absolute; top: 0; right: 0; bottom: 0; width: min(380px, 100vw); background: var(--paper); border-left: 1px solid var(--line); display: flex; flex-direction: column; transform: translateX(100%); transition: transform .2s ease; }
.cd.is-open .cd__panel { transform: translateX(0); }
.cd__head { display: flex; justify-content: space-between; align-items: center; padding: 14px 20px; border-bottom: 1px solid var(--line); }
.cd__head-title { font-size: 10px; font-weight: 300; text-transform: uppercase; letter-spacing: .12em; color: var(--muted); }
.cd__close { background: none; border: none; cursor: pointer; font-size: 16px; color: var(--faint); }
.cd__body { flex: 1; overflow-y: auto; }
.cd__empty { padding: 60px 20px; text-align: center; display: flex; flex-direction: column; gap: 20px; align-items: center; font-size: 10px; text-transform: uppercase; letter-spacing: .1em; color: var(--faintest); }
.cd__item { display: grid; grid-template-columns: 48px 1fr; gap: 12px; padding: 16px 20px; border-bottom: 1px solid var(--line); align-items: start; }
.cd__item-img, .cd__item-img-ph { width: 48px; height: 48px; border: 1px solid var(--line-soft); padding: 3px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.cd__item-img img { max-width: 100%; max-height: 100%; object-fit: contain; }
.cd__item-name { font-size: 11px; color: var(--ink); margin-bottom: 2px; }
.cd__item-price { font-size: 11px; color: var(--ink); }
.cd__item-stepper { display: flex; align-items: center; gap: 12px; }
.cd__item-stepper button { background: none; border: none; cursor: pointer; font-size: 14px; line-height: 1; color: var(--ink); }
.cd__item-remove { background: none; border: none; cursor: pointer; font-size: 10px; text-transform: uppercase; letter-spacing: .06em; color: var(--faintest); padding: 6px 0 0; }
.cd__foot { padding: 16px 20px; border-top: 1px solid var(--line); }
.cd__foot-row { display: flex; justify-content: space-between; margin-bottom: 16px; }
.cd__foot-label { font-size: 10px; text-transform: uppercase; letter-spacing: .1em; color: var(--muted); }
.cd__foot-total { font-size: 11px; color: var(--ink); }

/* ---- toasts ---- */
.toast-rack { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); z-index: 300; display: flex; flex-direction: column; gap: 8px; }
.toast { background: var(--ink); color: #fff; font-size: 11px; letter-spacing: .04em; padding: 12px 18px; opacity: 0; transform: translateY(8px); transition: opacity .2s, transform .2s; }
.toast--show { opacity: 1; transform: translateY(0); }
.toast--error { background: var(--danger); }

/* ---- hero (landing) ---- */
.hero { padding: 64px 0 40px; }
.hero__title { font-size: clamp(32px, 6vw, 56px); font-weight: 300; line-height: 1.05; letter-spacing: -.01em; }
.hero__sub { font-size: 12px; text-transform: uppercase; letter-spacing: .14em; color: var(--muted); margin-top: 16px; }

/* ---- helpers / pills ---- */
.pill { display: inline-block; font-size: 9px; font-weight: 400; text-transform: uppercase; letter-spacing: .08em; color: var(--ink); border: 1px solid var(--line); padding: 3px 8px; }
.u-label { font-size: 11px; font-weight: 400; text-transform: uppercase; letter-spacing: .1em; color: var(--muted); }
.u-eyebrow { font-size: 10px; font-weight: 400; text-transform: uppercase; letter-spacing: .12em; color: var(--muted); }

/* ---- utilities (kept compatible with existing markup) ---- */
.flex { display: flex; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.gap-2 { gap: 8px; }
.gap-4 { gap: 16px; }
.mb-4 { margin-bottom: 16px; }
.mb-8 { margin-bottom: 32px; }
.w-full { width: 100%; }
.text-right { text-align: right; }
.text-sm { font-size: 11px; }
.text-upper { text-transform: uppercase; letter-spacing: .08em; }
.text-muted { color: var(--muted); }

/* ============================================================================
 * Motion - subtle micro-interactions (#kang-motion-pass)
 * Understated to match the monochrome aesthetic: short durations, tiny
 * movements, no bounce/elastic easings. All neutralised under
 * prefers-reduced-motion at the bottom of this block.
 * ==========================================================================*/

/* ---- scroll reveal (driven by reveal_controller.js) ----
 * The hidden initial state is applied by the controller adding `.reveal`, so
 * with JS off nothing is ever hidden (no-JS fallback shows everything). When
 * the element enters the viewport the controller adds `.reveal--in`. */
/* !important: the reveal is a cross-cutting animation utility that must beat
 * component rules which land later in the cascade at equal specificity - e.g.
 * application.css's `.product-grid .product-card` (#101) sets transform/opacity
 * on cards and otherwise wins by load order, leaving the card visible so the
 * reveal never animates. `.reveal--in` is declared after `.reveal`, so for a
 * revealed element (which carries both classes) the !important `--in` values win. */
.shop-body .reveal {
  opacity: 0 !important;
  transform: translateY(14px) !important;
  transition: opacity .42s ease, transform .42s ease;
  will-change: opacity, transform;
}
.shop-body .reveal--in {
  opacity: 1 !important;
  transform: none !important;
  will-change: auto;
}

/* ---- button micro-interactions ----
 * Lift 1px on hover, settle back + slightly dim on active. Only `transform` and
 * `opacity` are new here; the background/color transitions are restated so the
 * single `transition` declaration covers all four properties.
 * (Product-card hover/active motion lives in application.css alongside the #101
 * grid-card polish, where the higher .product-grid specificity wins the cascade
 * - duplicating it here would be dead CSS.) */
.btn {
  transition: background .15s, color .15s, border-color .15s, transform .15s ease, opacity .15s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); opacity: .9; }

/* ---- reduced motion: neutralise the reveal + button motion added above ----
 * (#101's reduced-motion block in application.css neutralises the card motion.) */
@media (prefers-reduced-motion: reduce) {
  .shop-body .reveal,
  .shop-body .reveal--in {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    will-change: auto;
  }
  .btn,
  .btn:hover,
  .btn:active {
    transform: none;
    opacity: 1;
    transition: background .15s, color .15s, border-color .15s;
  }
}

/* ---- Order progress timeline (shop/orders/_status_timeline) ----
   Vertical on mobile, horizontal from 620px. Steps not yet reached are muted
   rather than hidden, so the customer can see what is still to come. */
.order-timeline {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 18px;
}
.order-timeline__step {
  position: relative;
  display: grid;
  grid-template-columns: 26px 1fr;
  grid-template-areas: "marker label" "marker date";
  column-gap: 12px;
  align-items: center;
}
.order-timeline__marker {
  grid-area: marker;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--paper);
}
.order-timeline__marker svg { width: 12px; height: 12px; }
.is-done .order-timeline__marker { background: var(--ink); border-color: var(--ink); }
.is-current .order-timeline__marker { box-shadow: 0 0 0 3px var(--wash); }
.order-timeline__label {
  grid-area: label;
  font-size: 12px;
  color: var(--muted);
  line-height: 1.3;
}
.is-done .order-timeline__label { color: var(--ink); }
.is-current .order-timeline__label { font-weight: 500; }
.order-timeline__date {
  grid-area: date;
  font-size: 10px;
  letter-spacing: .04em;
  color: var(--faint);
}
.order-timeline__bar {
  position: absolute;
  left: 10px;
  top: 24px;
  width: 1px;
  height: calc(100% + 18px - 24px);
  background: var(--line);
}
.is-done .order-timeline__bar { background: var(--ink); }

@media (min-width: 620px) {
  .order-timeline {
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 0;
  }
  .order-timeline__step {
    grid-template-columns: 1fr;
    grid-template-areas: "marker" "label" "date";
    justify-items: center;
    text-align: center;
    row-gap: 8px;
    padding: 0 6px;
  }
  .order-timeline__bar {
    left: calc(50% + 15px);
    top: 10px;
    width: calc(100% - 30px);
    height: 1px;
  }
}
