/* ==========================================================================
   PinkyDolly V2 — Design Tokens & Brand Foundation
   Phase 1 (see /pd-v2-brief.md §3, §6, §18)

   Load order: this file must load AFTER pinkydolly-source-variables.css
   (see layout/theme.html) so the --pls-* bridge below can override the
   Anvogue/PressLayouts factory values on body{}.

   Scope: values only. No selectors here restyle legacy markup beyond the
   --pls-* custom-property bridge; legacy sections keep their own rules and
   simply inherit new colors/radius/fonts through the variables they already
   reference. New markup should use pd-v2-* classes, not these internals.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Self-hosted variable fonts
   @font-face lives in layout/theme.html, not here — a relative
   src:url('../font/x.woff2') in a plain .css file resolves against that
   CSS file's own CDN path, and this CDN hashes every asset's path
   independently, so the relative URL silently 403s once pd-v2-tokens.css
   has a different hash than the font files (which is any time either has
   changed since the other). theme.html can use asset_url() per file
   (same helper the font preload links already use), a plain .css file
   can't. See the <style> block right after the preload links there.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   2. Design tokens — the single source of truth (brief §3, §6.2)
   -------------------------------------------------------------------------- */
:root {
  /* ---- color: brand (CONFIRMED, brief §3.1) ---- */
  --pd-paper:       #FFF7F1; /* warm white — page base */
  --pd-ink:         #262026; /* warm black — body text */
  --pd-main-1:      #F1B1FF; /* lilac — backgrounds / gradients only */
  --pd-main-2:      #FF9DCA; /* pink — backgrounds / gradients only */
  --pd-act:         #CB025C; /* primary, text-safe (5.35:1 on white) */
  --pd-act-raw:     #FE0373; /* primary raw — solid blocks/badges/hover fills ONLY, never text */
  --pd-act-2:       #A922D1; /* secondary, text-safe (5.17:1 on white) */
  --pd-act-2-raw:   #C527F3; /* secondary raw — solid blocks/badges/hover fills ONLY, never text */
  --pd-mint:        #9AF5D8; /* info: stock / shipping guarantee / success — chip/icon use, not page bg */
  --pd-lemon:       #FFF14F; /* info: promo badges / countdown / hot flag — chip use, not page bg */

  /* ---- color: neutral scale, derived from --pd-ink (not a new brand hue) ----
     Used for hairlines, hover washes and disabled states so we don't invent
     an off-palette gray. Needs no separate sign-off — it's --pd-ink at opacity. */
  --pd-ink-08:  rgba(38, 32, 38, 0.08);
  --pd-ink-16:  rgba(38, 32, 38, 0.16);
  --pd-ink-35:  rgba(38, 32, 38, 0.35);
  --pd-ink-60:  rgba(38, 32, 38, 0.60);
  --pd-paper-16: rgba(255, 247, 241, 0.16); /* hairline for use on dark/ink surfaces */
  --pd-hairline:         var(--pd-ink-16);
  --pd-hairline-inverse: var(--pd-paper-16);

  /* ---- color: functional (RECOMMENDATION — not in brief §3.1, needs Yimei sign-off) ----
     Form validation needs an error tone the brand palette doesn't define.
     Carried forward from the legacy --pls-critical-color value rather than
     inventing a new hue. Flag before Phase 3 form-state work ships. */
  --pd-danger:      #DB4444;
  --pd-danger-ink:  #7A1414;

  /* ---- color: sold-out text (CONFIRMED, brief §3.6 V1.3 — literal value, not derived) ---- */
  --pd-mute: #6E626E;

  /* ---- shape (CONFIRMED, brief §3.5) ---- */
  --pd-radius:      6px;
  --pd-radius-pill: 999px; /* badges & filter chips only */

  /* ---- type: families (CONFIRMED, brief §3.3/§3.4) ---- */
  --pd-disp:      'Fraunces', Georgia, serif;
  /* No "opsz" — superseded by handover/v2 SPEC §0.1: optical size now
     tracks font-size via font-optical-sizing:auto (set on html, inherited)
     instead of being pinned to one value, matching Figma's own default
     behavior. SOFT/WONK stay locked. */
  --pd-disp-axis: "SOFT" 0, "WONK" 0;
  --pd-body:      'Nunito Sans', system-ui, -apple-system, sans-serif;

  /* ---- type: display scale — Fraunces, brief §3.3 six-level table ----
     t1/t2 weight+tracking updated per handover/v2 SPEC §0.1: level-1 max
     is 700 (logo excepted), tracking -0.02~-0.028em (not -0.03em/-0.035em
     territory). */
  --pd-t1-size: clamp(34px, 6.2vw, 64px); --pd-t1-weight: 700; --pd-t1-tracking: -0.025em; --pd-t1-leading: 1.05;
  --pd-t2-size: clamp(26px, 4.4vw, 44px); --pd-t2-weight: 700; --pd-t2-tracking: -0.025em; --pd-t2-leading: 1.08;
  --pd-t3-size: clamp(21px, 3.1vw, 30px); --pd-t3-weight: 700; --pd-t3-tracking: -0.02em;  --pd-t3-leading: 1.15;
  --pd-t4-size: clamp(18px, 2.4vw, 23px); --pd-t4-weight: 600; --pd-t4-tracking: -0.015em; --pd-t4-leading: 1.2;
  --pd-t5-size: 18px; --pd-t5-weight: 600; --pd-t5-tracking: -0.01em; --pd-t5-leading: 1.3;
  --pd-t6-size: 15px; --pd-t6-weight: 500; --pd-t6-tracking: 0em;     --pd-t6-leading: 1.35;

  /* ---- type: body scale — Nunito Sans, brief §3.3 body table ---- */
  --pd-body-size: 16px;  --pd-body-weight: 400; --pd-body-leading: 1.75; --pd-body-opsz: 12;
  --pd-body-sm-size: 14px; --pd-body-sm-leading: 1.7; --pd-body-sm-opsz: 10;
  --pd-caption-size: 13px; --pd-caption-weight: 500; --pd-caption-leading: 1.65; --pd-caption-opsz: 8;
  --pd-eyebrow-size: 12px; --pd-eyebrow-weight: 700; --pd-eyebrow-leading: 1.4; --pd-eyebrow-tracking: 0.22em; /* brief V1.3: no rendered text below 12px */

  /* ---- motion ---- */
  --pd-ease: cubic-bezier(0.4, 0, 0.2, 1);
  --pd-duration-fast: 150ms;
  --pd-duration: 250ms;
  /* asymmetric in/out pair (brief V1.4 §7.2/§12.2) — the pd-v2-twins hover
     cascade's "silkiness" comes almost entirely from this asymmetry plus
     staggered start times, not from the easing curve alone. Not consumed
     anywhere in Phase 1; defined now so Phase 3/4A components share one
     source of truth instead of re-deriving the curve per component. */
  --pd-e-in: cubic-bezier(0.22, 1.14, 0.36, 1);   /* entrance — slight overshoot, 420ms in brief's spec */
  --pd-e-out: cubic-bezier(0.22, 0.61, 0.36, 1);  /* exit — pure ease-out, 950ms in brief's spec */

  /* ---- accessibility (brief §5) ---- */
  --pd-tap-min: 44px;
}

/* Reduced motion only zeroes animation/transition timing — it must never
   touch `filter`/`backdrop-filter` values, since the age-gate scrim blur is
   a safety measure, not decoration (brief §5). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* --------------------------------------------------------------------------
   3. Legacy bridge — --pls-* (Anvogue/PressLayouts, 138 vars) → --pd-*
   Every color/radius/font var is repointed here so old sections re-skin
   immediately with zero markup changes (brief §6.2). Pure layout metrics
   (widths/heights/gaps) are deliberately left untouched — those are
   structural, not brand-identity values, and get resized per component as
   each section is rebuilt. Left alone: --pls-container-width, --pls-grid-gap,
   --pls-logo-width, --pls-mobile-logo-width, --pls-header-height,
   --pls-sticky-header-height, --pls-mobile-header-height,
   --pls-navigation-height, --pls-topbar-height, --pls-promo-bar-height,
   --pls-newsletter-popup-width, --pls-scroll-w, --pls-preloader-background-image.
   -------------------------------------------------------------------------- */
body {
  /* base type */
  --pls-primary-font: var(--pd-body);
  --pls-secondary-font: var(--pd-body);
  --pls-font-size: var(--pd-body-size);
  --pls-font-weight: var(--pd-body-weight);
  --pls-line-height: var(--pd-body-leading);

  /* base color roles */
  --pls-primary-color: var(--pd-act-2);
  --pls-primary-inverse-color: var(--pd-paper);
  --pls-secondary-color: var(--pd-ink);
  --pls-secondary-inverse-color: var(--pd-paper);
  --pls-secondary-color2: var(--pd-ink-60);
  --pls-critical-color: var(--pd-danger);
  --pls-heading-color: var(--pd-ink);
  --pls-text-color: var(--pd-ink);
  --pls-theme-background-color: var(--pd-paper);
  --pls-body-background: var(--pd-paper);
  --pls-link-color: var(--pd-act);
  --pls-link-hover-color: color-mix(in srgb, var(--pd-act) 80%, black); /* darkened, stays text-safe — raw is never a text color (brief §3.1/#15) */

  /* base borders */
  --pls-border-top: 1px solid var(--pd-hairline);
  --pls-border-right: 1px solid var(--pd-hairline);
  --pls-border-bottom: 1px solid var(--pd-hairline);
  --pls-border-left: 1px solid var(--pd-hairline);
  --pls-border-color: var(--pd-hairline);

  /* radius — unify every legacy scale step to the single flat token */
  --pls-border-radius: var(--pd-radius);
  --pls-border-radius-xl: var(--pd-radius);
  --pls-border-radius-l: var(--pd-radius);
  --pls-border-radius-s: var(--pd-radius);
  --pls-border-radius-xs: var(--pd-radius);
  --pls-radius-round: var(--pd-radius-pill);
  --pls-newsletter-popup-radius: var(--pd-radius);

  /* inputs */
  --pls-input-background: var(--pd-paper);
  --pls-input-color: var(--pd-ink);
  --pls-placeholder-color: var(--pd-ink-35);

  /* preloader */
  --pls-preloader-background: var(--pd-paper);

  /* *-bg-hover-color below was --pd-act-raw on all five of these (button,
     shop-cart-button, product-cart-button, buy-now-button, checkout-button) —
     contrast audit (feedback item 5) caught it on the cart page's legacy "Return
     to shop" button (a.button.wc-backward, WooCommerce's generic .button:hover
     rule in theme.css): raw pink background + this same *-hover-color paper text
     measured 3.62:1, failing the 4.5:1 a 14px button label needs. --pd-act-raw is
     documented for "solid blocks/badges/hover fills ONLY, never text" (above) —
     the fill itself is fine, it's pairing it with a fixed, always-light text
     colour that breaks. --pd-act (non-raw) already passes paper text at 5.35+:1
     and is still visibly a hover state (darker fill, not just a no-op), so it's
     the fix for all five rather than also changing the text colour on hover. */

  /* generic button (brief §6.2 confirmed mapping) */
  --pls-button-color: var(--pd-paper);
  --pls-button-hover-color: var(--pd-paper);
  --pls-button-bg-color: var(--pd-act);
  --pls-button-bg-hover-color: var(--pd-act);

  /* product/collection grid hover "Add to cart" (.pls-product-actions .pls-cart-button a)
     — verified against theme.css: this is the actual consumer, not the header
     cart icon. It's a conversion action, so it takes the primary tier. */
  --pls-shop-cart-button-color: var(--pd-paper);
  --pls-shop-cart-button-hover-color: var(--pd-paper);
  --pls-shop-cart-button-bg-color: var(--pd-act);
  --pls-shop-cart-button-bg-hover-color: var(--pd-act);

  /* PDP main "Add to Cart" (form.cart .button on the single product page)
     — conversion action, primary tier */
  --pls-product-cart-button-color: var(--pd-paper);
  --pls-product-cart-button-hover-color: var(--pd-paper);
  --pls-product-cart-button-bg-color: var(--pd-act);
  --pls-product-cart-button-bg-hover-color: var(--pd-act);

  /* buy now (brief §6.2 confirmed mapping) */
  --pls-buy-now-button-color: var(--pd-paper);
  --pls-buy-now-button-hover-color: var(--pd-paper);
  --pls-buy-now-button-bg-color: var(--pd-act);
  --pls-buy-now-button-bg-hover-color: var(--pd-act);

  /* checkout (brief §6.2 confirmed mapping) */
  --pls-checkout-button-color: var(--pd-paper);
  --pls-checkout-button-hover-color: var(--pd-paper);
  --pls-checkout-button-bg-color: var(--pd-act);
  --pls-checkout-button-bg-hover-color: var(--pd-act);

  /* header chrome — light surface, dark nav */
  --pls-header-text-color: var(--pd-ink);
  --pls-header-link-color: var(--pd-ink);
  --pls-header-link-hover-color: var(--pd-act);
  --pls-header-border-top: 1px solid var(--pd-hairline);
  --pls-header-border-right: 1px solid var(--pd-hairline);
  --pls-header-border-bottom: 1px solid var(--pd-hairline);
  --pls-header-border-left: 1px solid var(--pd-hairline);
  --pls-header-button-bg-color: var(--pd-act);
  --pls-header-button-text-color: var(--pd-paper);

  /* mobile header — light surface */
  --pls-mobile-header-text-color: var(--pd-ink);
  --pls-mobile-header-background-color: var(--pd-paper);
  --pls-mobile-header-link-color: var(--pd-ink);
  --pls-mobile-header-link-hover-color: var(--pd-act);
  --pls-mobile-header-border-top: 1px solid var(--pd-hairline);
  --pls-mobile-header-border-right: 1px solid var(--pd-hairline);
  --pls-mobile-header-border-bottom: 1px solid var(--pd-hairline);
  --pls-mobile-header-border-left: 1px solid var(--pd-hairline);

  /* primary nav — light surface */
  --pls-navigation-text-color: var(--pd-ink);
  --pls-navigation-link-color: var(--pd-ink);
  --pls-navigation-link-hover-color: var(--pd-act);
  --pls-navigation-border-top: 1px solid var(--pd-hairline);
  --pls-navigation-border-right: 1px solid var(--pd-hairline);
  --pls-navigation-border-bottom: 1px solid var(--pd-hairline);
  --pls-navigation-border-left: 1px solid var(--pd-hairline);

  /* categories mega-menu */
  --pls-categories-menu-title-color: var(--pd-paper);
  --pls-categories-menu-title-background: var(--pd-ink);
  --pls-categories-menu-wrapper-background: var(--pd-paper);
  --pls-categories-menu-hover-background: var(--pd-ink-08);
  --pls-categories-menu-link-color: var(--pd-ink);
  --pls-categories-menu-link-hover-color: var(--pd-act);
  --pls-categories-menu-border-top: 1px solid var(--pd-hairline);
  --pls-categories-menu-border-right: 1px solid var(--pd-hairline);
  --pls-categories-menu-border-bottom: 1px solid var(--pd-hairline);
  --pls-categories-menu-border-left: 1px solid var(--pd-hairline);

  /* mobile popup menu */
  --pls-popup-menu-text-color: var(--pd-ink);
  --pls-popup-menu-link-color: var(--pd-ink);
  --pls-popup-menu-link-hover-color: var(--pd-act);

  /* footer — light surface, dark text */
  --pls-footer-title-color: var(--pd-ink);
  --pls-footer-text-color: var(--pd-ink);
  --pls-footer-link-color: var(--pd-ink);
  --pls-footer-link-hover-color: var(--pd-act);
  --pls-footer-border-top: 1px solid var(--pd-hairline);
  --pls-footer-border-right: 1px solid var(--pd-hairline);
  --pls-footer-border-bottom: 1px solid var(--pd-hairline);
  --pls-footer-border-left: 1px solid var(--pd-hairline);

  /* copyright strip — dark surface (legacy value was near-white text) */
  --pls-copyright-text-color: var(--pd-paper);
  --pls-copyright-link-color: var(--pd-main-2); /* brief §6.2 confirmed mapping */
  --pls-copyright-link-hover-color: var(--pd-act-2);
  --pls-copyright-border-top: 1px solid var(--pd-hairline-inverse);
  --pls-copyright-border-right: 1px solid var(--pd-hairline-inverse);
  --pls-copyright-border-bottom: 1px solid var(--pd-hairline-inverse);
  --pls-copyright-border-left: 1px solid var(--pd-hairline-inverse);

  /* top announcement bar — dark surface (legacy value was near-white text) */
  --pls-topbar-text-color: var(--pd-paper);
  --pls-topbar-link-color: var(--pd-paper);
  --pls-topbar-link-hover-color: var(--pd-lemon);
  --pls-topbar-border-top: 1px solid var(--pd-hairline-inverse);
  --pls-topbar-border-right: 1px solid var(--pd-hairline-inverse);
  --pls-topbar-border-bottom: 1px solid var(--pd-hairline-inverse);
  --pls-topbar-border-left: 1px solid var(--pd-hairline-inverse);
  --pls-topbar-border-color: var(--pd-hairline-inverse);

  /* promo bar button */
  /* Same raw-bg/paper-text hover fix as the five button tokens above. */
  --pls-promo-bar-button-color: var(--pd-paper);
  --pls-promo-bar-button-hover-color: var(--pd-paper);
  --pls-promo-bar-button-bg-color: var(--pd-act);
  --pls-promo-bar-button-bg-hover-color: var(--pd-act);

  /* product price */
  --pls-product-price-color: var(--pd-ink);
  --pls-product-sale-price-color: var(--pd-act);

  /* product labels — swapped from the brief's original §6.2/§3.6 mapping
     2026-09-18: live-preview QA found the Hot badge rendering yellow-bg +
     hardcoded-white-text (near-zero contrast, legacy CSS never templated
     the text color). Yimei chose to swap roles rather than just recolor the
     text, so discount is now the yellow/black pair and Hot is magenta/white.
     Text-color overrides for this pairing are further down (section 3b). */
  --pls-woocommece-sale-label-color: var(--pd-lemon);
  --pls-woocommece-featured-label-color: var(--pd-act); /* brief V1.3: #CB025C, NOT raw — white text on raw only hits 3.62–3.84, fails AA */
  --pls-woocommece-outofstock-label-color: transparent; /* brief V1.3 §3.6: sold-out is outline, not filled — see 3b for border/text */
  --pls-woocommece-new-label-color: var(--pd-mint);

  /* menu label chip (brief §6.2 confirmed mapping) */
  --pls-menu-label-color: var(--pd-act);
  --pls-menu-label-border-color: var(--pd-act);
}

/* Page background: theme.css hardcodes body{background-color:#fff} rather
   than reading --pls-body-background (that var only drives *nested* surfaces
   — popups, dropdowns, card interiors — leaving the outermost page a
   different, non-brand white). Same specificity, later in the cascade. */
body {
  background-color: var(--pd-paper);
}

/* --------------------------------------------------------------------------
   3b. Legacy bridge — text-color fixes theme.css never templated
   theme.css hardcodes color:#fff on the shared .pls-product-labels>span
   rule, so swapping a badge's *background* role (above) doesn't fix its
   *text* color — that always needs an explicit override here. Matches
   the discount/Hot swap decided 2026-09-18.
   -------------------------------------------------------------------------- */
.pls-product-labels span.on-sale {
  color: var(--pd-ink); /* discount badge is now lemon bg — needs dark text */
}
.pls-product-labels span.new {
  color: var(--pd-ink); /* overrides the shared span rule's inherited white */
}
.pls-product-labels span.out-of-stock {
  color: var(--pd-mute); /* brief V1.3 §3.6: transparent + neutral outline, not filled */
  border: 1px solid var(--pd-ink-16);
}
/* .featured (Hot) keeps the shared rule's white text — its magenta (--pd-act,
   not the raw variant) background passes contrast with white at 5.35:1. */

/* PDP price-block discount chip (sections/product-details/blocks/price.html,
   .pls-product-discount-label .on-sale) is a THIRD, separate on-sale surface
   — div.summary .on-sale{background:var(--pls-primary-color)...} (theme.css)
   outranks the shared badge rule here (0,2,1 beats 0,2,0), so it was still
   rendering purple/white instead of the discount pair. Needs specificity
   higher than div.summary .on-sale to win outright. */
div.summary .pls-product-discount-label .on-sale {
  background: var(--pd-lemon);
  color: var(--pd-ink);
}

/* --------------------------------------------------------------------------
   3c. Elementor Kit bridge — a SECOND, separate legacy variable namespace
   Discovered during live-preview QA 2026-09-18: About/Care/FAQ/Policy pages
   (anything migrated from Elementor) don't read any --pls-* variable at
   all. They're driven by Elementor's own --e-global-* kit variables,
   defined in post-7.css on .elementor-kit-7 (applied to <body> sitewide —
   see layout/theme.html). That's why no Fraunces or brand color showed up
   anywhere outside WooCommerce-style components. Font-weight vars are left
   at their default (400) — Elementor's flat one-weight-per-role model can't
   express the brief's per-heading-level weight table; that needs each
   section rebuilt as pd-v2-* in Phase 2/4A, not patched here.
   -------------------------------------------------------------------------- */
.elementor-kit-7 {
  --e-global-color-primary: var(--pd-act-2);
  --e-global-color-secondary: var(--pd-ink);
  --e-global-color-text: var(--pd-ink);
  --e-global-color-link: var(--pd-act);
  --e-global-color-heading: var(--pd-ink);
  --e-global-color-df63ba0: var(--pd-paper);
  --e-global-color-b40797b: var(--pd-paper);
  --e-global-color-6341324: var(--pd-ink-16);
  --e-global-typography-primary-font-family: var(--pd-disp);
  --e-global-typography-secondary-font-family: var(--pd-disp);
  --e-global-typography-text-font-family: var(--pd-body);
  --e-global-typography-accent-font-family: var(--pd-body);
}

/* --------------------------------------------------------------------------
   3d. Global heading typography
   .elementor-heading-title (a class, specificity beats a bare tag selector)
   gets its font-family from the kit bridge above; this rule covers every
   other heading — WooCommerce/PressLayouts markup that was never wrapped in
   an Elementor class — and locks the Fraunces axis for both paths, since
   Elementor's own CSS never sets font-variation-settings and the default
   axis values (opsz 9, WONK 1) are exactly what brief §3.3/#14 reject.
   -------------------------------------------------------------------------- */
/* SPEC-typography.md applies to legacy pages too (blog articles, policies —
   whatever real h-tags render here without going through a pd-v2-* section).
   pd-v2-base.css's own h1-h4 rule (loaded later) already wins for h1-h4 on
   every pd-v2 page; this covers h5/h6, which that rule doesn't reach, and is
   the fallback for any legacy page that doesn't load pd-v2-base.css's rule
   for some reason. Display by default, same reasoning as that rule. */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--pd-disp);
  font-variation-settings: var(--fr-display);
  font-weight: 650;
  font-style: normal;
}

/* --------------------------------------------------------------------------
   4. Typography utilities
   -------------------------------------------------------------------------- */
.pd-v2-t1, .pd-v2-t2, .pd-v2-t3, .pd-v2-t4, .pd-v2-t5, .pd-v2-t6 {
  font-family: var(--pd-disp);
  font-variation-settings: var(--pd-disp-axis);
  font-optical-sizing: auto; /* was none/pinned — see --pd-disp-axis above */
  margin: 0;
  color: var(--pd-ink);
}
.pd-v2-t1 { font-size: var(--pd-t1-size); font-weight: var(--pd-t1-weight); letter-spacing: var(--pd-t1-tracking); line-height: var(--pd-t1-leading); }
.pd-v2-t2 { font-size: var(--pd-t2-size); font-weight: var(--pd-t2-weight); letter-spacing: var(--pd-t2-tracking); line-height: var(--pd-t2-leading); }
.pd-v2-t3 { font-size: var(--pd-t3-size); font-weight: var(--pd-t3-weight); letter-spacing: var(--pd-t3-tracking); line-height: var(--pd-t3-leading); }
.pd-v2-t4 { font-size: var(--pd-t4-size); font-weight: var(--pd-t4-weight); letter-spacing: var(--pd-t4-tracking); line-height: var(--pd-t4-leading); }
.pd-v2-t5 { font-size: var(--pd-t5-size); font-weight: var(--pd-t5-weight); letter-spacing: var(--pd-t5-tracking); line-height: var(--pd-t5-leading); }
.pd-v2-t6 { font-size: var(--pd-t6-size); font-weight: var(--pd-t6-weight); letter-spacing: var(--pd-t6-tracking); line-height: var(--pd-t6-leading); }

.pd-v2-body, .pd-v2-body-sm, .pd-v2-caption, .pd-v2-eyebrow {
  font-family: var(--pd-body);
  font-optical-sizing: none;
  margin: 0;
  color: var(--pd-ink);
}
.pd-v2-body {
  font-size: var(--pd-body-size);
  font-weight: var(--pd-body-weight);
  line-height: var(--pd-body-leading);
  letter-spacing: 0em;
  font-variation-settings: "opsz" var(--pd-body-opsz);
}
.pd-v2-body-sm {
  font-size: var(--pd-body-sm-size);
  font-weight: var(--pd-body-weight);
  line-height: var(--pd-body-sm-leading);
  letter-spacing: 0em;
  font-variation-settings: "opsz" var(--pd-body-sm-opsz);
}
.pd-v2-caption {
  font-size: var(--pd-caption-size);
  font-weight: var(--pd-caption-weight);
  line-height: var(--pd-caption-leading);
  letter-spacing: 0em;
  font-variation-settings: "opsz" var(--pd-caption-opsz);
}
.pd-v2-eyebrow {
  display: inline-block;
  font-size: var(--pd-eyebrow-size);
  font-weight: var(--pd-eyebrow-weight);
  line-height: var(--pd-eyebrow-leading);
  letter-spacing: var(--pd-eyebrow-tracking); /* em, never % — brief §3.3 */
  text-transform: uppercase;
}

/* --------------------------------------------------------------------------
   6. Small shared utilities
   -------------------------------------------------------------------------- */
.pd-v2-tap-target {
  min-width: var(--pd-tap-min);
  min-height: var(--pd-tap-min);
}
.pd-v2-badge {
  display: inline-flex;
  align-items: center;
  border-radius: var(--pd-radius-pill);
  padding: 0.35em 0.9em;
  font-family: var(--pd-body);
  font-optical-sizing: none;
  font-size: var(--pd-eyebrow-size);
  font-weight: var(--pd-eyebrow-weight);
  letter-spacing: 0.08em;
  line-height: 1;
  white-space: nowrap;
}
/* Colors match brief V1.3 §3.6 exactly (discount/Hot roles swapped 2026-09-18
   from the original V1.2 mapping — see the --pls- bridge comment above). */
.pd-v2-badge--sale { background: var(--pd-lemon); color: var(--pd-ink); } /* discount, e.g. "-19%" */
.pd-v2-badge--hot { background: var(--pd-act); color: var(--pd-paper); } /* HOT/new — #CB025C, never raw */
.pd-v2-badge--new { background: var(--pd-mint); color: var(--pd-ink); }
.pd-v2-badge--sold-out { background: transparent; color: var(--pd-mute); border: 1px solid var(--pd-ink-16); }
