/**
 * Oliu design tokens and base styles.
 *
 * SOURCE OF EVIDENCE: every value in this file is cited from
 * docs/M5_3_LEGACY_VISUAL_UX_AUDIT.md (sections noted inline), which in
 * turn cites exact files under cosmeticsweb/cosmetic/. Nothing here is
 * invented — where the audit found no confirmed value, this file uses a
 * plain, undecorated fallback rather than guessing.
 *
 * Q6f (font licensing): the actual "Laviossa-Medium" and "DB-BrandVoice-X"
 * font FILES were restored into /assets/fonts/ from the legacy source
 * (cosmeticsweb/cosmetic/public/font/) on 08 Aug 2026, per explicit owner
 * approval to prioritize legacy visual fidelity — see
 * docs/Q6F_FONT_RESTORATION.md. No LICENSE/README was ever found
 * alongside these files in the legacy source or anywhere in this project;
 * licensing/redistribution rights remain UNCONFIRMED. The system-font
 * fallback stacks below are kept in place (not removed) so the site still
 * renders correctly if the fonts are ever pulled again pending a licensing
 * decision.
 */

/* ---- Typography (audit §14) ---- */
@font-face {
  font-family: "Laviossa-Medium";
  src: url("../fonts/Laviossa-Medium.otf") format("opentype");
  font-display: swap;
}
@font-face {
  font-family: "DB-BrandVoice-X-Regular";
  src: url("../fonts/DB-BrandVoice-X-Regular.ttf") format("truetype");
  font-display: swap;
}
@font-face {
  font-family: "DB-BrandVoice-X-Bold";
  src: url("../fonts/DB-BrandVoice-X-Bold.ttf") format("truetype");
  font-weight: 700;
  font-display: swap;
}

:root {
  /* Colors — audit §15. Two distinct confirmed cream values kept
     distinct on purpose (the legacy source itself never unified them). */
  --oliu-color-primary: #FF6801;
  --oliu-color-text: #272726;
  --oliu-color-text-muted: #A0A0A0;
  --oliu-color-line-green: #00C200;
  --oliu-color-cream-section: #FDF8F5;
  --oliu-color-cream-footer: #F9ECE4;
  --oliu-color-white: #FFFFFF;
  --oliu-color-border-light: #F0F3F8;
  --oliu-color-border-mid: #E6E2E2;
  --oliu-color-border-blue: #D1DCE7;
  --oliu-color-accent-teal: #73DECA;

  /* Typography */
  --oliu-font-heading: "Laviossa-Medium", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --oliu-font-body: "DB-BrandVoice-X-Regular", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --oliu-font-body-bold: "DB-BrandVoice-X-Bold", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  /* Layout widths — audit §16 */
  --oliu-content-width: 1080px;
  --oliu-content-width-mid: 900px;
  --oliu-content-width-wide: 1320px;

  /* Spacing rhythm — audit §16 */
  --oliu-space-section: 64px;
  --oliu-space-sub: 32px;
  --oliu-space-tight: 16px;
}

/* ---- Responsive breakpoints (audit §17) ----
   Legacy source used 767px in CSS and 768px in one JS hook — a
   confirmed 1px inconsistency, not a second real breakpoint. This
   theme standardizes on 768px everywhere (documented choice, not a
   silent guess) as the single mobile breakpoint. Secondary confirmed
   breakpoints (900px, 1124px) are used where the audit found them. */

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  font-family: var(--oliu-font-body);
  color: var(--oliu-color-text);
  /* M5.13a (G1/G11 fix): no background was ever set here, so any
     section without its own explicit background (.oliu-hero,
     .oliu-contact-grid__details) fell through to the browser's default
     canvas fill — near-black under prefers-color-scheme: dark —
     leaving --oliu-color-text (#272726) illegible on top of it.
     Confirmed via getComputedStyle: body background-color was
     rgba(0,0,0,0). Single shared-rule fix, no new color introduced. */
  background: var(--oliu-color-white);
}

h1, h2, h3, h4 {
  font-family: var(--oliu-font-heading);
  margin: 0;
  font-weight: 500;
}

a { color: inherit; text-decoration: none; }
img { max-width: 100%; height: auto; display: block; }

.oliu-container {
  width: 100%;
  max-width: var(--oliu-content-width);
  margin: 0 auto;
  padding: 0 20px;
}
.oliu-container--mid { max-width: var(--oliu-content-width-mid); }
.oliu-container--wide { max-width: var(--oliu-content-width-wide); }

@media (max-width: 768px) {
  .oliu-container { padding: 0 16px; }
}

/* ---- Buttons (audit §5, §13) ---- */
.oliu-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--oliu-font-body);
  font-size: 18px;
  padding: 12px 24px;
  border: 1px solid var(--oliu-color-text);
  background: var(--oliu-color-white);
  color: var(--oliu-color-text);
  cursor: pointer;
}
.oliu-btn--primary {
  border-color: var(--oliu-color-primary);
  color: var(--oliu-color-primary);
}
.oliu-btn[disabled],
.oliu-btn--disabled {
  border-color: var(--oliu-color-text-muted);
  color: var(--oliu-color-text-muted);
  cursor: not-allowed;
}
/* Line CTA colour is confirmed distinct from the site primary (audit §13/§14) */
.oliu-btn--line {
  background: var(--oliu-color-line-green);
  border: 0;
  border-radius: 30px;
  color: var(--oliu-color-white);
  font-family: var(--oliu-font-body-bold);
}

/* ---- Header / nav (audit §1) ----
   Q6a (flat vs grouped nav) is OPEN — deliberately not decided here.
   Menu items themselves come from wp_nav_menu() (an editor-managed
   WordPress menu), so this CSS only styles whatever structure an
   editor builds; it does not assume flat or grouped.

   P1 originally gave this bar a full-width black background, on the
   belief that legacy's header was solid black. CORRECTED during the
   visual fidelity pass (docs/VISUAL_FIDELITY_PASS_2026-08-09.md, Batch
   A): legacy's header is `<AppBar color="transparent">` — confirmed via
   the real injected CSS rule (`background-color: transparent`) — the
   "black bar" in the original audit was a dark-mode rendering artifact,
   not real legacy design (same bug class as audit §2.5). The bar is now
   white with a subtle drop shadow, reproducing legacy's actual MUI
   `elevation={10}` AppBar shadow (values read from the live legacy
   computed style, not invented). .oliu-header stays width-capped by
   .oliu-container for the actual nav content. */
.oliu-header-bar {
  background: var(--oliu-color-white);
  box-shadow: 0 3px 3px -2px rgba(0,0,0,0.2), 0 3px 4px rgba(0,0,0,0.14), 0 1px 8px rgba(0,0,0,0.12);
}
.oliu-header {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: space-between;
  padding: 10px 0;
}
/* UAT R1 visual remediation (23 Aug 2026): the logo link/image previously
   had no shrink/overflow constraint of its own. Combined with the
   invalid nested-<a> markup this template used to emit (fixed
   separately, see header.php), the logo block's content could exceed
   its fair flex share on narrow phones, and — because flex items don't
   wrap by default — that overflow silently pushed the mobile hamburger
   toggle past the right edge of the viewport instead of visibly
   colliding with it. Confirmed via real headless-browser screenshot at
   375-390px (the toggle was completely absent from the visible frame,
   not just misstyled). min-width:0 lets this flex item actually honor
   its shrink factor instead of defaulting to its content's min-content
   width; flex-shrink:0 on the toggle guarantees it never gives up its
   own space to the logo. */
.oliu-header__logo { min-width: 0; flex-shrink: 1; overflow: hidden; }
.oliu-header__logo a { color: var(--oliu-color-text); display: inline-flex; align-items: center; max-width: 100%; }
.oliu-header__toggle { flex-shrink: 0; }
.oliu-header__nav > ul > li > a { color: var(--oliu-color-text); }
.oliu-header__nav .sub-menu a { color: var(--oliu-color-text); }
/* Fixed width alongside height: this environment doesn't reliably derive
   width from the img's width/height attributes' aspect ratio when only
   height is set via CSS (same class of bug fixed for footer social icons
   above) — width is the exact proportional value for the confirmed
   legacy logo's 300x137 source at a 45px height (matches legacy Header.js). */
.oliu-header__logo img { height: 45px; width: 98.5px; }
.oliu-header__nav { display: none; }
.oliu-header__nav ul { list-style: none; display: flex; gap: 24px; margin: 0; padding: 0; }
/* Typography matched to legacy nav links (Header.style.js MenuItemButton,
   computed live: Laviossa-Medium 14px/500, 0.4px letter-spacing). */
.oliu-header__nav a { font-family: var(--oliu-font-heading); font-size: 14px; font-weight: 500; letter-spacing: 0.4px; }
/* Products dropdown (Q6a.2): desktop hover/focus reveal, no JS needed here. */
.oliu-header__nav li.menu-item-has-children { position: relative; }
.oliu-header__nav .sub-menu {
  display: none;
  list-style: none;
  position: absolute;
  top: 100%; left: 0;
  min-width: 160px;
  margin: 0; padding: 8px 0;
  background: var(--oliu-color-white);
  box-shadow: -4px 4px 18px rgba(51, 78, 105, 0.1);
  z-index: 1040;
}
.oliu-header__nav li.menu-item-has-children:hover > .sub-menu,
.oliu-header__nav li.menu-item-has-children:focus-within > .sub-menu { display: block; }
.oliu-header__nav .sub-menu li { padding: 8px 16px; }
.oliu-header__toggle {
  background: none; border: 0; cursor: pointer; color: var(--oliu-color-primary);
  font-size: 28px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 4px;
}
/* UAT R1 visual remediation (23 Aug 2026): confirmed via real
   headless-browser screenshot at 390px that the toggle was being pushed
   entirely outside the visible viewport by *some* horizontal-overflow
   source on the page (not narrowed down to one exact cause after
   multiple targeted flex/markup fixes — those are kept above as genuine
   improvements, not reverted). Pinning the toggle to the viewport with
   `position: fixed` makes it immune to ANY document-width overflow,
   wherever it originates, which matters more here than root-causing the
   overflow itself: without this, mobile visitors have no way at all to
   reach navigation. Desktop is unaffected (this rule only applies below
   769px, same breakpoint the toggle is already display:none above). */
@media (max-width: 768px) {
  .oliu-header__toggle {
    position: fixed;
    top: 14px;
    right: 16px;
    z-index: 1060;
    background: var(--oliu-color-white);
    border-radius: 50%;
    box-shadow: 0.5px 0.5px 8px rgba(16, 42, 67, 0.15);
  }
}
@media (min-width: 769px) {
  .oliu-header__nav { display: block; }
  .oliu-header__toggle { display: none; }
}
.oliu-header__mobile-menu {
  display: none;
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: 290px;
  background: var(--oliu-color-white);
  box-shadow: -4px 4px 18px rgba(51, 78, 105, 0.1);
  padding: 16px 0;
  z-index: 1050;
  overflow: auto;
}
.oliu-header__mobile-menu.is-open { display: block; }
.oliu-header__mobile-menu ul { list-style: none; margin: 0; padding: 0; }
.oliu-header__mobile-menu li { padding: 12px 24px; }
/* Products expand/collapse (Q6a.2): submenu hidden until the parent li
   gets .is-open, toggled by nav.js on click (no new drawer mechanism). */
.oliu-header__mobile-menu .sub-menu { display: none; padding: 0; margin-top: 8px; }
.oliu-header__mobile-menu li.menu-item-has-children.is-open > .sub-menu { display: block; }
.oliu-header__mobile-menu .sub-menu li { padding: 8px 24px 8px 36px; }
.oliu-header__mobile-menu .menu-item-has-children > a::after { content: " \25BE"; font-size: 12px; }
@media (max-width: 768px) {
  /* Top-level items only — the browser-default 16px is pinned back
     explicitly on .sub-menu so the Products dropdown (Face/Hair/Body/
     Wellness) doesn't inherit the larger top-level size. */
  .oliu-header__mobile-menu > ul { font-size: 24px; }
  .oliu-header__mobile-menu .sub-menu { font-size: 16px; }
}

/* ---- Footer (audit §12) ---- */
.oliu-footer {
  background: var(--oliu-color-cream-footer);
  padding: var(--oliu-space-section) 0;
  margin-top: var(--oliu-space-section);
}
@media (max-width: 768px) {
  /* Mobile UI audit (05 Sep 2026), P1: the sitewide fixed floating CTA
     balloon (.oliu-balloon--global, ~54px tall incl. padding, bottom: 2%)
     reserves no space of its own in document flow, so at the true end of
     scroll on any page it can sit on top of the footer's copyright line
     and nav links. Extra bottom padding here, not a change to the
     balloon itself, keeps that final content clear on mobile without
     touching desktop (where the balloon sits further from short pages'
     footers) or the balloon's own confirmed-legacy positioning. */
  .oliu-footer { padding-bottom: calc(var(--oliu-space-section) + 56px); }
}
.oliu-footer__grid { display: flex; flex-wrap: wrap; gap: 32px; }
.oliu-footer__brand { flex: 1 1 320px; }
.oliu-footer__brand img { height: auto; width: 150px; margin-bottom: 16px; }
/* Typography matched to legacy (Footer.style.js `FooterAddress`/`Menu`,
   visual fidelity pass Batch E): address 24px/30px, nav links 18px/21px
   weight 500 — was 20px/no line-height and unstyled size/weight. */
.oliu-footer__address { font-size: 24px; line-height: 30px; max-width: 70%; }
.oliu-footer__social { display: flex; gap: 12px; margin-top: 16px; }
.oliu-footer__social a { display: block; flex: 0 0 auto; }
.oliu-footer__social img { width: 32px; height: 32px; }
.oliu-footer__nav { flex: 1 1 320px; }
/* UAT R1 visual remediation (24 Aug 2026): 3-column grid, column-major
   fill, matching legacy's 3-stacked-column footer nav
   (`work/visual_baseline/legacy/desktop/03_brands_footer.jpg`) — was a
   single flex-wrap row (2 items, so visually indistinguishable from a
   list either way until the footer menu itself was enriched to 6 items
   alongside this change). */
.oliu-footer__nav ul {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, auto);
  grid-template-rows: repeat(2, auto);
  grid-auto-flow: column;
  gap: 12px 48px;
  margin: 0;
  padding: 0;
}
@media (max-width: 768px) {
  .oliu-footer__nav ul { grid-template-columns: repeat(2, auto); grid-template-rows: repeat(3, auto); gap: 8px 32px; }
}
.oliu-footer__nav a { font-family: var(--oliu-font-heading); font-size: 18px; line-height: 21px; font-weight: 500; color: var(--oliu-color-primary); }
.oliu-footer__divider { border: 0; border-top: 1px solid var(--oliu-color-border-blue); margin: 32px 0 16px; }
.oliu-footer__copyright { text-align: center; color: var(--oliu-color-text-muted); font-size: 14px; margin: 0; }

@media (max-width: 768px) {
  .oliu-footer__address { max-width: 100%; }
}

/* ---- Balloon / floating CTA (audit §13) ---- */
.oliu-balloon {
  position: fixed;
  bottom: 2%;
  right: 20px;
  z-index: 900;
  display: flex;
  gap: 8px;
  padding: 8px;
  background: var(--oliu-color-cream-footer);
  border-radius: 30px;
  box-shadow: 1px 1px 16px 10px rgba(0,0,0,0.1);
}
/* flex-shrink:0 on the link wrappers — without it, the generic
   `img { max-width: 100% }` rule lets flexbox squeeze these icons
   narrower than their fixed width on narrow viewports (confirmed:
   ~22x32 instead of 32x32 on a 375px screen), distorting them. */
.oliu-balloon > a { flex-shrink: 0; }
.oliu-balloon img { width: 32px; height: 32px; object-fit: contain; }
@media (max-width: 768px) {
  /* 07 Sep 2026: reported "slightly overflows" on a real phone even
     though emulated widths down to 360px showed clear margin either
     side — likely device text-size/zoom rather than viewport width, so
     trimmed the balloon's own chrome (not the 32x32 icons, which must
     stay fixed) for extra safety margin rather than guessing further. */
  .oliu-balloon { right: 50%; transform: translateX(50%); gap: 6px; padding: 6px; }
  .oliu-balloon__shop { padding: 0 14px; font-size: 13px; }
}
/* UAT R1 visual remediation (24 Aug 2026): sitewide use of this
   already-built class (see oliu_render_floating_cta(), inc/template-tags.php)
   — confirmed legacy element, previously only wired up inline/neutralized
   on the Contact hero. The Shop Now pill reuses .oliu-btn--line's colour
   (legacy's confirmed distinct Line-green CTA colour) at a size that fits
   the 38px icon row rather than the larger inline-button padding/font-size
   used elsewhere on the site. */
.oliu-balloon__shop {
  height: 32px;
  padding: 0 18px;
  font-size: 14px;
  white-space: nowrap;
}

/* ---- Card family (audit §4, §7, §8) ----
   Shared "Popular" ribbon pattern confirmed identical between product
   and brand cards — implemented once here, reused by both. */
.oliu-card {
  background: var(--oliu-color-white);
  border: 1px solid var(--oliu-color-border-light);
  box-shadow: 0.5px 0.5px 8px rgba(16, 42, 67, 0.1);
  position: relative;
}
.oliu-card__ribbon {
  position: absolute;
  top: 10px; right: -10px;
  background: var(--oliu-color-primary);
  color: var(--oliu-color-white);
  padding: 4px 16px;
  font-size: 16px;
}
.oliu-card__image { width: 100%; height: 230px; object-fit: cover; object-position: center; padding: 10px; }
/* Brand logos: 1:1 square, uncropped (contain, not cover) — a cover crop
   cuts off logo text/edges, which cover-fit at a fixed 230px height did
   on narrow (e.g. 3-up mobile carousel) columns. */
.oliu-brand-card .oliu-card__image { height: auto; aspect-ratio: 1 / 1; object-fit: contain; }
.oliu-card__body { padding: 24px; }
.oliu-card__title { font-size: 22px; font-weight: 600; margin: 0 0 8px; }
@media (max-width: 768px) {
  .oliu-card__title { font-size: 18px; }
}
.oliu-card__meta { color: var(--oliu-color-text-muted); font-size: 18px; margin: 0; }
/* M5.13f: 2-line clamp on the brand card description, matching legacy
   CardBrand.js's confirmed 2-line-clamped description (M5_13C2 §3). A
   character-count clamp is already applied server-side (template-tags.php)
   as the primary safety net — this is a second, purely visual guard. */
.oliu-card__desc {
  margin-top: 4px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.oliu-card__price { color: var(--oliu-color-primary); font-weight: 700; font-size: 25px; margin-top: 16px; display: inline-block; vertical-align: baseline; }
/* Requested change: was-price now sits on the same line as the final
   price (instead of stacking below it) and is rendered slightly
   smaller than the final price rather than matching it 1:1. */
.oliu-card__price-was { display: inline-block; vertical-align: baseline; color: var(--oliu-color-text-muted); text-decoration: line-through; font-weight: 300; font-size: 19px; margin-top: 16px; margin-left: 10px; }
@media (max-width: 767px) {
  .oliu-card__price-was { font-size: 15px; margin-left: 8px; }
}

/* ---- Grid ----
   M5.13d: grid tracks use minmax(0, 1fr) rather than bare 1fr. A bare
   `1fr` track's minimum size defaults to the content's min-content width
   (the "grid blowout" behaviour), so a card with enough intrinsic content
   width can force its track wider than its fair 1fr share and push the
   grid past its container — this was the confirmed root cause of the
   74px `/brands/` mobile overflow and, since the ribbon's negative
   right-inset is anchored to the resulting oversized card, also of the
   25px `.oliu-card__ribbon` homepage mobile overflow (both documented in
   docs/M5_13C2_BRAND_VISUAL_QA.md §4/§7). minmax(0, 1fr) caps each
   track's minimum at 0, so tracks stay within their fair share and cards
   shrink (with wrapping/ellipsis handled by existing card content rules)
   instead of overflowing. */
.oliu-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px; }
@media (max-width: 900px) { .oliu-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 480px) { .oliu-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; } }
/* Homepage Blog section (front-page.php) — kept at 3 columns per owner
   request, distinct from the 4-column change applied to the rest of
   .oliu-grid's usages; mobile/tablet breakpoints above still apply since
   both classes are present on the same element. */
.oliu-grid--blog { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* /category/articles/ + /category/promotions/ (shared category.php
   template) — top spacing matched to the existing 64px gap already
   present below the grid (before the footer), which had no equivalent
   above it (the heading previously sat flush against the hero band). */
.oliu-articles-listing { margin-top: var(--oliu-space-section); }
.oliu-grid--listing .oliu-blog-card .oliu-card__date,
.oliu-grid--listing .oliu-blog-card .oliu-card__readmore { display: none; }
@media (max-width: 768px) {
  .oliu-grid--listing { grid-template-columns: 1fr; }
}
@media (max-width: 768px) {
  /* Blog (homepage) — single column list; each card becomes a row with
     the image at ~60% width beside the title. Excerpt/date/"Read more"
     are hidden, leaving only image + title per the confirmed scope. */
  .oliu-grid--blog { grid-template-columns: 1fr; }
  .oliu-blog-card a { display: flex; align-items: flex-start; gap: 12px; padding: 12px; }
  .oliu-blog-card .oliu-card__image { flex: 0 0 60%; width: 60%; height: auto; aspect-ratio: 1 / 1; padding: 0; }
  .oliu-blog-card .oliu-card__body { flex: 1; padding: 0; }
  /* Title/date/"Read more" hidden — excerpt shown in the title's place. */
  .oliu-blog-card .oliu-card__title,
  .oliu-blog-card .oliu-card__date,
  .oliu-blog-card .oliu-card__readmore { display: none; }
  .oliu-blog-card .oliu-card__excerpt { display: block; margin: 0; }
}
/* A "See more >" button sitting directly after a grid (Face/Hair/Body
   rows) had no spacing from the cards above it — scoped to that exact
   adjacency so other .oliu-btn uses elsewhere are unaffected. */
.oliu-grid + .oliu-btn { margin-top: var(--oliu-space-tight); }
/* "View More" (Face/Hair/Body rows) — centered under the section, pill
   shape matching the site's existing pill convention (.oliu-balloon's
   30px radius), rather than the default left-aligned square button. */
.oliu-btn--seemore { display: block; width: fit-content; border-radius: 30px; }
.oliu-grid + .oliu-btn--seemore { margin: 24px auto 0; }

/* ---- Homepage carousel (P2, docs/P2_HOME_CAROUSEL.md) ----
   Legacy (cosmeticsweb/cosmetic/pages/index.js) renders "Our Popular
   Product" and "Our Brand" with react-slick: slidesToShow 3 (>=950px),
   2 (575-949px), 1 (<575px); infinite: false; swipeToSlide: true;
   prev/next arrows hidden below 991px (styles/slick-custom.css). This
   is a dependency-free equivalent: a native horizontally-scrolling flex
   track (scroll-snap gives free touch/drag, no JS needed for that) plus
   two buttons that scroll by one slide width. No carousel library
   existed anywhere in this theme to reuse, so none was introduced. */
.oliu-carousel { position: relative; margin-top: 32px; }
.oliu-carousel__viewport {
  display: flex;
  gap: 24px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding-bottom: 4px;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.oliu-carousel__viewport::-webkit-scrollbar { display: none; }
.oliu-carousel__slide { flex: 0 0 calc((100% - 72px) / 4); min-width: 0; scroll-snap-align: start; }
@media (max-width: 949px) { .oliu-carousel__slide { flex-basis: calc((100% - 24px) / 2); } }
@media (max-width: 574px) { .oliu-carousel__slide { flex-basis: 100%; } }
@media (prefers-reduced-motion: reduce) { .oliu-carousel__viewport { scroll-behavior: auto; } }

.oliu-carousel__btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--oliu-color-border-light);
  background: rgba(255, 255, 255, 0.9);
  box-shadow: 0.5px 0.5px 8px rgba(16, 42, 67, 0.1);
  color: var(--oliu-color-primary);
  font-size: 22px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 1;
  padding: 0;
}
.oliu-carousel__btn--prev { left: 8px; }
.oliu-carousel__btn--next { right: 8px; }
.oliu-carousel__btn:disabled { opacity: 0.35; cursor: default; }
/* Matches legacy's own arrow-hiding breakpoint (max-width: 991px in
   styles/slick-custom.css) — below it, legacy relies on swipe only. */
@media (max-width: 991px) { .oliu-carousel__btn { display: none; } }
@media (max-width: 768px) {
  /* "Our Popular Product" — static 2-column grid instead of a swipeable
     carousel. Arrows are already hidden at this width (rule above); the
     scroll-based carousel.js becomes a harmless no-op once the viewport
     has no horizontal overflow. */
  .oliu-carousel--products .oliu-carousel__viewport {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    overflow: visible;
    scroll-snap-type: none;
  }
  .oliu-carousel--products .oliu-carousel__slide { flex: none; }

  /* "Our Brand" — real swipeable carousel, 3 logos visible per screen
     (not a static grid: touch/scroll still works, matching arrows-hidden
     behavior above). Card name/description/item-count (all inside one
     .oliu-card__body wrapper) are hidden, leaving only .oliu-card__image. */
  .oliu-carousel--brands .oliu-carousel__slide { flex-basis: calc((100% - 48px) / 3); }
  .oliu-carousel--brands .oliu-brand-card .oliu-card__body { display: none; }
}

/* ---- Page-cover band (audit §3, §9) ----
   Background CORRECTED during the visual fidelity pass
   (docs/VISUAL_FIDELITY_PASS_2026-08-09.md, Batch A/D): legacy's
   category/product-listing hero (cosmeticsweb/cosmetic/pages/Mode/Filter/
   index.js `.cover__Page`) uses a real gradient/pattern image
   (`bg-cover-new.png`), not a solid color — confirmed min-height 284px
   and white title/desc text match exactly what this band already had.
   Used as-is by category.php / archive-product.php /
   taxonomy-product_category.php; archive-brand.php gets its own
   `--brands` modifier below (different legacy background + 2-col layout). */
.oliu-cover-band {
  min-height: 284px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  background: var(--oliu-color-text) url('../images/covers/bg-cover-new.png') center/cover no-repeat;
  color: var(--oliu-color-white);
  padding: 48px 20px;
}
.oliu-cover-band__title { font-size: 48px; }
.oliu-cover-band__desc { font-size: 20px; max-width: 660px; margin-top: 16px; }
@media (max-width: 768px) {
  .oliu-cover-band__title { font-size: 24px; }
  .oliu-cover-band__desc { font-size: 16px; }
}

/* ---- Section rhythm (audit §16) ---- */
.oliu-section { padding: var(--oliu-space-section) 0; }
.oliu-section--cream { background: var(--oliu-color-cream-section); }
.oliu-section__title { font-size: 36px; color: var(--oliu-color-primary); margin-bottom: var(--oliu-space-sub); }
@media (max-width: 768px) {
  .oliu-section { padding: 48px 0; }
  .oliu-section__title { font-size: 24px; }
}

/* ---- Hero (M5.13f) ----
   Restores the legacy hero's 2-column layout (text left, product image
   right — pages/index.js's `Grid` with `xs=12 md=6` columns). Uses
   minmax(0, 1fr) tracks (same lesson as the M5.13d grid-blowout fix) so
   the image column can never force horizontal overflow. Collapses to a
   single column under the theme's standard 768px breakpoint, image below
   text — no new breakpoint or layout pattern introduced. */
.oliu-hero {
  background: url('../images/brands/bg-cover-brand.png') center/cover no-repeat;
}
.oliu-hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--oliu-space-sub);
  align-items: center;
}
.oliu-hero__image-wrap { justify-self: end; }
.oliu-hero__image { width: 100%; max-width: 376px; height: auto; }
/* Typography matched to legacy (pages/index.js `.grid-left h1`/`.desc`,
   visual fidelity pass Batch B/punch-list #11): the hero heading/desc
   had no explicit size at all, falling back to the browser's UA-default
   h1 (32px, dark text) — legacy is 52px/orange (32px on mobile), desc
   28px/32px (20px/24px on mobile). */
.oliu-hero__text h1 { font-size: 52px; color: var(--oliu-color-primary); line-height: 1.1; }
.oliu-hero__text p { font-family: var(--oliu-font-body); font-size: 28px; line-height: 32px; margin-top: 24px; }
@media (max-width: 768px) {
  .oliu-hero__grid { grid-template-columns: 1fr; }
  .oliu-hero__image-wrap { justify-self: center; margin-top: var(--oliu-space-tight); }
  .oliu-hero__image { max-width: 280px; }
  .oliu-hero__text h1 { font-size: 32px; }
  .oliu-hero__text p { font-size: 20px; line-height: 24px; }
}

/* ---- Product detail layout (M5.12e) ----
   Two-column grid — gallery left, info right — replacing the previously
   unstyled single-column stack (confirmed gap, M5.12d). Collapses to a
   single column at the theme's existing 768px breakpoint, preserving
   natural document order (gallery, then title/price/options/buy). Reuses
   existing spacing tokens only; no new design system introduced. The
   M5.12a proportional-image fix (global `img { height: auto }`) already
   covers the gallery image and is untouched here. */
.oliu-product-detail {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--oliu-space-sub);
  align-items: start;
  margin-top: var(--oliu-space-sub);
}
/* 07 Sep 2026 layout pass: brand logo (moved above the title, logo only
   — no more brand-name text link), title size, and the now-bare Buy
   button — none of these had any dedicated CSS before, only browser
   defaults. */
.oliu-product-detail__brand { display: block; }
.oliu-product-detail__brand img { height: 40px; width: auto; }
.oliu-product-detail__title { font-size: 18px; }
.oliu-product-detail__info > * + * {
  margin-top: var(--oliu-space-tight);
}
/* 07 Sep 2026: was a separate full-width section below the two-column
   layout (needed the wide --oliu-space-section gap to separate it from
   the layout above); now moved inline into .oliu-product-detail__info
   between price and Size, so it just uses that column's normal
   --oliu-space-tight rhythm like every other item in it. */
@media (max-width: 768px) {
  .oliu-product-detail {
    grid-template-columns: 1fr;
    gap: var(--oliu-space-tight);
  }
}

/* ---- Product gallery (P0, docs/VISUAL_AUDIT_LEGACY_VS_WORDPRESS.md §2.8) ----
   Legacy: large main image + thumbnail strip (active thumb has an
   orange border), lightbox-capable. WordPress had no gallery/thumbnail
   markup at all — confirmed the single largest gap in that audit.
   Images come from oliu_get_product_gallery_images() (the product's
   featured image + each distinct, real SKU image already imported into
   the ACF `skus` repeater) — no placeholder/stock image is ever used;
   a product with zero resolvable images simply renders an empty
   .oliu-product-detail__gallery, same as before this change, so the
   two-column layout never breaks. Main image is fixed to a square
   aspect-ratio box with object-fit: contain so no source image (any
   original dimensions) can force the page wider or taller than
   intended, on desktop or the single-column mobile stack. */
.oliu-gallery {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.oliu-gallery__main {
  width: 100%;
  aspect-ratio: 1 / 1;
  background: var(--oliu-color-cream-section);
  border: 1px solid var(--oliu-color-border-light);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  cursor: zoom-in;
}
.oliu-gallery__main-image {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.oliu-gallery__thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.oliu-gallery__thumb {
  width: 72px;
  height: 72px;
  padding: 2px;
  border: 2px solid var(--oliu-color-border-light);
  background: var(--oliu-color-white);
  cursor: pointer;
  display: block;
}
/* Active-thumbnail indicator, matching legacy's confirmed orange border. */
.oliu-gallery__thumb.is-active {
  border-color: var(--oliu-color-primary);
}
.oliu-gallery__thumb-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Minimal dependency-free lightbox (no library found in the theme to
   reuse — audit confirmed legacy is "lightbox-capable" but this theme
   had no image-gallery markup at all yet to inherit one from). */
.oliu-lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.85);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 2000;
  padding: 24px;
}
.oliu-lightbox.is-open { display: flex; }
.oliu-lightbox__image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
.oliu-lightbox__close {
  position: absolute;
  top: 16px;
  right: 20px;
  background: none;
  border: 0;
  color: var(--oliu-color-white);
  font-size: 36px;
  line-height: 1;
  cursor: pointer;
}

/* ---- Archive / category layout (M5.12f) ----
   Sidebar (category list) + main (product grid), two columns on desktop —
   replacing the previously unstyled stack where the category list rendered
   full-width above the grid (confirmed gap, M5.12 baseline §2/§6). Reuses
   existing spacing tokens and the theme's single 768px breakpoint only;
   the product grid/card component itself (.oliu-grid/.oliu-card) is
   untouched. */
.oliu-archive-layout {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  gap: var(--oliu-space-sub);
  align-items: start;
  margin-top: var(--oliu-space-sub);
}
.oliu-archive-main {
  min-width: 0;
}
@media (max-width: 768px) {
  .oliu-archive-layout {
    grid-template-columns: 1fr;
    gap: var(--oliu-space-tight);
  }
}

/* ---- Category sidebar hierarchy (category-sidebar UI work order, 05 Sep
   2026) ----
   Replaces the previous plain wp_list_categories() output (no active
   state, no visual distinction between the taxonomy's confirmed 3 levels,
   no spacing between the 4 top-level groups). Markup comes from
   oliu_render_category_sidebar() (inc/template-tags.php) via
   template-parts/category-sidebar.php, shared by both
   taxonomy-product_category.php and archive-product.php. Reuses existing
   tokens only (--oliu-color-primary for the active/brand accent, the
   existing heading/body font tokens); no new colours introduced. */
.oliu-cat-sidebar__group {
  border-bottom: 1px solid var(--oliu-color-border-light);
  padding-bottom: var(--oliu-space-tight);
  margin-bottom: var(--oliu-space-tight);
}
.oliu-cat-sidebar__group:last-of-type {
  border-bottom: none;
  padding-bottom: 0;
  margin-bottom: 0;
}
.oliu-cat-sidebar__parent {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  cursor: pointer;
  list-style: none;
  font-family: var(--oliu-font-heading);
  font-weight: 500;
  font-size: 16px;
}
.oliu-cat-sidebar__parent::-webkit-details-marker {
  display: none;
}
.oliu-cat-sidebar__parent::marker {
  content: "";
}
.oliu-cat-sidebar__parent::after {
  content: "+";
  color: var(--oliu-color-text-muted);
  font-family: var(--oliu-font-heading);
}
.oliu-cat-sidebar__group[open] > .oliu-cat-sidebar__parent::after {
  content: "\2212"; /* minus sign, matches the "+" glyph weight when open */
}
.oliu-cat-sidebar__parent a {
  color: var(--oliu-color-text);
  text-decoration: none;
}
.oliu-cat-sidebar__parent--active a {
  color: var(--oliu-color-primary);
  font-weight: 700;
}
.oliu-cat-sidebar__list {
  list-style: none;
  margin: var(--oliu-space-tight) 0 0;
  padding: 0;
}
.oliu-cat-sidebar__list .oliu-cat-sidebar__list {
  margin-top: 4px;
}
.oliu-cat-sidebar__child {
  padding: 6px 0 6px var(--oliu-space-tight);
  font-size: 14px;
}
.oliu-cat-sidebar__grandchild {
  padding: 4px 0 4px 32px;
  font-size: 13px;
}
@media (min-width: 769px) {
  .oliu-cat-sidebar__child { font-size: 18px; }
  .oliu-cat-sidebar__grandchild { font-size: 16px; }
}
.oliu-cat-sidebar__child a,
.oliu-cat-sidebar__grandchild a {
  color: var(--oliu-color-text);
  text-decoration: none;
}
.oliu-cat-sidebar__grandchild a {
  color: var(--oliu-color-text-muted);
}
.oliu-cat-sidebar__child--active > a,
.oliu-cat-sidebar__grandchild--active > a {
  color: var(--oliu-color-primary);
  font-weight: 700;
}

/* ---- Contact layout (M5.12g) ----
   Map + details two-column grid, replacing the previously unstyled stack
   (confirmed gap, M5.12d/M5.12 baseline §10). Reuses existing spacing
   tokens and the theme's single 768px breakpoint only; existing
   typography, `.oliu-btn`/`.oliu-btn--line`, `.oliu-footer__address`, and
   `.oliu-footer__social` are untouched. The map column's content comes
   from `the_content()` (editable, no confirmed embed yet per
   page-contact.php's own comment) — the iframe/img/embed rule below only
   caps width at 100% so whatever gets embedded can't force horizontal
   overflow; it does not alter height/aspect ratio, so a fixed-height
   embed's own dimensions are preserved as authored. */
.oliu-contact-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--oliu-space-sub);
  align-items: start;
  margin-top: var(--oliu-space-sub);
}
.oliu-contact-grid__map,
.oliu-contact-grid__details {
  min-width: 0;
}
.oliu-contact-grid__map iframe,
.oliu-contact-grid__map img,
.oliu-contact-grid__map embed,
.oliu-contact-grid__map object {
  max-width: 100%;
}
.oliu-contact-grid__details > * + * {
  margin-top: var(--oliu-space-tight);
}
@media (max-width: 768px) {
  .oliu-contact-grid {
    grid-template-columns: 1fr;
    gap: var(--oliu-space-tight);
  }
}

/* ---- Contact hero / branding (M5.13g) ----
   Scoped to `.oliu-cover-band--contact` only — the base `.oliu-cover-band`
   rules (used by category/brand/product archives and taxonomy pages) are
   untouched. Restores the legacy Contact hero's confirmed background
   image, logo, and 2-column text/image layout
   (cosmeticsweb/cosmetic/pages/Contact/index.js:44-79). Uses the same
   minmax(0, 1fr) + single-768px-breakpoint pattern as the M5.13f homepage
   hero. */
.oliu-cover-band--contact {
  background-image: url('../images/contact/bg-cover-contact.png');
  background-size: cover;
  background-position: center;
  text-align: left;
  align-items: stretch;
}
.oliu-cover-band__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--oliu-space-sub);
  align-items: center;
  width: 100%;
  max-width: 1080px;
  margin: 0 auto;
}
.oliu-cover-band__text { text-align: left; }
.oliu-cover-band__logo { height: 40px; width: auto; margin-bottom: 16px; }
.oliu-cover-band--contact .oliu-cover-band__title { text-align: left; }
.oliu-cover-band--contact .oliu-balloon { justify-content: flex-start; }
/* M5.13g fix: `.oliu-balloon`'s own mobile rule (`right: 50%;
   transform: translateX(50%);`) is written for its fixed-position, floating
   use — it does not know about this in-flow hero usage (inline-overridden
   to position:static). Left un-neutralized here, the transform still
   applies to the static box and was confirmed (via scrollWidth measurement)
   to push the Contact hero's text column ~168px past its container at
   375px, a genuine new horizontal-overflow bug. Scoped to this page's
   hero only — the shared `.oliu-balloon` rule itself is untouched. */
.oliu-cover-band--contact .oliu-balloon { right: auto; transform: none; }
.oliu-cover-band__image-wrap { justify-self: end; }
.oliu-cover-band__image { width: 100%; max-width: 360px; height: auto; }
@media (max-width: 768px) {
  .oliu-cover-band__grid { grid-template-columns: 1fr; }
  .oliu-cover-band__text { text-align: center; }
  .oliu-cover-band--contact .oliu-cover-band__title { text-align: center; }
  .oliu-cover-band--contact .oliu-balloon { justify-content: center; }
  .oliu-cover-band__image-wrap { justify-self: center; margin-top: var(--oliu-space-tight); }
  .oliu-cover-band__image { max-width: 280px; }
}

/* ---- Product detail Details/How-to-order tabs (audit §2.8,
   punch-list #4, visual fidelity pass Batch C) ---- */
.oliu-tabs__list { display: flex; gap: 32px; border-bottom: 1px solid var(--oliu-color-border-mid); }
.oliu-tabs__tab {
  background: none; border: 0; cursor: pointer;
  font-family: var(--oliu-font-heading); font-size: 18px; color: var(--oliu-color-text-muted);
  padding: 12px 0; margin-bottom: -1px;
  border-bottom: 2px solid transparent;
}
.oliu-tabs__tab.is-active { color: var(--oliu-color-primary); border-bottom-color: var(--oliu-color-primary); }
.oliu-tabs__panel { padding-top: var(--oliu-space-tight); }
.oliu-tabs__panel[hidden] { display: none; }

/* ---- Brand detail hero (audit §2.9, visual fidelity pass Batch D) ----
   TEMPLATE bug, confirmed: this hero had no height/object-fit rule at
   all, so `the_post_thumbnail()` rendered at its raw intrinsic pixel
   size — harmless for landscape photos, but a near-square image (e.g.
   OliU's, a screenshot-derived asset per D6_EXECUTION_EVIDENCE.md)
   produced an ~900px-tall band. Legacy (pages/Brands/detail/index.js
   `.image__Cover`) fixes this to a flat 400px with object-fit: cover on
   desktop, and lets height go auto (no crop) below 767px — reproduced
   exactly, values read directly from that file, not invented. */
/* 07 Sep 2026: the desktop `object-fit: cover` rule this replaced was
   faithful to the legacy source's `.image__Cover`, but that legacy
   behaviour assumed a landscape photo. Several brand hero images are
   actually near-square logo files with heavy white/transparent padding
   (already confirmed for mobile below, 05 Sep 2026) — cover-cropping
   those to a flat 400px band zooms into a tiny corner of the logo
   instead of showing it (confirmed live, /brands/hirsuit/). Switched to
   object-fit: contain with a cream backdrop at every width, so the whole
   image always shows regardless of its native shape. */
.oliu-brand-detail__hero {
  height: 400px;
  overflow: hidden;
  background: var(--oliu-color-cream-section);
  display: flex;
  align-items: center;
  justify-content: center;
}
.oliu-brand-detail__hero img {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
@media (max-width: 767px) {
  .oliu-brand-detail__hero { height: 280px; }
}

/* Header (logo/title/count) + Brand Concept side by side on desktop —
   wrapped in their own container so the shared .oliu-container class
   (used sitewide) isn't turned into a grid. */
.oliu-brand-detail__top {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--oliu-space-sub);
  align-items: start;
  margin-top: var(--oliu-space-sub);
}
@media (max-width: 768px) {
  .oliu-brand-detail__top { grid-template-columns: 1fr; gap: var(--oliu-space-tight); }
}

/* ---- Brands archive hero (audit §2.10, visual fidelity pass Batch D) ----
   Legacy (cosmeticsweb/cosmetic/pages/Brands/index.js): a distinct
   colorful hero (`bg-cover-brand.png`, different from the generic
   `.oliu-cover-band` gradient above), a headline + descriptive subtext,
   and a product-photo illustration (`Brand_cover.webp`) in a 2-column
   layout, height 550px. Reuses the existing `.oliu-cover-band__grid`/
   `__text`/`__image-wrap`/`__image` pattern already built for the
   Contact hero (M5.13g) rather than inventing a new layout mechanism. */
.oliu-cover-band--brands {
  background: url('../images/brands/bg-cover-brand.png') center/cover no-repeat;
  min-height: 400px;
  text-align: left;
  align-items: stretch;
}
.oliu-cover-band--brands .oliu-cover-band__title { text-align: left; font-size: 40px; }
.oliu-cover-band--brands .oliu-cover-band__desc { text-align: left; max-width: none; margin-top: 12px; }
@media (max-width: 768px) {
  .oliu-cover-band--brands { min-height: 0; padding: 32px 20px; }
  .oliu-cover-band--brands .oliu-cover-band__title,
  .oliu-cover-band--brands .oliu-cover-band__desc { text-align: center; }
}

/* ---- Brands archive "Sort By" control (audit §2.10, punch-list #12) ----
   Legacy (pages/Brands/index.js `DropDown`): a top-right dropdown with
   Name A-Z / Name Z-A / Popular options, client-side re-sort of the
   already-rendered brand list — no new data/query, so a plain vanilla-JS
   DOM reorder (same "no new dependency" precedent as gallery.js/
   carousel.js) reproduces the behavior. */
.oliu-brands-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: var(--oliu-space-sub);
  margin-bottom: var(--oliu-space-tight);
}
.oliu-brands-sort {
  font-family: var(--oliu-font-heading);
  font-size: 16px;
  padding: 8px 12px;
  border: 1px solid var(--oliu-color-border-mid);
  border-radius: 4px;
  background: var(--oliu-color-white);
  color: var(--oliu-color-text);
}
/* /brands/ archive (desktop) — 6-column logo grid, name/description/
   item-count hidden (leaving only .oliu-card__image), matching the
   homepage's logo-only brand treatment. */
@media (min-width: 769px) {
  [data-oliu-brands-grid] { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  [data-oliu-brands-grid] .oliu-card__body { display: none; }
}

/* ---- Contact LINE QR (M5.13g) ----
   Restores the legacy QR graphic next to the existing, untouched
   "Add friend now" CTA (Contact/index.js:126-144). */
.oliu-contact-line {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}
.oliu-contact-line__qr { width: 120px; height: 121px; object-fit: cover; }
@media (max-width: 768px) {
  .oliu-contact-line { justify-content: center; }
}

/* ---- Contact "Our Shop" gallery (M5.13g) ----
   Restores the confirmed legacy 3-photo gallery + background band
   (Contact/index.js:169-178). Uses the same minmax(0, 1fr) grid pattern
   as `.oliu-grid`/`.oliu-hero__grid` so the gallery can never force
   horizontal overflow at 1280px or 375px. */
.oliu-contact-ourshop {
  background-image: url('../images/contact/bg-cover-contact-ourshop.png');
  background-size: cover;
  background-position: center;
  padding: var(--oliu-space-section) 0;
  margin-top: var(--oliu-space-section);
  /* This is the last section before the footer on /contact/. The footer's
     own sitewide margin-top (--oliu-space-section) would otherwise add a
     second, redundant blank gap after this section's own cream-colored
     padding-bottom — visually a cream/white/cream sandwich. Cancel it out
     here (via ordinary margin collapsing through <main>, which has no
     padding/border of its own) rather than changing the footer's margin
     sitewide. */
  margin-bottom: calc(-1 * var(--oliu-space-section));
}
.oliu-contact-ourshop__title { color: var(--oliu-color-white); text-align: center; }
.oliu-contact-ourshop__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px;
}
.oliu-contact-ourshop__img {
  width: 100%;
  height: 260px;
  object-fit: cover;
  object-position: center;
}
@media (max-width: 768px) {
  .oliu-contact-ourshop__grid { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .oliu-contact-ourshop__img { height: 220px; }
}

/* ---- Testimonials (M5.13i) ----
   Restores the legacy "Our customers are saying…" homepage section
   (pages/index.js:760-784, CardCustomerReviews.js) between Body and
   Blog. Background image + white title/desc text color are both
   confirmed legacy values (bgImgCode 1 → bg-cover-reviews.png;
   `.title__Reviews`/`.title__CustomersDesc` both `color: #ffffff`).
   Card styling mirrors CardCustomerReviews.js's own styled-component
   (white bg, `#f0f3f8` border — already this theme's
   --oliu-color-border-light token, box-shadow) as closely as this
   theme's existing `.oliu-card` base class allows. Grid uses the same
   minmax(0, 1fr) + single-768px-breakpoint pattern already established
   throughout this theme (M5.13d/f/g) rather than legacy's exact MUI
   Grid breakpoints, for consistency with the rest of the site. */
.oliu-testimonials {
  background-image: url('../images/home/bg-cover-reviews.png');
  background-size: cover;
  background-position: center;
  color: var(--oliu-color-white);
}
.oliu-testimonials__title { color: var(--oliu-color-white); }
.oliu-testimonials__desc {
  max-width: 660px;
  margin-top: -8px;
  margin-bottom: var(--oliu-space-sub);
  color: var(--oliu-color-white);
}
.oliu-testimonial-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 24px;
}
.oliu-testimonial-card {
  padding: 32px 32px 28px;
  min-height: 260px;
  display: flex;
  flex-direction: column;
}
.oliu-testimonial-card__label {
  font-weight: 700;
  font-size: 26px;
  color: var(--oliu-color-text);
  margin: 0;
}
.oliu-testimonial-card__name {
  font-size: 18px;
  color: var(--oliu-color-text-muted);
  margin: 2px 0 0;
}
.oliu-testimonial-card__text {
  margin: 18px 0 0;
  font-size: 18px;
  line-height: 1.4;
  color: var(--oliu-color-text);
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
  flex: 1 0 auto;
}
.oliu-star-rating { display: inline-flex; gap: 2px; margin-top: 16px; }
.oliu-star-rating__star { font-size: 22px; line-height: 1; color: var(--oliu-color-border-mid); }
.oliu-star-rating__star--full,
.oliu-star-rating__star--half { color: var(--oliu-color-primary); }
@media (max-width: 768px) {
  .oliu-testimonial-grid { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .oliu-testimonial-card { min-height: 0; }
}

/* ---- Privacy Policy content (readability pass, 06 Sep 2026) ----
   .oliu-privacy-content had no dedicated styling at all — raw editor
   output relying on browser defaults inside the sitewide 1080px
   .oliu-container, which is too wide for comfortable long-form reading
   and left headings/lists/links visually flat. Scoped to this page only
   (not the shared h1/a/strong elements used elsewhere). */
.oliu-privacy-title { margin-top: var(--oliu-space-sub); margin-bottom: var(--oliu-space-sub); }
.oliu-privacy-content {
  max-width: 760px;
  margin: var(--oliu-space-sub) auto 0;
  line-height: 1.7;
}
.oliu-privacy-content h2 {
  font-size: 24px;
  color: var(--oliu-color-primary);
  margin: 40px 0 12px;
}
.oliu-privacy-content h3 {
  font-size: 19px;
  margin: 28px 0 10px;
}
.oliu-privacy-content p { margin: 0 0 16px; }
.oliu-privacy-content ul,
.oliu-privacy-content ol {
  margin: 0 0 16px;
  padding-left: 24px;
}
.oliu-privacy-content li { margin-bottom: 8px; }
.oliu-privacy-content a {
  color: var(--oliu-color-primary);
  text-decoration: underline;
}
.oliu-privacy-content strong { font-family: var(--oliu-font-body-bold); }

/* ---- Breadcrumb (07 Sep 2026) ----
   Had zero CSS at all (plain browser-default text). Legacy source
   (cosmeticsweb/cosmetic/pages/Products/detail/index.js .breadcrumb):
   muted gray text, 24px, body font, 60px top / 16px bottom margin —
   applied here as the confirmed direction the rest of the site's
   design already follows (cite legacy values, not invented ones). */
.oliu-breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  margin: 60px 0 16px;
  font-family: var(--oliu-font-body);
  font-size: 24px;
  color: var(--oliu-color-text-muted);
}
.oliu-breadcrumb a { color: var(--oliu-color-text-muted); }
.oliu-breadcrumb__sep { margin: 0 4px; }
@media (max-width: 768px) {
  .oliu-breadcrumb { margin: 24px 0 16px; font-size: 16px; }
}
