/* =========================================================================
   Meshkovi Winery — Design System layer
   -------------------------------------------------------------------------
   Single source of truth for the structural / design-system fixes. Loaded
   LAST in nuxt.config so it has the final word over the vendored ThemeREX /
   WooCommerce stylesheets.

   Theme model: the light/dark toggle (useColorTheme) writes
   `data-color-theme="dark|light"` on <html> and swaps the appearance CMS
   palette (the `--site-bg-color`, `--title-color`, … custom properties set by
   plugins/appearance.client.ts). The tokens below give every DS component a
   dark + light value from ONE place, deriving from the appearance vars where
   the CMS drives a surface and falling back to per-mode defaults otherwise.
   No raw color literals live in the component rules — only in this token map.
   ========================================================================= */

/* ---- 0. Base reset --------------------------------------------------------
   The dropped vendored `style.min.css` provided the global `body{margin:0}` +
   `box-sizing:border-box` reset the whole storefront was built on (full-bleed
   bands, the 100vh hero, every `width:100%`+padding component). Restored here so
   the DS layer is self-sufficient — without it the browser's default 8px body
   margin insets every page and the box model shifts (WIN-40). */
*,
*::before,
*::after {
  box-sizing: border-box;
}
html,
body {
  margin: 0;
  padding: 0;
}
/* Root font-size carries the admin "Font size" knob: `--ds-font-scale` is set by
   plugins/appearance.client.ts from site_appearance.extra.fontScale (default 1),
   so the admin can scale ALL text up/down for readability. Everything sized in
   rem/em scales from here. */
html {
  font-size: calc(100% * var(--ds-font-scale, 1));
}
/* Base type — EB Garamond for running text, Cormorant for headings. (The
   vendored style.min that used to set the body font was dropped in WIN-40, so
   without this the page falls back to Times New Roman.) Classed elements with
   their own font-family still win; this is just the inherited default. */
body {
  font-family: var(--font-text);
  /* 18px base — EB Garamond has a small x-height, so it needs a larger base than
     a normal serif to read comfortably. Many section components (PromoBand,
     HomeContact, …) size their copy in `em` off this inherited base rather than
     the rem tokens, so this is what scales them. The admin font-scale multiplies
     it further. */
  font-size: 1.125rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}
h1,
h2,
h3 {
  font-family: var(--font-display);
}
/* Form controls don't inherit font-family by default (UA leaks Arial/Times) and
   are functional UI, so pin them to Inter. */
button,
input,
select,
textarea {
  font-family: var(--font-ui);
}

/* ---- 1. Token layer -------------------------------------------------------
   Generic, theme-able tokens. `:root` carries the dark defaults so a missing
   data-color-theme (pre-hydration) renders the intended dark direction; the
   light block overrides for light mode. Surface tokens defer to the
   appearance vars (`--site-bg-color`, `--title-strip-color`, …) so the CMS
   palette keeps the last word on the actual page background. */
:root,
:root[data-color-theme="dark"] {
  /* Vertical rhythm — ONE section-spacing scale (replaces the old 100vh bands)
     so sections breathe consistently without the oversized empty gaps the design
     review flagged. Used as block padding / capped min-heights on the home bands. */
  /* Shared section rhythm. (Was a malformed clamp(64px,8vw,60px) — min > max, so
     it resolved to a flat 60px; corrected to a valid range that preserves the
     tight desktop feel reviewers liked and tightens mobile a touch — review v4.) */
  --ds-section-y: clamp(48px, 8vw, 64px);
  /* Each color token reads the admin appearance var FIRST (so the CMS keeps
     control — "set everything from the admin"), and only falls back to the
     per-mode brand default when the admin hasn't configured that field. */
  --ds-bg: var(--site-bg-color, #0e0b08);
  --ds-surface: var(--image-color, #15100a);
  --ds-surface-2: #1c150d;
  --ds-text: var(--paragraph-text-color, #ece4d6);
  /* Muted text lifted for contrast (design review: muted copy read too faint). */
  --ds-text-muted: var(--paragraph-subtitle-color, #b6a886);
  --ds-gold: var(--button-color, #c9a45c);
  --ds-gold-strong: #e6c98a;
  --ds-gold-dim: #9a7e44;
  --ds-border: rgba(201, 164, 92, 0.28);
  --ds-border-soft: rgba(236, 228, 214, 0.1);
  /* Unified form-field treatment (one source of truth for every input/textarea
     across Contact, Account and comments — design review v4). These reference the
     themed surface/gold tokens, so they auto-adapt in light mode without a second
     definition. */
  --ds-field-bg: var(--ds-surface-2);
  --ds-field-border: color-mix(in srgb, var(--ds-gold, #c9a45c) 55%, transparent);
  --ds-field-focus: var(--ds-gold, #c9a45c);
  --ds-field-focus-ring: 0 0 0 3px
    color-mix(in srgb, var(--ds-gold, #c9a45c) 22%, transparent);
  --ds-on-gold: var(--button-text-color, #1a1206);
  --ds-error: #d4694f;
  --ds-error-border: #c8553d;
  /* Rail / utility foreground: light glyphs on the dark surface. */
  --ds-rail-fg: var(--paragraph-text-color, #ece4d6);
  --ds-shadow-card: 0 16px 32px rgba(0, 0, 0, 0.5);
  --ds-skeleton-1: #15100a;
  --ds-skeleton-2: #241a10;
}

:root[data-color-theme="light"] {
  --ds-bg: var(--site-bg-color, #f1eee7);
  --ds-surface: var(--image-color, #f7f4ee);
  --ds-surface-2: #efebe2;
  --ds-text: var(--paragraph-text-color, #2b2118);
  --ds-text-muted: var(--paragraph-subtitle-color, #5d513e);
  /* Light-mode defaults for the CMS appearance TEXT vars. Many components fall
     back to DARK-theme colours (e.g. var(--paragraph-text-color, #d8c9a3),
     var(--paragraph-category-color, #c9a96e)) which fail WCAG AA on cream when a
     tenant's light palette leaves these unset. Supplying readable light values
     here fixes them centrally (a configured CMS value still wins via inline
     style). None of these vars drive a dark surface in light mode. */
  --paragraph-text-color: #2b2118;
  --paragraph-subtitle-color: #5d513e;
  --paragraph-category-color: #6e5214; /* deep gold — AA (>=4.5) on cream */
  --paragraph-title-color: #211a12;
  /* Deeper gold for text/links/eyebrows on cream (AA); brand gold stays for
     large accents via --ds-gold-strong where needed. */
  --ds-gold: var(--button-color, #9c7327);
  --ds-gold-strong: #b8893a;
  --ds-gold-dim: #b69a5e;
  --ds-border: rgba(156, 115, 39, 0.3);
  --ds-border-soft: rgba(43, 33, 24, 0.12);
  --ds-on-gold: var(--button-text-color, #1a1206);
  --ds-error: #b23a22;
  --ds-error-border: #b23a22;
  /* Rail / utility foreground: dark glyphs on the cream surface. */
  --ds-rail-fg: var(--paragraph-text-color, #2b2118);
  --ds-shadow-card: 0 16px 30px rgba(60, 45, 25, 0.18);
  --ds-skeleton-1: #ece7dc;
  --ds-skeleton-2: #ded7c8;
}

/* Vertical-rhythm + sizing scale (mode-independent). */
:root {
  --ds-space-1: 8px;
  --ds-space-2: 16px;
  --ds-space-3: 24px;
  --ds-space-4: clamp(40px, 6vw, 72px); /* between-section gap */
  --ds-space-5: clamp(64px, 9vw, 120px); /* large section gap   */
  --ds-control-min: 48px; /* >= 44px hit target  */
  --ds-radius: 2px;
  --ds-focus-ring: 0 0 0 2px var(--ds-bg), 0 0 0 4px var(--ds-gold);
  --ds-ease: cubic-bezier(0.16, 1, 0.3, 1);
  --ds-title-band-py: clamp(40px, 5vw, 56px); /* page-title band vertical pad */

  /* ── Type families ───────────────────────────────────────────────────────
     The Meshkovi type system. All three carry full Latin + Cyrillic (loaded in
     nuxt.config with subset=…,cyrillic), so EN and MK share one scale.
       display → Cormorant Garamond — hero, H1–H3, section/page titles, wordmark.
                 NEVER below ~22px: its hairlines vanish (use --font-text instead).
       text    → EB Garamond — body, leads, subtitles, quotes, card descriptions.
       ui      → Inter — nav, buttons, prices, badges, eyebrows, captions, forms.
     (The footer keeps its own bespoke faces — Cinzel/PT Serif/Montserrat.) */
  --font-display: "Cormorant Garamond", Georgia, "Times New Roman", serif;
  --font-text: "EB Garamond", Georgia, "Times New Roman", serif;
  --font-ui: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* ── Type scale ──────────────────────────────────────────────────────────
     One modular ramp so headings / body / labels draw their size from a shared
     source instead of ad-hoc rem values. The heading tiers (xl+) are the type
     system's fluid display scale (clamp: desktop ceiling → mobile floor); the
     small steps (≤ base) stay fixed for predictable labels/meta. */
  --ds-fs-3xs: 0.625rem; /* 10px — micro labels / fine print */
  --ds-fs-2xs: 0.72rem; /* eyebrows, badges, tiny meta      */
  --ds-fs-xs: 0.8rem; /* small meta, secondary labels     */
  --ds-fs-sm: 1rem; /* captions, secondary text — 16px      */
  --ds-fs-base: 1.125rem; /* body copy — 18px (EB Garamond reads small) */
  --ds-fs-md: 1.35rem; /* lead / intro body — ~22px         */
  --ds-fs-lg: 1.55rem; /* small headings, large body        */
  --ds-fs-xl: clamp(1.375rem, 1vw + 0.9rem, 1.75rem); /* H3 / card + sub titles */
  --ds-fs-2xl: clamp(1.75rem, 2vw + 0.75rem, 2.5rem); /* H2 / section titles    */
  --ds-fs-3xl: clamp(2.25rem, 3vw + 1rem, 3.5rem); /* H1 / page titles          */
  --ds-fs-4xl: clamp(2.5rem, 4vw + 1rem, 4.25rem); /* oversized headings        */
  --ds-fs-5xl: clamp(3rem, 5vw + 1rem, 5rem); /* display                        */

  /* Weights — the storefront only ever uses these four. */
  --ds-fw-normal: 400;
  --ds-fw-medium: 500;
  --ds-fw-semibold: 600;
  --ds-fw-bold: 700;

  /* Line-heights. */
  --ds-lh-tight: 1.15; /* large headings        */
  --ds-lh-snug: 1.3; /* sub-heads / card titles */
  --ds-lh-base: 1.6; /* body copy             */

  /* Tracking — the uppercase eyebrow/label tracking that recurs everywhere. */
  --ds-tracking-label: 0.14em;
}

/* =========================================================================
   P0-1 / P0-3 — Cream-strip rail + theme parity (root cause)
   -------------------------------------------------------------------------
   The vendored theme hard-codes `.scheme_dark .menu_side_inner` to #2a2a2a
   (__colors.css), independent of the page surface, so the fixed 49px right
   rail paints the INVERSE of the page: a dark strip on the cream default,
   a cream strip on a dark palette. Drive it from the page-surface token so it
   can never invert, and theme its glyphs from --ds-rail-fg (which flips with
   the mode) so they stay legible on either surface.
   ========================================================================= */
.menu_side_wrap .menu_side_inner {
  /* Honour an explicit CMS side-panel colour, else follow the page surface. */
  background-color: var(--side-panel-bg-color, var(--ds-bg)) !important;
  color: var(--ds-rail-fg) !important;
  /* A hairline separates the rail from the content without a colour jump. */
  border-left: 1px solid var(--ds-border-soft);
  box-sizing: border-box;
}

/* Rail glyphs (account / cart / language / search / theme) follow the rail
   foreground token instead of the hard-coded #fff in default.vue, so they
   read on both the cream and the dark surface. */
.menu_side_inner .side-icon-link,
.menu_side_inner .theme-toggle-side,
.menu_side_inner .search-side-wrap {
  color: var(--ds-rail-fg) !important;
}
.menu_side_inner .side-icon-link:hover,
.menu_side_inner .theme-toggle-side:hover {
  color: var(--ds-gold) !important;
}
/* Language flags get a token-driven ring so the circle reads on either
   surface (the inline style ships a translucent-white ring tuned for dark). */
.menu_side_inner .lang-switcher-side button img {
  box-shadow: 0 0 0 1px var(--ds-border) !important;
}
.menu_side_inner .lang-switcher-side button.active img {
  box-shadow: 0 0 0 2px var(--ds-gold) !important;
}
.menu_side_inner .lang-sep-side {
  background: var(--ds-border) !important;
}

/* Visible focus ring on every rail control (a11y). */
.menu_side_inner .side-icon-link:focus-visible,
.menu_side_inner .theme-toggle-side:focus-visible,
.menu_side_inner .lang-switcher-side button:focus-visible {
  outline: none;
  box-shadow: var(--ds-focus-ring);
  border-radius: var(--ds-radius);
}

/* =========================================================================
   P0-2 — Scrim utility for text-over-image
   -------------------------------------------------------------------------
   ONE reusable overlay for any full-bleed image section that holds text
   (hero, contact closer, future ones). The gradient + vignette stay a DARK
   wash in BOTH themes — text over photos is always light — so it is
   independent of the page palette. Apply `.media-scrim` to the image
   container and put the text in a `.media-scrim__content` (or any child with
   position) so it sits above the wash.
   ========================================================================= */
.media-scrim {
  position: relative;
  isolation: isolate;
}
.media-scrim::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(
    to top,
    rgba(10, 8, 6, 0.82) 0%,
    rgba(10, 8, 6, 0.35) 55%,
    rgba(10, 8, 6, 0.55) 100%
  );
}
/* Subtle full-frame vignette so corners stay legible on the brightest photo. */
.media-scrim::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  box-shadow: inset 0 0 140px 40px rgba(10, 8, 6, 0.7);
}
.media-scrim > *:not(.media-scrim__bg) {
  position: relative;
  z-index: 2;
}
.media-scrim__content {
  position: relative;
  z-index: 2;
}
/* Text inside a scrim is always light — fixed, not theme-dependent. */
.media-scrim__content,
.media-scrim__content :is(h1, h2, h3, h4, h5, h6, p, a, span) {
  color: #fff;
}
.media-scrim__content .media-scrim__eyebrow {
  color: var(--ds-gold-strong);
}

/* =========================================================================
   P1-5 — Sticky compact header
   -------------------------------------------------------------------------
   Inner pages use `.top_panel_style_1`, whose full height is ~500px (a large
   centred logo). The theme's own `state_fixed` sticky path is dead code here
   (gated `!menu_style_side && !header_position_under`, and the body carries
   both classes), so we pin + compact it ourselves. `body.ds-scrolled` is
   toggled by plugins/sticky-header.client.ts past ~80px. The home hero header
   (`.top_panel_style_2`) deliberately opts out. Transitions are gated on
   prefers-reduced-motion: no-preference; reduced-motion users get the compact
   end-state with no animation.
   ========================================================================= */
/* Header utility cluster (account · cart · search · lang · theme) — top-right of
   the header in both layouts. The inner-header structure + its sticky compaction
   now live in app/layouts/default.vue (.site-header); the home hero header in
   app/layouts/home.vue. Both share the .site-nav primary nav defined below. */
.ds-header-util {
  position: absolute;
  top: 20px;
  right: 28px;
  z-index: 30;
}
@media (prefers-reduced-motion: no-preference) {
  .ds-header-util {
    transition: top 0.3s var(--ds-ease);
  }
}
/* ---- Shared primary navigation (horizontal row, both headers) ----
   Gold uppercase Lato links with a thin divider between items. Colour follows
   the appearance title colour; hover/active follows the accent. */
.site-nav__list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  margin: 22px 0 66px;
  padding: 0;
  list-style: none;
}
.site-nav__item {
  position: relative;
}
.site-nav__item + .site-nav__item::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  height: 11px;
  border-left: 1px solid var(--title-color, #8a6a2a);
  opacity: 0.4;
  transform: translateY(-50%);
}
.site-nav__item > a {
  display: block;
  position: relative;
  padding: 1em 1.4em;
  color: var(--title-color, #8a6a2a);
  font-family: var(--font-ui);
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  line-height: 1.2;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.2s var(--ds-ease);
}
.site-nav__item > a span {
  color: inherit;
}
.site-nav__item > a:hover,
.site-nav__item > a:hover span,
.site-nav__item > a.router-link-active,
.site-nav__item > a.router-link-active span {
  color: var(--paragraph-category-color, #1a1a1a);
}
/* Centred gold underline on the INTERIOR nav — mirrors the home hero so the
   hover/active indicator is consistent across the whole site (was hero-only).
   Scoped to :not(.site-nav--hero) so the hero keeps its own (home.vue) rule. */
.site-nav:not(.site-nav--hero) .site-nav__item > a::after {
  content: "";
  position: absolute;
  left: 50%;
  right: 50%;
  bottom: 0.55em;
  height: 1px;
  background: var(--ds-gold-strong, #e6c98a);
  opacity: 0;
  transition: left 0.25s var(--ds-ease), right 0.25s var(--ds-ease),
    opacity 0.25s var(--ds-ease);
}
.site-nav:not(.site-nav--hero) .site-nav__item > a:hover::after,
.site-nav:not(.site-nav--hero) .site-nav__item > a.router-link-active::after {
  left: 1.4em;
  right: 1.4em;
  opacity: 1;
}

/* ---- Mobile slide-out menu + hamburger (shared by both layouts) ----
   Vue-driven via useMobileMenu (WIN-40, replaces the legacy jQuery toggle). The
   hamburger shows ≤1023px (where the horizontal nav is hidden); the panel slides
   in from the right behind a dimming overlay. The hero-dark hamburger variant
   (white bars) lives in app/layouts/home.vue. */
.nav-toggle {
  display: none;
  position: absolute;
  top: 22px;
  left: 24px;
  z-index: 31;
  width: 30px;
  height: 24px;
  padding: 4px 0;
  background: none;
  border: 0;
  cursor: pointer;
}
.nav-toggle span {
  display: block;
  width: 100%;
  height: 2px;
  margin: 4px 0;
  background: var(--title-color, #d4af37);
  border-radius: 1px;
  transition: background-color 0.2s var(--ds-ease);
}
@media (max-width: 1023px) {
  .nav-toggle {
    display: block;
  }
}
.mobile-menu__overlay {
  position: fixed;
  inset: 0;
  z-index: 100000;
  background: rgba(0, 0, 0, 0.8);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s var(--ds-ease);
}
.mobile-menu__overlay.is-open {
  opacity: 1;
  pointer-events: auto;
}
.mobile-menu {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 100002;
  width: min(290px, 78vw);
  height: 100%;
  transform: translateX(100%);
  transition: transform 0.35s var(--ds-ease);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.mobile-menu.is-open {
  transform: translateX(0);
}
.mobile-menu__inner {
  position: relative;
  min-height: 100%;
  padding: 58px 28px;
  /* Dark slide-out surface — admin side-panel colour, dark default. */
  background: var(--side-panel-bg-color, #2a2a2a);
  color: #ece4d6;
}
.mobile-menu__close {
  position: absolute;
  top: 14px;
  right: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  background: none;
  border: 0;
  padding: 0;
  color: #ece4d6;
  /* A real "×" glyph — the theme icon font (.icon-cancel) was dropped in WIN-40,
     leaving the button invisible/untappable. */
  font-size: 30px;
  line-height: 1;
  cursor: pointer;
  transition: color 0.2s var(--ds-ease);
}
.mobile-menu__close:hover {
  color: var(--ds-gold, #c9a45c);
}
.mobile-menu__list {
  list-style: none;
  margin: 0 0 24px;
  padding: 0;
}
.mobile-menu__item > a {
  display: block;
  padding: 11px 0;
  color: #ece4d6;
  font-family: var(--font-ui);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  text-decoration: none;
  transition: color 0.2s var(--ds-ease);
}
.mobile-menu__item > a:hover,
.mobile-menu__item > a.router-link-active {
  color: var(--ds-gold, #c9a45c);
}
.mobile-menu__search {
  margin-bottom: 20px;
}
/* Lock the page behind the overlay while the menu is open. */
body.mobile-menu-open {
  overflow: hidden;
}

/* Page content container — the 1170px centred column the theme's `.wrap` gave
   the cart / checkout / account / search bodies (WIN-40 shell de-class). */
.ds-container {
  width: min(1170px, 100% - 60px);
  margin-inline: auto;
}
/* Home hero header (`.top_panel_style_2`): the utility cluster sits over the
   dark video, so force light glyphs regardless of the page palette. */
.ds-header-util--hero {
  --ds-rail-fg: #ece4d6;
  top: 28px;
}

/* =========================================================================
   P1-6 — Button system (.ds-btn + variants)
   -------------------------------------------------------------------------
   One component, three variants. Used directly via <DsButton> / the classes,
   and the shared sizing tokens keep every CTA aligned. Buttons in one row
   share width + height via `.ds-btn-row` (equal flex children). All colours
   are tokens, so the admin palette drives them in both themes.
   ========================================================================= */
.ds-btn {
  -webkit-appearance: none;
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: var(--ds-control-min);
  padding: 0 28px;
  border-radius: var(--ds-radius);
  border: 1px solid transparent;
  font-family: var(--font-ui);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.2s var(--ds-ease), color 0.2s var(--ds-ease),
    border-color 0.2s var(--ds-ease), box-shadow 0.2s var(--ds-ease);
}
.ds-btn:focus-visible {
  outline: none;
  box-shadow: var(--ds-focus-ring);
}
.ds-btn[disabled],
.ds-btn.is-disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

/* The tier variants are written as `.ds-btn.ds-btn--x` (specificity 0,2,0) on
   purpose: the theme's `.scheme_default button, … input[type="submit"]` reset in
   __colors.css is (0,1,1) and forces a transparent background + paragraph-title
   border onto ANY bare <button>. A single-class variant (0,1,0) loses to it, so
   a migrated submit/CTA would render as a ghost outline. The doubled class clears
   that reset without !important; border-color is pinned so the frame matches too. */

/* Primary — filled gold, dark text. */
.ds-btn.ds-btn--primary {
  background: var(--ds-gold);
  border-color: var(--ds-gold);
  color: var(--ds-on-gold);
}
.ds-btn.ds-btn--primary:hover {
  background: var(--ds-gold-strong);
  border-color: var(--ds-gold-strong);
  color: var(--ds-on-gold);
}

/* Secondary — bordered gold on transparent. */
.ds-btn.ds-btn--secondary {
  background: transparent;
  color: var(--ds-gold);
  border-color: var(--ds-border);
}
.ds-btn.ds-btn--secondary:hover {
  background: color-mix(in srgb, var(--ds-gold) 12%, transparent);
  border-color: var(--ds-gold-strong);
  color: var(--ds-gold-strong);
}

/* Text — inline link with an underline that grows on hover. */
.ds-btn.ds-btn--text {
  background: none;
  border: none;
  min-height: 0;
  padding: 0 2px 4px;
  color: var(--ds-gold);
  position: relative;
}
.ds-btn--text::after {
  content: "";
  position: absolute;
  left: 2px;
  right: 2px;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0.6);
  transform-origin: left;
  transition: transform 0.25s var(--ds-ease);
}
.ds-btn--text:hover {
  color: var(--ds-gold-strong);
}
.ds-btn--text:hover::after {
  transform: scaleX(1);
}

/* Compact size — for dense contexts (product/cross-sell cards) where the full
   48px control height is too heavy. Treatment (tier colours) is unchanged; only
   the metrics shrink, so a small card CTA still reads as the same button. */
.ds-btn--sm {
  min-height: 38px;
  padding: 0 18px;
  font-size: 11px;
  letter-spacing: 0.12em;
}

/* Equal-width / equal-height buttons in a row. */
.ds-btn-row {
  display: flex;
  gap: 16px;
  align-items: stretch;
  flex-wrap: wrap;
}
.ds-btn-row > .ds-btn {
  flex: 1 1 0;
}

/* =========================================================================
   P1-7 — Form fields
   -------------------------------------------------------------------------
   A bordered field with comfortable padding, a legible label, a clear
   :focus-visible ring and an error state. Targets the `.ds-field` class (Vue
   forms) + the search field. (Contact/account inputs use their own `--ds-field-*`
   token treatment; the legacy `.sc_form` selectors were dropped in WIN-40.)
   ========================================================================= */
.ds-field,
.search_form .search_field {
  width: 100%;
  box-sizing: border-box;
  min-height: var(--ds-control-min);
  padding: 12px 14px !important;
  background: var(--ds-bg) !important;
  border: 1px solid var(--ds-border) !important;
  border-radius: var(--ds-radius) !important;
  color: var(--ds-text) !important;
  font-family: inherit !important;
  font-size: 15px !important;
  line-height: 1.4;
  box-shadow: none !important;
  transition: border-color 0.2s var(--ds-ease), box-shadow 0.2s var(--ds-ease);
}
.ds-field--textarea {
  min-height: 120px;
  resize: vertical;
}
.ds-field::placeholder,
.search_form .search_field::placeholder {
  color: var(--ds-text-muted);
  opacity: 0.8;
}
.ds-field:focus,
.ds-field:focus-visible,
.search_form .search_field:focus {
  outline: none;
  border-color: var(--ds-gold) !important;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ds-gold) 22%, transparent) !important;
}
/* Error state. */
.ds-field--error {
  border-color: var(--ds-error-border) !important;
}
.ds-field--error:focus,
.ds-field--error:focus-visible {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ds-error) 22%, transparent);
}
.ds-field-error-msg {
  display: block;
  margin-top: 6px;
  font-size: 12.5px;
  color: var(--ds-error);
}
/* Legible labels (>=14px, token contrast). */
.ds-field-label {
  font-size: 14px;
  font-weight: 500;
  color: var(--ds-text);
  letter-spacing: 0.02em;
}
.ds-field-label .ds-req {
  color: var(--ds-gold);
}

/* =========================================================================
   P1-8 — One quantity stepper everywhere
   -------------------------------------------------------------------------
   Three pages each shipped their own stepper (cart `.qty-control`, product
   `.qty-control`, legacy product `.lp-qty` with vertical ▲▼ arrows) in three
   shapes and colour systems. Collapse them to ONE token-driven horizontal
   `−  value  +` control so the buy flow feels the same wherever a quantity is
   picked. Markup: `.ds-stepper > (button.ds-stepper__btn, span.ds-stepper__val,
   button.ds-stepper__btn)`. 48px hit targets, tabular value, keyboard ring.
   ========================================================================= */
.ds-stepper {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius);
  overflow: hidden;
  background: var(--ds-bg);
}
.ds-stepper__btn {
  -webkit-appearance: none;
  appearance: none;
  background: none;
  border: none;
  width: var(--ds-control-min);
  height: var(--ds-control-min);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  color: var(--ds-gold);
  transition: background-color 0.2s var(--ds-ease), color 0.2s var(--ds-ease);
}
.ds-stepper__btn:hover:not(:disabled) {
  background: color-mix(in srgb, var(--ds-gold) 12%, transparent);
  color: var(--ds-gold-strong);
}
.ds-stepper__btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.ds-stepper__btn:focus-visible {
  outline: none;
  box-shadow: var(--ds-focus-ring);
}
.ds-stepper__val {
  min-width: 56px;
  height: var(--ds-control-min);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-size: 1.05rem;
  color: var(--ds-text);
  border-left: 1px solid var(--ds-border);
  border-right: 1px solid var(--ds-border);
  font-variant-numeric: tabular-nums;
}

/* =========================================================================
   P1-9 — One social-icon treatment everywhere
   -------------------------------------------------------------------------
   The theme renders footer socials as diamonds (rotate(45deg) container +
   counter-rotated glyph) while mobile / share rows are plain. Unify them to a
   single circular, token-driven container so there's one shape sitewide. The
   glyph counter-rotation in default.vue/home.vue is no longer needed.
   ========================================================================= */
.social_item .social_icons {
  transform: none !important;
  width: 44px !important;
  height: 44px !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  border-radius: 50% !important;
  border: 1px solid var(--ds-border) !important;
  color: var(--ds-text-muted) !important;
  background: transparent !important;
  transition: border-color 0.2s var(--ds-ease), color 0.2s var(--ds-ease),
    transform 0.2s var(--ds-ease) !important;
}
.social_item .social_icons:hover {
  border-color: var(--ds-gold) !important;
  color: var(--ds-gold) !important;
  transform: translateY(-2px) !important;
}
.social_item .social_icons:focus-visible {
  outline: none !important;
  box-shadow: var(--ds-focus-ring) !important;
}
/* SVG sits upright (no diamond counter-rotation) and scales gently on hover. */
.social_item .social_icons .social_svg {
  transform: none !important;
}
.social_item .social_icons:hover .social_svg {
  transform: scale(1.1) !important;
}
/* Footer is a dark band in BOTH page themes: its background is
   `var(--paragraph-title-color, #2a2a2a)`, and the light palette leaves that
   var unset → it falls back to #2a2a2a. The token rule above, however, flips to
   the light-mode foreground (a dark glyph + faint border) when the page is in
   light mode, sinking the footer socials into that dark band. Re-pin them to a
   light-on-dark gold stroke in light mode so they stay legible. Dark mode reads
   correctly already and is left untouched. */
/* Force the intended dark footer band in light mode: this tenant's light palette
   sets --paragraph-title-color to a light value, which turns the band cream and
   hides the scheme_dark (light) footer text. The dark band also gives the cream
   page a strong closing seam. */
:root[data-color-theme="light"] .site_footer_wrap {
  background-color: #1a1510 !important;
  /* The footer is a dark band, so its text vars must stay LIGHT — otherwise the
     light-mode dark --paragraph-* defaults render footer text dark-on-dark. */
  --paragraph-text-color: #ece4d6;
  --paragraph-subtitle-color: #b8ad97;
  --paragraph-category-color: #c9a45c;
  --paragraph-title-color: #f3ead8;
  --ds-text: #ece4d6;
  --ds-text-muted: #b8ad97;
}
:root[data-color-theme="light"] .site_footer_wrap .social_item .social_icons {
  border-color: rgba(201, 164, 92, 0.45) !important;
  color: #b3a888 !important;
}
:root[data-color-theme="light"]
  .site_footer_wrap
  .social_item
  .social_icons:hover {
  border-color: var(--ds-gold-strong, #e6c98a) !important;
  color: var(--ds-gold-strong, #e6c98a) !important;
}

/* Light mode card definition: the CMS light palette sets --image-color =
   --site-bg-color, so card surfaces share the page tone and "melt" into it
   (review #32/#33). A soft resting shadow lifts the boxed card primitives off
   the background so the layout reads as distinct surfaces. Dark mode keeps its
   own deeper shadow tokens and is untouched. */
:root[data-color-theme="light"] :is(.sp-card, .ds-card) {
  box-shadow: 0 4px 16px rgba(60, 45, 25, 0.08);
}
/* Titles that read from --title-color (default #fff, meant for dark bands) but
   sit on a CREAM content surface — pin them dark in light mode. */
:root[data-color-theme="light"] :is(.ev-agenda-title, .ccs-title) {
  color: var(--paragraph-title-color, #211a12);
}
/* Meta text that hard-codes a light grey/gold (dates, struck prices, counts,
   pillar titles, quote attributions) and fails AA on cream — pin to readable
   light-mode tokens. */
:root[data-color-theme="light"]
  :is(
    .wn-price-old,
    .bl-recent-date,
    .bl-classic-date,
    .bl-widget-count,
    .wn-year
  ) {
  color: var(--ds-text-muted, #5d513e) !important;
}
:root[data-color-theme="light"]
  :is(.bl-quote-author, .ev-agenda-mon, .ev-agenda-venue) {
  color: var(--paragraph-category-color, #6e5214) !important;
}
/* Header nav links read var(--title-color, #c9a96e) — gold, which is correct on
   the dark home hero (top_panel_style_2) but only 1.8:1 on the cream INTERIOR
   header (top_panel_style_1) in light mode. Pin interior nav links dark (still
   following a configured --title-color when the tenant sets one). */
:root[data-color-theme="light"] .site-header .site-nav__item > a,
:root[data-color-theme="light"] .site-header .site-nav__item > a span {
  color: var(--title-color, #2b2118) !important;
}
/* The shop hero carousel is a DARK band, so (like the footer) keep its text vars
   LIGHT — otherwise the light-mode dark --paragraph-* defaults render its
   title/description dark-on-dark. */
:root[data-color-theme="light"] .sp-hero {
  --paragraph-title-color: #f3ead8;
  --paragraph-text-color: #ece4d6;
  --paragraph-subtitle-color: #cfc3aa;
  --title-color: #ffffff;
  --ds-text: #ece4d6;
  --ds-text-muted: #cfc3aa;
}
/* Hardcoded light greys (filter tabs, struck prices) that fail AA on cream —
   pin to readable tokens. */
:root[data-color-theme="light"] :is(.sp-price-old, .sp-cat-btn) {
  color: var(--ds-text-muted, #5d513e) !important;
}
/* Generic content text that inherits the theme's pale body grey (#7a7a7a) —
   addresses, the empty-cart line, form labels, the auth divider — reads at only
   ~3.4:1 on cream. Set a readable content default in light mode (components with
   their own colour still win; the dark title-strip/footer set their own). */
:root[data-color-theme="light"] .site-content {
  color: var(--paragraph-text-color, #2b2118);
}

/* =========================================================================
   P1-11 — Footer anchoring on short pages
   -------------------------------------------------------------------------
   Make `.page-wrap` a full-height flex column so the footer is pushed to the
   viewport bottom on sparse pages (cart, login, account) instead of floating
   mid-screen. Content between the (sticky) header and footer grows to fill.
   ========================================================================= */
.page-wrap {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
.page-wrap > .mk-footer {
  margin-top: auto;
}

/* =========================================================================
   P1-12 — Hover / interaction vocabulary
   -------------------------------------------------------------------------
   One consistent language: cards lift + inner image scales (1.03); links grow
   a gold underline; icon-cards brighten their border + lift. Keyboard
   :focus-visible mirrors hover. Gated on prefers-reduced-motion.
   ========================================================================= */
@media (prefers-reduced-motion: no-preference) {
  /* Cards lift + inner image scales on hover / focus-within. */
  .ds-card {
    transition: transform 0.25s var(--ds-ease), box-shadow 0.25s var(--ds-ease);
  }
  .ds-card:hover,
  .ds-card:focus-within {
    transform: translateY(-6px);
    box-shadow: var(--ds-shadow-card);
  }
  .ds-card .ds-media img {
    transition: transform 0.3s var(--ds-ease);
  }
  .ds-card:hover .ds-media img {
    transform: scale(1.03);
  }
}
/* Clip the frame so the scaled image doesn't bleed past the card. */
.ds-card .ds-media {
  overflow: hidden;
}

/* Underline-grow links (the .ds-link helper + theme content links). */
.ds-link {
  position: relative;
  color: var(--ds-gold);
  text-decoration: none;
}
.ds-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.25s var(--ds-ease);
}
.ds-link:hover::after,
.ds-link:focus-visible::after {
  transform: scaleX(1);
}

/* Global keyboard focus ring for links + buttons the components don't ring
   themselves. Components with their own ring above are unaffected. */
a:focus-visible,
button:focus-visible {
  outline: none;
  box-shadow: var(--ds-focus-ring);
  border-radius: var(--ds-radius);
}

/* =========================================================================
   P1-13 — Scroll-reveal (v-reveal directive)
   -------------------------------------------------------------------------
   Elements tagged with `v-reveal` fade into place the first time they scroll
   into view. plugins/reveal.ts adds the hidden `.reveal` class on mount and
   `.is-visible` on first intersection, then unobserves (reveal-once). A group
   wrapper (`v-reveal="{ group: true }"`) carries data-reveal-group and the
   observer staggers its direct children.

   The MOTION STYLE is admin-driven and GLOBAL (same on every page): the CMS
   Appearance page persists `revealAnim` + `revealSpeed` into
   site_appearance.extra, and appearance.client.ts reflects them as two custom
   properties on <html> — `--reveal-from` (the hidden-state transform) and
   `--reveal-duration`. Unset → the fade-up / 0.7s defaults below. No-JS users
   are un-hidden by the <noscript> rule in nuxt.config; reduced motion and the
   admin motion-off toggle are handled below.
   ========================================================================= */
.reveal {
  opacity: 0;
  transform: var(--reveal-from, translateY(20px));
  transition: opacity var(--reveal-duration, 0.7s)
      cubic-bezier(0.22, 0.61, 0.36, 1),
    transform var(--reveal-duration, 0.7s) cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: opacity, transform;
}
.reveal.is-visible {
  opacity: 1;
  transform: none;
}
/* Staggered group children — the observer sets each child's transition-delay. */
[data-reveal-group="true"] > * {
  opacity: 0;
  transform: var(--reveal-from, translateY(20px));
  transition: opacity var(--reveal-duration, 0.7s)
      cubic-bezier(0.22, 0.61, 0.36, 1),
    transform var(--reveal-duration, 0.7s) cubic-bezier(0.22, 0.61, 0.36, 1);
}
[data-reveal-group="true"].is-visible > * {
  opacity: 1;
  transform: none;
}
/* Accessibility: honour an explicit reduced-motion preference — everything in
   place, no movement (the observer also skips observing these visitors). */
@media (prefers-reduced-motion: reduce) {
  .reveal,
  [data-reveal-group="true"] > * {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

/* =========================================================================
   Admin-settable structural controls
   -------------------------------------------------------------------------
   "Set everything from the admin": the CMS Appearance page persists three
   non-colour knobs into `site_appearance.extra`, and plugins/appearance.client
   .ts reflects them as classes on <html>. Defaults (no class) keep the shipped
   behaviour, so an un-configured / offline site looks exactly as before.
     • ds-sticky-off       — Sticky pinning OFF; slim STATIC masthead (P1-5).
     • ds-motion-off       — Scroll-reveal + card-hover motion OFF (P1-12/13).
     • ds-density-compact /
       ds-density-spacious — Section spacing density (overrides the rhythm
                             tokens; the page-title band height is the visible
                             effect, P1-10).
   ========================================================================= */
/* Sticky header OFF (admin opt-out): render the structure review's slim
   masthead, but STATIC — the header sits compact at the top and scrolls away
   normally instead of pinning. The compaction (logo → gold wordmark, collapsed
   nav row) is shared with the scrolled state via the `:is(body.ds-scrolled,
   html.ds-sticky-off)` selectors above; here we just unpin it and give the bar
   a surface + hairline so it reads as its own block. This keeps the opt-out
   from reverting to the ~515px crest the review flagged. */
html.ds-sticky-off .site-header {
  position: static;
  background-color: var(--ds-bg);
  border-bottom: 1px solid var(--ds-border-soft);
}
/* Motion OFF: reveal elements render in place, cards don't lift. The `html`
   type bump + !important clears the reveal hidden-state and hover rules. */
html.ds-motion-off .reveal,
html.ds-motion-off [data-reveal-group="true"] > * {
  opacity: 1 !important;
  transform: none !important;
  transition: none !important;
}
html.ds-motion-off .ds-card:hover {
  transform: none !important;
}
/* Density: re-scale the spacing tokens. Comfortable = the :root defaults. */
html.ds-density-compact {
  --ds-title-band-py: clamp(28px, 3.5vw, 40px);
  --ds-space-4: clamp(28px, 4vw, 48px);
  --ds-space-5: clamp(44px, 6vw, 80px);
}
html.ds-density-spacious {
  --ds-title-band-py: clamp(52px, 6.5vw, 76px);
  --ds-space-4: clamp(56px, 8vw, 96px);
  --ds-space-5: clamp(88px, 12vw, 160px);
}

/* ── P3.6 · Macedonian header nav fits one row ────────────────────────────
   The flat 8-item desktop nav uses a generous `padding: 1em 2.5em` per link
   (theme base) with UPPERCASE labels. Cyrillic labels run materially longer
   than the English ones once uppercased — "НАШАТА ФИЛОЗОФИЈА" vs
   "OUR PHILOSOPHY", "ПРОДАВНИЦА" vs "SHOP" — so at the same per-item padding
   the row crowds the logo / utilities (Design Review v1 · P3.6). For mk only
   we trim the horizontal padding + drop letter-spacing so the longer labels
   still sit on one comfortable row. `html:lang(mk)` matches the BCP-47
   `mk-MK` lang app.vue binds via useLocaleHead. Desktop horizontal nav only
   (≥960px); below that the mobile slide-out stacks the items, so it's never
   crowded and is left untouched. */
@media (min-width: 960px) {
  html:lang(mk) .site-nav__item > a {
    padding-left: 1em;
    padding-right: 1em;
    letter-spacing: 0;
  }
}
/* Same crowding bites EN too, but only in the narrow desktop band right at the
   horizontal-nav hand-off: on the interior layout the 8-item EN nav wraps to a
   second row at ~1024px (it's comfortable again by ~1100px, and the burger
   takes over below 1024px). Trim the per-link padding in that band for ALL
   locales so it stays one row; the spacious 2.5em is preserved at ≥1200px,
   where Design Review v2 praised it. (mk's ≥960px rule above is stronger and
   wins inside this band, so mk keeps its tighter spacing.) */
@media (min-width: 1024px) and (max-width: 1280px) {
  .site-nav__item > a {
    padding-left: 1.05em;
    padding-right: 1.05em;
    letter-spacing: 0.06em;
  }
  /* mk labels run materially longer; shrink them a touch more in this crowded
     band so the 8-item row stays single-line down to the 1024px burger hand-off. */
  html:lang(mk) .site-nav__item > a {
    font-size: 0.82rem;
    padding-left: 0.75em;
    padding-right: 0.75em;
  }
}

/* =========================================================================
   A11y — Skip-to-content link + main landmark
   -------------------------------------------------------------------------
   First focusable element on the page; sits off-screen until focused, then
   slides in. Targets the `<main id="ds-main">` wrapper added around the page
   slot in both layouts. `.ds-main` also carries `flex: 1 0 auto` so it grows
   inside the `.page_wrap` flex column — reinforcing the P1-11 footer anchoring
   on short pages.
   ========================================================================= */
.ds-skip-link {
  position: absolute;
  left: 12px;
  top: 12px;
  z-index: 10000;
  /* Fixed dark bg + light text (the theme's link rules were tinting the <a>
     gold, leaving gold-on-gold), so it's bulletproof in both themes. */
  background: #1a1510;
  color: #f5efe2 !important;
  border-radius: var(--ds-radius);
  font-family: inherit;
  font-weight: 600;
  text-decoration: none;
  /* Visually hidden until keyboard focus. Clipping to a 1px box (instead of the
     old `translateY(-160%)` slide) guarantees it can never peek out: the top
     referral/announcement bars push this element's absolute-positioning context
     downward, so the slide-up reveal left it visible over the referral bar. */
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}
.ds-skip-link:focus,
.ds-skip-link:focus-visible {
  width: auto;
  height: auto;
  padding: 10px 18px;
  overflow: visible;
  clip: auto;
  clip-path: none;
  outline: none;
  box-shadow: var(--ds-focus-ring);
}
.ds-main {
  flex: 1 0 auto;
}
.ds-main:focus {
  outline: none;
}
