/* ===========================================================================
   Skincare vertical · COMPONENTS — 06-system/DESIGN.md, implemented exactly.

   This is the authoritative reskin layer. It loads last.

   IT NO LONGER OWNS THE RADIUS SCALE. It used to, for a structural reason:
   primitives.css loaded after tokens.css and redefined --radius-*, so a brand
   could not set radii from its own token file and the vertical was the only
   layer late enough to win. primitives.css now CONSUMES --p-radius-* instead
   of defining it, so radius is a brand knob again and the seven declarations
   that used to sit here were redundant — identical values, stated twice.
   Set radius in brands/<b>/tokens/primitives.tokens.json.

   THE ONE DOCUMENTED DEVIATION from the playbook is the page ground: the
   system's bg is neutral-100 (warm cream) and the founder chose pure white.
   Everything else here is the spec's own value. That means cards, inputs and
   chips are WARM CREAM surfaces on a white ground, which is the intended
   look — not a neutral-grey UI with blue accents.

   PALETTE RATIO (brand kit, set-level target): cream ~40% of pixels, cupric
   ~25% at full intensity, pale steps ~20%, ink and deep blues ~15%. A grid of
   23 flooded product cards inverts that to ~80% saturated blue, which is why
   the flood is scoped below to where DESIGN.md actually puts it: the PDP
   gallery panel and "flood cards of the 3-step routine, ramp-ordered".
   =========================================================================== */

:root {
  /* shadow: cards default to border and NO shadow; shadow on interaction */
  --shadow-sm: 0 1px 2px color-mix(in oklab, var(--foreground) 6%, transparent);
  --shadow-md: 0 4px 12px color-mix(in oklab, var(--foreground) 8%, transparent);
  --shadow-lg: 0 12px 32px color-mix(in oklab, var(--foreground) 10%, transparent);
  --elevation-card: none;
  --elevation-whisper: none;
  --elevation-key: none;
  --elevation-lift: var(--shadow-sm);
  --elevation-pop: var(--shadow-lg);

  --ms-ease: cubic-bezier(.32,.72,0,1);
}

/* ---------------------------------------------------------------- TYPE ---- */
body { font-family: var(--font-sans); font-weight: 400; }
/* Vertical sheets load LAST, so this rule outranks both the engine's h1-h6 and
   primitives' .title-2xl. It said var(--font-sans), which meant the skincare
   site never actually rendered .title-2xl in the display face at all — the
   engine and docs claimed a display/voice split that this one line quietly
   cancelled. Only .sk-hero__h1, which carries its own class, escaped it.
   2026-08-21: pointed at the display face, which is what it always described. */
h1,h2,h3,h4,h5,h6, .ms-title, .title-2xl { font-family: var(--font-display); font-weight: 600; letter-spacing: var(--p-tracking-n20); }
/* Martian Mono is the evidence: every number that makes a claim. */
.u-mono, .u-data, code, kbd, samp,
.ms-crumbs, .chip-cat, .shopcard__spec, .shopcard__price, .pdp-price,
.ms-eyebrow, .ms-count, .pill__count { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.ms-eyebrow { letter-spacing: var(--p-tracking-8); text-transform: uppercase; font-size: var(--p-text-12); color: var(--ink-3); }

/* --------------------------------------------------------------- BUTTON ---
   GS 500, lowercase, pill. sm h32 px12 · default h40 px16 · lg h48 px24.     */
.btn, .ms-btn {
  font-family: var(--font-sans); font-weight: 500; text-transform: lowercase;
  border-radius: var(--radius-pill); border-width: 1.5px; letter-spacing: var(--p-tracking-0);
  transition: background-color 150ms var(--ms-ease), color 150ms var(--ms-ease),
              border-color 150ms var(--ms-ease), transform 150ms var(--ms-ease);
  box-shadow: none;
}
.btn:active, .ms-btn:active { transform: translateY(1px); }
.btn--sm, .ms-btn--sm { height: 32px; padding-inline: var(--p-space-3); font-size: var(--p-text-14); }
.btn--md, .btn--lg, .ms-btn { height: 40px; padding-inline: var(--p-space-4); font-size: var(--p-text-14); }
.btn--lg  { height: 48px; padding-inline: var(--p-space-6); font-size: var(--p-text-16); }
.btn--xl, .ms-btn--xl { height: 48px; padding-inline: var(--p-space-6); font-size: var(--p-text-16); }

/* primary — WHITE label, not the spec's neutral-100 cream.
   Same argument as the neutrals: cream-on-cupric was drawn for a cream page,
   where the label reads as continuous with the ground. On a white page it is a
   dimmed white — the highest-attention element going slightly muddy. Cream
   still owns the DARK stages (topbar, ink bands), which is where the law
   actually puts it. */
.btn--cta, .ms-btn--brand { background: var(--brand); color: var(--brand-foreground); border-color: transparent; }
.btn--cta:hover, .ms-btn--brand:hover { background: var(--brand-hover); color: var(--brand-foreground); }
.btn--cta:active { background: var(--brand-active); }
/* disabled was tan-on-brown (#D1CABB fill / #6F6B63 label) — a mud slab. */
.btn--cta[disabled], .btn--cta:disabled { background: var(--control-disabled); color: var(--ink-4); box-shadow: none; pointer-events: none; }

.btn--secondary { background: var(--muted); color: var(--foreground); border-color: transparent; }
.btn--secondary:hover { background: var(--brand-muted); }

.btn--outline { background: var(--surface); border: 1px solid var(--border-strong); color: var(--foreground); box-shadow: 0 1px 2px color-mix(in oklab, var(--brand) 5%, transparent); }
.btn--outline:hover { background: var(--brand-muted); border-color: var(--border-hover); color: var(--brand-hover); }
.btn--outline:active { background: var(--brand-muted); border-color: var(--ring); }

.btn--ghost { background: transparent; color: var(--brand); border-color: transparent; }
.btn--ghost:hover { background: var(--brand-muted); color: var(--brand); }

.btn--ink, .ms-btn--onink { background: var(--foreground); color: var(--on-dark-warm); border-color: transparent; }
.btn--ink:hover { background: var(--ink-band-2); color: var(--on-dark-warm); }

/* focus is global: 2px cupric, offset 2 */
.btn:focus-visible, .ms-btn:focus-visible, a:focus-visible, button:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--ring); outline-offset: 2px;
}

/* ---------------------------------------------------------------- INPUT ---
   Light, not muddy. The playbook's input (cream fill, 1.5px neutral-600 edge)
   was drawn for a cream page; on white it reads brown. Here: white fill, a
   blue-derived edge, a very slight resting shadow so the control lifts off
   the surface without a box around it, and a focus ring in the brand colour.

   EVERY BARE ELEMENT SELECTOR IN THIS BLOCK IS WRAPPED IN :where().

   This is a form BASELINE, and a baseline must never out-rank the component
   that owns a control. `input[type="number"]` is (0,1,1) and beat
   `.pdp-qty__input` (0,1,0), so the PDP quantity stepper — which asks for a
   chromeless number in the middle of a pill — was served this rule's border,
   radius, white fill and sans font instead, and rendered as a box inside a
   box. The same collision was patched once before, one selector at a time
   (see .ms-search__input below), which fixed that instance and left the
   class of bug in place.

   :where() has specificity zero, so any component class now wins by
   construction and no future component has to know this file exists.        */
:where(input[type="text"], input[type="search"], input[type="email"], input[type="password"],
input[type="tel"], input[type="number"], input[type="url"], textarea, select),
.control, .ms-search__input, .ms-sort {
  font-family: var(--font-sans); font-size: var(--p-text-15); color: var(--foreground);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  min-height: 40px; padding-inline: var(--p-space-3-5);
  /* NOT padding-inline on the search field: shop.css reserves 2.5rem on the
     left for the magnifier, and a blanket padding-inline overrode it, so the
     icon sat on top of the placeholder. Scoped back below. */
  box-shadow: 0 1px 2px color-mix(in oklab, var(--brand) 5%, transparent), 0 1px 1px color-mix(in oklab, var(--foreground) 2%, transparent);
  transition: border-color 150ms var(--ms-ease), box-shadow 150ms var(--ms-ease);
  appearance: none; -webkit-appearance: none;
}
:where(select) { padding-inline-end: var(--p-space-9); background-repeat: no-repeat;
  background-position: right 0.75rem center; background-size: 0.7rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%230B55CE' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E"); }
:where(textarea) { min-height: 96px; padding-block: var(--p-space-2-5); }
/* Was `.ms-search input.ms-search__input` — an extra element bolted on purely
   to out-specify `input[type="search"]` above. That selector is now :where()d
   at zero, so the plain class carries it. */
.ms-search__input { padding-left: var(--p-space-10); padding-right: var(--p-space-3); }
/* --ink-4, not the warm neutral-500 it used to name. The founder's 2026-08-19
   direction replaced the warm text greys with contrast-matched cool ones
   (tokens.css: "ink-400 3.34 vs #928D83 3.30"); the placeholder and the
   disabled label were the two declarations that missed it. This is that
   migration finished, not a new decision — #928D83 → #6D7687. */
:where(input, textarea)::placeholder { color: var(--ink-4); }
:where(input, textarea, select):hover, .control:hover { border-color: var(--border-hover); }
:where(input:focus, input:focus-visible, textarea:focus, select:focus), .control:focus {
  border-color: var(--ring); outline: none;
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--brand) 16%, transparent), 0 1px 2px color-mix(in oklab, var(--brand) 8%, transparent);
}
:where(input[aria-invalid="true"]), input.is-error {
  border-color: var(--destructive); box-shadow: 0 0 0 3px color-mix(in oklab, var(--destructive) 16%, transparent);
}
:where(input:disabled, textarea:disabled, select:disabled) {
  background: var(--muted); border-color: var(--border); color: var(--ink-4); box-shadow: none;
}
:where(label) { font-family: var(--font-sans); font-weight: 500; font-size: var(--p-text-14); color: var(--foreground); }
:where(input[type="checkbox"], input[type="radio"]) { accent-color: var(--brand); }

/* ------------------------------------------------------ BADGE / CHIP ------
   bg blue-100, fg blue-500, pill. Dose chips in mono caps.                   */
/* `line-height: 1` on a tracked-out mono cap leaves nothing under the baseline,
   so the pill sat optically low beside anything it labelled and clipped any
   descender that reached it — and the badge string is editor-supplied free
   text, so descenders do reach it. Side padding is asymmetric on purpose:
   letter-spacing adds a trailing space after the final glyph, and equal
   padding therefore always reads right-heavy on caps. */
.chip-cat, .shopcard__badge, .ms-badge, .badge {
  display: inline-flex; align-items: center;
  background: var(--brand-muted); color: var(--brand);
  border-radius: var(--radius-chip); border: none;
  /* Was 11px. Brand law §2: "Minimum text size 0.75rem / 12px. Nothing ships
     smaller, anywhere." A badge is the smallest type in the system, which is
     exactly why it was the one breaking the floor. */
  font-family: var(--font-mono); font-size: var(--p-text-12); letter-spacing: var(--p-tracking-6);
  text-transform: uppercase; line-height: 1.45;
  padding-block: var(--p-space-1);
  padding-inline: var(--p-space-2-5) calc(var(--p-space-2-5) - 0.0625rem);
  white-space: nowrap;
}
/* filter pills: inactive = tinted, active = cupric with a cream label */
.pill {
  font-family: var(--font-sans); font-weight: 500; font-size: var(--p-text-14);
  background: var(--brand-muted); color: var(--brand);
  border: 1.5px solid transparent; border-radius: var(--radius-pill);
  height: 36px; padding-inline: var(--p-space-3-5);
  transition: background-color 150ms var(--ms-ease), color 150ms var(--ms-ease);
}
.pill:hover { background: var(--brand-muted-hover); color: var(--brand-hover); }
/* `.is-active` is NOT in this list, though it was until 2026-08-20. The engine
   mirrors every pseudo-class onto an `.is-*` twin so /design can show states it
   cannot hover — `.pill:active, .pill.is-active { transform: scale(0.98) }` in
   primitives.css. Claiming `.is-active` for "this is the chosen filter" made the
   two meanings collide, and the specimen's active column drew the selected pill.
   Nothing ever put `is-active` on a pill in markup or JS, so the selector was
   shadowing the mirror for no one. `.is-on` is the class the nav actually uses. */
.pill[aria-selected="true"], .pill.is-on {
  background: var(--brand); color: var(--on-dark-warm);
}
.pill__count { font-family: var(--font-mono); opacity: .75; margin-inline-start: 0.4rem; font-size: var(--p-text-12); }

/* view toggle — it inherited the UA button (Arial, 4.8px radius) */
.ms-viewtoggle { border: 1px solid var(--border-strong); border-radius: var(--radius-pill); padding: var(--p-space-0-5); background: var(--surface); box-shadow: 0 1px 2px color-mix(in oklab, var(--brand) 5%, transparent); }
.ms-viewtoggle__btn {
  font-family: var(--font-sans); background: transparent; color: var(--ink-3);
  border: none; border-radius: var(--radius-pill); height: 32px; width: 36px;
  display: grid; place-items: center; box-shadow: none;
  transition: background-color 150ms var(--ms-ease), color 150ms var(--ms-ease);
}
.ms-viewtoggle__btn:hover { color: var(--foreground); background: var(--brand-muted); }
/* White, not cream — same rule as .btn--cta: cream is for the dark stages,
   white for a label sitting on saturated cupric. */
.ms-viewtoggle__btn.is-active { background: var(--brand); color: var(--brand-foreground); }

/* ----------------------------------------------------------------- CARD ---
   White card on a white page: definition comes from a blue-derived hairline
   plus a whisper of blue-tinted shadow, and the card lifts on hover. The
   photograph keeps its own cream stage, so the card reads as a photo panel
   over a clean white info panel rather than one flat beige block.          */
/* A GENERIC CARD WITH NO PADDING IS NOT A CARD. This rule set background,
   border, radius, shadow and overflow for all three classes and padding for
   none of them. `.shopcard` gets away with it — its `__stage` and `__body`
   children own the inset, and adding padding here would double it. `.ms-card`
   and `.card` have no such children: they wrap whatever they are given, and
   that content was landing flush against the border. Padded separately, below
   the shared rule, so the shopcard is untouched. */
.shopcard, .ms-card, .card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 1px 2px color-mix(in oklab, var(--brand) 5%, transparent), 0 1px 1px color-mix(in oklab, var(--foreground) 2%, transparent);
  overflow: hidden;
  transition: border-color 150ms var(--ms-ease), box-shadow 250ms var(--ms-ease), transform 250ms var(--ms-ease);
}
.shopcard:hover {
  border-color: var(--border-hover);
  box-shadow: 0 10px 24px -10px color-mix(in oklab, var(--brand) 20%, transparent), 0 2px 6px color-mix(in oklab, var(--foreground) 4%, transparent);
  transform: translateY(-2px);
}
.ms-card, .card { padding: var(--p-space-5); }
.ms-card > :first-child, .card > :first-child { margin-block-start: 0; }
.ms-card > :last-child,  .card > :last-child  { margin-block-end: 0; }

.shopcard__stage { background: transparent; border-radius: 0; }
.shopcard__stage img { mix-blend-mode: normal; }
.shopcard__body { color: var(--foreground); background: var(--surface); border-top: 1px solid var(--border); }
.shopcard__tagline { color: var(--ink-2); }
.shopcard__spec, .shopcard__cpm, .shopcard__dose { color: var(--ink-3); font-family: var(--font-mono); }
.shopcard__price { font-family: var(--font-mono); color: var(--foreground); }

/* -------------------------------------------------------------- CHROME ---- */
.ms-topbar { background: var(--surface-ink); }          /* spec: blue-800 */
.ms-topbar__text { color: var(--on-dark-warm); font-family: var(--font-mono); font-size: var(--p-text-12); letter-spacing: var(--p-tracking-6); text-transform: uppercase; }
/* was --p-neutral-200 (#D1CABB): a tan hairline under the STICKY header, so
   the warmest line on the site sat above every page at all times. */
.ms-header { background: var(--background); border-bottom: 1px solid var(--border); }
.ms-header__bar { min-height: 72px; }
.ms-nav__link { font-family: var(--font-sans); font-weight: 500; font-size: var(--p-text-15); text-transform: lowercase; color: var(--foreground); }
.ms-nav__link:hover { color: var(--brand); }
/* Underline comes from the engine's animated .ms-nav__link::after bar; adding
   text-decoration here drew a second line under the current link. Colour only.
   Dropped a paired `[aria-current]` selector that matched nothing: the only two
   places that emit `.ms-nav__link` (chrome.php's navgroup trigger and its plain
   link, both desktop) set `is-current`, and storefront.js never sets the
   attribute. The mobile drawer is a separate component, `.ms-mobilenav__link`,
   dressed by the engine. */
.ms-nav__link.is-current { color: var(--brand); }
.ms-cart-count { background: var(--brand); color: var(--brand-foreground); font-family: var(--font-mono); font-size: var(--p-text-12); border-radius: var(--radius-pill); }
.ms-crumbs { font-family: var(--font-mono); font-size: var(--p-text-12); letter-spacing: var(--p-tracking-6); text-transform: uppercase; color: var(--ink-3); }
.ms-crumbs a { color: var(--ink-3); }
.ms-crumbs a:hover { color: var(--brand); }

/* ------------------------------------------------------- DATA / TABLES ----
   Data tables are hairline-ruled, radius 0, mono, and never animated.        */
table, .ms-table { border-collapse: collapse; border-radius: 0; font-family: var(--font-sans); }
/* CELLS HAD NO PADDING. `border-bottom` was the whole rule, so every data
   table in the theme rendered with its text sitting directly on the rule
   beneath it and touching the row above. Hairline-ruled and radius 0 is the
   brand; airless is not. Row height is the only thing making a spec table
   scannable, and it was the one property not set. */
table th, table td {
  border-bottom: 1px solid var(--border);
  padding: var(--p-space-2-5) var(--p-space-4) var(--p-space-2-5) 0;
  vertical-align: baseline;
}
table th:last-child, table td:last-child { padding-inline-end: 0; }
table th {
  font-family: var(--font-mono); font-size: var(--p-text-12); letter-spacing: var(--p-tracking-6);
  text-transform: uppercase; color: var(--ink-3); font-weight: 400; text-align: left;
  padding-bottom: var(--p-space-2);
}
/* A spec table is read by comparing one row against the next, which only works
   when the digits line up. Deliberately NOT setting a font-size here: `table td`
   also reaches cart, checkout and account, and their cell sizes are each their
   own decision. */
table td { color: var(--foreground); font-variant-numeric: tabular-nums; }
table tbody tr:last-child :is(th, td) { border-bottom: 0; }

/* callout — NOTE THE MISSING .pdp-callout HERE, deliberately.
   This rule used to catch .pdp-callout too and repainted it #FAECD7 sand on
   #7D4D05 brown, which put the two muddiest values on the site directly on
   top of the product photo. The engine already styles .pdp-callout as a
   glass chip on --border/--background and it was correct; the vertical was
   overriding good work. Only the generic callout is styled here now. */
/* A CALLOUT WAS BEING SET IN MONOSPACE. The component's whole job is to carry
   one sentence worth stopping for — a sentence, in the brand's body face. Mono
   is this brand's voice for DATA: doses, sizes, SKUs, prices, protocol codes.
   Spending it on prose costs the mono its meaning and costs the sentence its
   readability, which is why the specimen read as a code block that had lost
   its syntax highlighting.

   Structure replaces the box: a cupric rule down the leading edge marks the
   aside, so it is legible as one without a strong border and a shadow both
   competing with whatever it interrupts. */
.ms-callout {
  background: var(--surface); color: var(--foreground);
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--brand);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  box-shadow: none;
  font-family: var(--font-sans);
  font-size: var(--p-text-15);
  line-height: var(--leading-body);
  padding: var(--p-space-4) var(--p-space-5);
}
.ms-callout > :first-child { margin-block-start: 0; }
.ms-callout > :last-child { margin-block-end: 0; }

@media (prefers-reduced-motion: reduce) {
  .btn, .ms-btn, .shopcard, .pill { transition: none; }
  .btn:active, .ms-btn:active { transform: none; }
}

/* ------------------------------------------------------------- ACCOUNT ----
   Inputs are radius sm (8px) everywhere. account.css styles its nav pills and
   its form fields off --radius-2xl, which the brand sets to 16 for CARDS, so
   the login fields came out as near-pills. Inputs are pinned here. */
.acct-card input, .acct-card select, .acct-card textarea,
.woocommerce-Input, .woocommerce form .form-row input.input-text,
.woocommerce form .form-row textarea, .woocommerce form .form-row select {
  border-radius: var(--radius-sm) !important;
  background: var(--surface); border: 1px solid var(--border-strong);
  min-height: 40px; font-family: var(--font-sans);
  box-shadow: 0 1px 2px color-mix(in oklab, var(--brand) 5%, transparent);
}
.acct-nav__item { border-radius: var(--radius-pill); }
.acct-display, .acct-h2 { font-family: var(--font-display); font-weight: 600; letter-spacing: var(--p-tracking-n20); }
.woocommerce form .form-row label { font-family: var(--font-sans); font-weight: 500; }
/* WooCommerce ships `.woocommerce form .form-row .required { color:#a00 }` at
   (0,4,0). The pair below was (0,2,0) and lost, so a raw #AA0000 asterisk —
   a hue that exists nowhere in the palette — was painting on every account
   and checkout form. Matched selector-for-selector rather than !important. */
.required, .woocommerce .required,
.woocommerce form .form-row .required,
.woocommerce form .form-row abbr.required { color: var(--destructive); text-decoration: none; }

/* ------------------------------------------------------------ PDP PANEL ---
   DESIGN.md: "Gallery: panel radius md, bg = SKU flood colour"; thumbnails
   64px radius sm, selected border 2px blue-500. */
/* DESIGN.md puts the SKU flood behind the gallery packshot. That assumes a
   CUTOUT product; ours are full-frame photographs that carry their own stage,
   so a flood behind them renders as cupric bars above and below the image
   (observed). The panel keeps the spec's radius and the photograph keeps its
   own ground. The data-band attribute stays on the element for any future
   cutout set. */
.pdp-gallery__main { border-radius: var(--radius-md); overflow: hidden; }
/* `.pdp-gallery__thumb` was never emitted — ms_pdp_gallery() writes
   `.pdp-thumb`, and `[aria-current]` is never set either (the rail uses
   role="tab" + aria-selected). Both halves of this rule matched nothing, so
   the engine's own near-black active border went unchallenged. The thumbnail
   rail is owned end-to-end by engine/assets/pdp.css now; nothing to override
   from here. */

/* ------------------------------------------------------- WOO CART BLOCKS --
   The cart page renders WooCommerce's own blocks, which ship a mascot-ish
   empty state and Title Case headings. Brand law §7.6 bans mascots and
   exclamation marks in UI; headings are lowercase-forward. */
/* The empty-bag mascot and its copy are handled in PHP (render_block), not
   here: the graphic is an <img> whose src is unpredictable and the string
   never passes through gettext. */
.wc-block-cart, .wp-block-woocommerce-empty-cart-block { font-family: var(--font-sans); }
.wc-block-cart h2, .wp-block-woocommerce-empty-cart-block h2,
.wc-block-cart__empty-cart__title { text-transform: lowercase; font-weight: 600; letter-spacing: var(--p-tracking-n20); }
/* Split 2026-08-21. These were one rule, but they are not one thing: a grid
   product title is a HEADING and takes the display face; a cart line-item name
   is a UI row and stays in the voice. Bundling them meant the heading followed
   the row. */
.wc-block-grid__product-title { font-family: var(--font-display); text-transform: lowercase; }
.wc-block-cart-item__product-name { font-family: var(--font-sans); text-transform: lowercase; }
.wc-block-components-button, .wc-block-cart__submit-button {
  border-radius: var(--radius-pill) !important; background: var(--brand) !important;
  color: var(--on-dark-warm) !important; font-family: var(--font-sans); font-weight: 500; text-transform: lowercase;
}

/* ---------------------------------------------------------------------------
   SHOP CARD — ROW LAYOUT

   ms_shop_card($p, $priority, 'row') has always emitted .shopcard--row, and
   nothing has ever styled it. The variant fell back to the column layout with
   an unconstrained stage, so the media rendered full-bleed and the card was
   taller than the viewport. It was never called on the storefront, so nothing
   caught it until /design/commerce rendered both layouts side by side — which
   is the entire reason a component catalogue is worth having.

   Implemented rather than deleted: a horizontal card is what a related rail, a
   search result and a cart line all want, and the grid card already carries the
   right data. Geometry follows .flood--row, which solved the same problem for
   the flood cards.
--------------------------------------------------------------------------- */
.shopcard--row {
  flex-direction: row;
  align-items: stretch;
  max-width: 34rem;
}
.shopcard--row .shopcard__stage {
  aspect-ratio: 1;
  width: var(--p-space-24);
  flex: 0 0 var(--p-space-24);
  border-radius: var(--radius-card) 0 0 var(--radius-card);
}
.shopcard--row .shopcard__body {
  flex: 1;
  min-width: 0;
  border-top: none;
  border-left: 1px solid var(--border);
}
.shopcard--row .shopcard__tagline {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
@media (max-width: 480px) {
  /* Below the fold of a phone a row card is narrower than its own media, so it
     falls back to the column it already knows how to be. */
  .shopcard--row { flex-direction: column; max-width: none; }
  .shopcard--row .shopcard__stage {
    width: 100%; flex: none; border-radius: var(--radius-card) var(--radius-card) 0 0;
  }
  .shopcard--row .shopcard__body { border-left: none; border-top: 1px solid var(--border); }
}
