/*
Theme Name: KUO'S Maroc
Template: astra
Version: 1.0.4
*/

/* ===== DESIGN TOKENS ===== */
:root {
  --black:  #0E0E0E;
  --white:  #FFFFFF;
  --bg:     #FAF8F5;
  --rose:   #E8D5C4;
  --gold:   #C9A96E;
  --taupe:  #6E6E6E;
  --line:   #E2E2E0;

  --serif: 'Cormorant Garamond', Georgia, serif;
  --sans:  'DM Sans', system-ui, sans-serif;

  --container: 1280px;
  --section-pad: clamp(60px, 8vw, 120px);
  --grey:   #F5F3EF;
}

/* ===== GLOBAL RESET ===== */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* Caps grid/text content on large & ultrawide monitors so 8vw padding alone
   doesn't stretch lines/images edge-to-edge past a readable width. */
.intro-grid, .cat-grid, .cat-head, .story, .ing-head, .ing-slide-inner,
.footer-grid,
.page-nous .nous-origin-grid, .page-nous .nous-split,
.page-nous .nous-hero-inner {
  max-width: var(--container);
  margin-left: auto;
  margin-right: auto;
}

body {
  background: var(--bg);
  color: var(--black);
  /* Global guard against stray horizontal overflow from any full-bleed/100vw
     element (Windows counts the scrollbar width in 100vw). `clip` — NOT
     `hidden` — because clip doesn't establish a scroll container and therefore
     doesn't break position:sticky (the homepage ingredients section relies on
     it). */
  overflow-x: clip;
  font-family: var(--sans);
  font-weight: 300;
  -webkit-font-smoothing: antialiased;
}

a { text-decoration: none; color: inherit; }

/* Image protection — pairs with the contextmenu/dragstart guards in main.js.
   -webkit-touch-callout kills iOS's long-press "Save Image" sheet specifically. */
img, video {
  -webkit-user-drag: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

/* ===== BRAND STAMP ===== */
.brand-stamp {
  position: fixed; top: 0; left: 0;
  /* was 100vw — on Windows 100vw includes the vertical scrollbar's width, so
     the bar stuck ~17px past the content edge and created a horizontal
     scrollbar. 100% of the fixed containing block excludes the scrollbar. */
  height: 2px; width: 100%;
  background: var(--gold);
  z-index: 1100;
  transform: scaleX(0);
  transform-origin: left center;
  will-change: transform;
  transition: transform 1.8s cubic-bezier(.76,0,.24,1) .3s;
}
.brand-stamp.drawn { transform: scaleX(1); }

/* =====================================================
   HEADER — matches mockup nav, built on Bootstrap navbar
   ===================================================== */
#kuos-header {
  position: fixed !important;
  top: 0 !important; left: 0 !important;
  width: 100% !important;
  z-index: 1050 !important;
  background: rgba(255,255,255,0.92) !important;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid transparent !important;
  box-shadow: none !important;
  padding: 28px 8vw !important;
  transition: padding .4s ease, border-color .4s ease;
}
#kuos-header.scrolled {
  padding: 16px 8vw !important;
  border-color: var(--line) !important;
}
/* Bootstrap's container-fluid inside the header — strip its padding, we pad the header itself */
#kuos-header .container-fluid {
  padding: 0 !important;
  max-width: 100%;
  align-items: center;
}

/* Logo — image wordmark + "Maroc" region label */
#kuos-header .navbar-brand.site-logo {
  display: flex !important;
  align-items: center !important;
  gap: 12px;
  padding: 0 !important;
  margin: 0 !important;
  line-height: 1 !important;
}
#kuos-header .site-logo-img {
  height: 32px;
  width: auto;
  display: block;
  transition: height .4s ease;
}
#kuos-header.scrolled .site-logo-img { height: 26px; }

/* Nav links row */
#kuos-header .navbar-nav {
  align-items: center;
  gap: 40px;
}
#kuos-header .nav-link {
  font-family: var(--sans) !important;
  font-size: 12px !important;
  font-weight: 300 !important;
  letter-spacing: 0.18em !important;
  text-transform: uppercase !important;
  color: var(--black) !important;
  padding: 0 !important;
  margin: 0 !important;
  position: relative;
  line-height: 1.4;
}
#kuos-header .nav-link::after {
  content: '';
  position: absolute;
  left: 0; bottom: -6px;
  width: 0; height: 1px;
  background: currentColor;
  transition: width .35s ease;
}
#kuos-header .nav-link:hover::after,
#kuos-header .nav-link.active::after { width: 100%; background: var(--black); }

/* Kill Bootstrap's dropdown caret */
#kuos-header .dropdown-toggle::after { display: none !important; }

/* Dropdown — opens on HOVER on desktop */
@media (min-width: 1200px) {
  #kuos-header .nav-item.dropdown:hover .dropdown-menu {
    display: block;
    animation: dropFade .25s ease;
  }
}
@keyframes dropFade {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}
#kuos-header .dropdown-menu {
  border: 1px solid var(--line) !important;
  border-radius: 0 !important;
  box-shadow: 0 8px 24px rgba(0,0,0,0.08) !important;
  background: rgba(255,255,255,0.97) !important;
  backdrop-filter: blur(8px);
  padding: 12px 0 !important;
  min-width: 220px !important;
  margin-top: 0 !important;
}
#kuos-header .dropdown-item {
  font-family: var(--sans) !important;
  font-size: 11px !important;
  font-weight: 400 !important;
  letter-spacing: 0.14em !important;
  text-transform: uppercase !important;
  color: var(--taupe) !important;
  padding: 10px 24px !important;
  transition: color .2s ease, padding-left .2s ease;
}
#kuos-header .dropdown-item:hover {
  background: transparent !important;
  color: var(--gold) !important;
  padding-left: 30px !important;
}
/* Bootstrap paints .dropdown-item.active and :focus with its own blue
   (--bs-dropdown-link-active-bg). Once a gamme page is open, is_page() puts
   .active on that item, so re-opening Services showed a solid blue bar. Only
   :hover was overridden here, which is why it only surfaced after navigating.
   The current page is marked with gold text + a hairline rule instead. */
#kuos-header .dropdown-item:focus,
#kuos-header .dropdown-item:active,
#kuos-header .dropdown-item.active,
#kuos-header .dropdown-item:focus-visible {
  background: transparent !important;
  color: var(--gold) !important;
}
#kuos-header .dropdown-item.active {
  font-weight: 500 !important;
  box-shadow: inset 2px 0 0 var(--gold);
}
#kuos-header .dropdown-item:focus-visible { outline: 1px solid var(--gold); outline-offset: -3px; }

/* Cosmétique group — non-clickable label + two indented sub-items (Visage /
   Corps). Not a flyout submenu: with only two children a static indented
   list is simpler and works identically on desktop hover and mobile tap. */
#kuos-header .dropdown-item--group {
  display: block;
  cursor: default;
  color: var(--black) !important;
  font-weight: 500 !important;
}
#kuos-header .dropdown-item--group:hover { padding: 10px 24px !important; }
#kuos-header .dropdown-submenu-list { list-style: none; margin: 0; padding: 2px 0 8px; }
#kuos-header .dropdown-item--sub {
  padding: 8px 24px 8px 38px !important;
  font-size: 10.5px !important;
}
#kuos-header .dropdown-item--sub:hover { padding-left: 44px !important; }

/* Language switcher spacing */
#kuos-header .nav-item.ms-xl-3 { margin-left: 24px; }

/* Language switcher — FR / EN text toggle, hairline separator between items,
   active = solid black + medium weight, inactive = taupe → gold on hover.
   Gold hover distinguishes it from nav links (which hover to a black underline). */
.lang-switch { display: flex; align-items: center; gap: 14px; }
.lang-switch-link {
  position: relative;
  font-family: var(--sans);
  font-size: 12px; font-weight: 400;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--taupe);
  transition: color .3s ease;
}
.lang-switch-link.is-active { color: var(--black); font-weight: 500; }
.lang-switch-link:not(.is-active):hover { color: var(--gold); }
.lang-switch-link:focus-visible {
  outline: 1px solid var(--gold); outline-offset: 4px; color: var(--black);
}
/* hairline divider before every item except the first (scales to N languages) */
.lang-switch-link + .lang-switch-link::before {
  content: ''; position: absolute; left: -7px; top: 50%; transform: translateY(-50%);
  width: 1px; height: 11px; background: var(--line);
}

/* Social links — same thin-line circle-button language as .cat-card-arrow / .news-popup-close */
.nav-social { display: flex; align-items: center; gap: 20px; }
#kuos-header .nav-social.ms-xl-3 { margin-left: auto; }
.nav-social-link {
  width: 38px; height: 38px; border-radius: 50%;
  border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
  color: var(--black);
  transition: background .35s cubic-bezier(.16,1,.3,1), border-color .35s cubic-bezier(.16,1,.3,1),
              color .35s cubic-bezier(.16,1,.3,1), transform .35s cubic-bezier(.16,1,.3,1);
}
.nav-social-link:hover {
  background: var(--gold); border-color: var(--gold); color: var(--white);
  transform: translateY(-3px);
}

/* Hamburger — hidden on desktop, custom lines on mobile */
#kuos-header .navbar-toggler {
  border: none !important;
  background: none !important;
  box-shadow: none !important;
  padding: 4px !important;
  flex-direction: column;
  gap: 5px;
  display: none;
}
#kuos-header .navbar-toggler:focus { box-shadow: none !important; }
#kuos-header .navbar-toggler .navbar-toggler-icon { display: none !important; }
#kuos-header .navbar-toggler span {
  display: block;
  width: 22px; height: 1.5px;
  background: var(--black);
  transition: transform .3s ease, opacity .3s ease;
}
#kuos-header .navbar-toggler[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
#kuos-header .navbar-toggler[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
#kuos-header .navbar-toggler[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* ===== MOBILE HEADER (<1200px) ===== */
@media (max-width: 1199.98px) {
  #kuos-header { padding: 20px 6vw !important; }
  #kuos-header.scrolled { padding: 14px 6vw !important; }
  #kuos-header .navbar-toggler { display: flex; }

  #kuosNavMenu {
    background: var(--white);
    padding: 20px 0 8px;
    border-top: 1px solid var(--line);
    margin-top: 16px;
  }
  #kuos-header .navbar-nav { gap: 0; align-items: flex-start; }
  #kuos-header .nav-link { padding: 12px 0 !important; }
  #kuos-header .nav-link::after { display: none; }
  #kuos-header .dropdown-menu {
    border: none !important;
    box-shadow: none !important;
    background: transparent !important;
    padding: 0 0 0 16px !important;
  }
  #kuos-header .nav-item.ms-xl-3 { margin-left: 0; margin-top: 8px; }
  #kuos-header .nav-social.ms-xl-3 { margin-left: 0; margin-top: 16px; }

  /* Language switcher — larger tap targets, set off with a hairline above,
     sits just under the nav links before the social row */
  #kuos-header .nav-lang.ms-xl-3 {
    margin-top: 8px; padding-top: 16px;
    border-top: 1px solid var(--line);
  }
  .lang-switch { gap: 20px; }
  .lang-switch-link { font-size: 14px; padding: 8px 0; }
  .lang-switch-link + .lang-switch-link::before { left: -10px; height: 14px; }
}

/* Kill Astra's own header */
#ast-fixed-header,
.ast-primary-header-bar,
.main-header-bar,
.site-header-primary-section { display: none !important; }

/* =====================================================
   HERO / BRAND FILM
   ===================================================== */
#kuos-main { padding-top: 0; }

/* [A11Y-HERO-SCRIM] The hero text sits on an autoplaying video, so its legibility
   used to depend entirely on which frame happened to be on screen: the old
   0.15→0.45 ramp measured 1.06:1 against the video's own light frames (H1 needs
   3:1, the eyebrow 4.5:1). The ramp below is weighted to the lower third where
   the caption actually sits — at the eyebrow it resolves to ~5.5:1 and at the H1
   to ~6.3:1 even against a near-white frame, while staying light enough up top
   that the footage still reads. Do not flatten this back to a linear two-stop
   gradient; the whole point is that the darkness is concentrated where the text is. */
.brand-film-scrim {
  background: linear-gradient(180deg,
    rgba(0,0,0,0.10)  0%,
    rgba(0,0,0,0.20) 45%,
    rgba(0,0,0,0.55) 72%,
    rgba(0,0,0,0.78) 100%);
  z-index: 1;
}
/* Belt-and-braces for the frames the gradient alone can't cover (a blown-out
   highlight drifting through the caption zone). Cheap, and invisible on dark frames. */
.brand-film-caption .eyebrow,
.brand-film-title {
  text-shadow: 0 1px 3px rgba(0,0,0,.45), 0 2px 24px rgba(0,0,0,.35);
}
/* Was inline rgba(255,255,255,0.7) in front-page.php — 11px at 70% opacity could
   not reach 4.5:1 on any light frame no matter how strong the scrim. Full white. */
.brand-film-caption .eyebrow { color: #fff; }
.brand-film-caption h1 {
  font-family: var(--serif); font-style: italic; font-weight: 300;
  font-size: clamp(22px, 2.8vw, 34px); line-height: 1.3; margin-top: 14px;
}

/* Word-stagger load reveal: each word sits in an overflow-hidden mask so it
   rises into place on its own instead of the whole line fading as one block.
   JS adds .is-in on load to start the animation (keeps the very first paint
   static for LCP — see main.js). Weight settle is applied via inline
   style.fontWeight (JS, scroll-tied) on the true variable Cormorant range. */
.brand-film-title .word-mask { display: inline-block; overflow: hidden; vertical-align: top; }
.brand-film-title .word {
  display: inline-block; transform: translateY(115%); opacity: 0;
  transition: font-weight .15s ease-out;
}
.brand-film-title.is-in .word {
  animation: wordRise .9s cubic-bezier(.16,1,.3,1) forwards;
  animation-delay: calc(var(--i) * 0.08s + 0.15s);
}
@keyframes wordRise { to { transform: translateY(0); opacity: 1; } }

/* Near-full-viewport hero. The source is a true 16:9 master, so at this height
   cover crops only ~40px off the top/bottom on a 1080p screen — the framing
   stays intact. svh (not vh) so the mobile URL bar can't push it taller than
   the visible viewport. */
.brand-film { height: 92vh; height: 92svh; min-height: 620px; max-height: 1100px; }

@media (max-width: 767.98px) {
  .brand-film { height: 150vw; min-height: 460px; max-height: 760px; }
}
@media (min-width: 768px) and (max-width: 1199.98px) {
  .brand-film { height: 88vw; min-height: 560px; max-height: 880px; }
}

/* =====================================================
   MARQUEE
   ===================================================== */
.marquee-track {
  white-space: nowrap;
  animation: marquee 32s linear infinite;
  width: max-content;
}
.marquee-track span {
  font-family: var(--sans); font-weight: 400; letter-spacing: 0.06em; text-transform: uppercase;
  font-size: 15px; padding: 0 36px; color: var(--black);
  display: inline-flex; align-items: center; gap: 36px;
}
.marquee-track span::after {
  content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--gold); display: inline-block;
}
.marquee-track span.centered { transform: scale(1.18); color: var(--gold); }
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* Pause/play control — same 32px thin-line circle-button language as
   .nav-social-link, so both marquees (band ticker + press logos) have an
   on-page way to stop motion for keyboard/touch users, not just mouseleave.
   Only one icon shows at a time via .is-paused toggling which SVG is visible. */
.marquee-pause-btn {
  position: absolute; z-index: 3;
  top: 50%; right: 8vw; transform: translateY(-50%);
  width: 32px; height: 32px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--white);
  display: flex; align-items: center; justify-content: center;
  color: var(--black); cursor: pointer;
  transition: background .3s ease, border-color .3s ease, color .3s ease;
}
.marquee-pause-btn:hover, .marquee-pause-btn:focus-visible {
  background: var(--gold); border-color: var(--gold); color: var(--white);
}
.marquee-pause-btn .icon-play { display: none; }
.marquee-pause-btn.is-paused .icon-pause { display: none; }
.marquee-pause-btn.is-paused .icon-play { display: block; }
.press-pause-btn { top: 22px; right: 24px; transform: none; }
@media (max-width: 560px) {
  .marquee-pause-btn { right: 4vw; }
}

/* =====================================================
   INTRO / BRAND STATEMENT
   ===================================================== */
.intro-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 80px; align-items: center;
}
@media (max-width: 900px) { .intro-grid { grid-template-columns: 1fr; gap: 50px; } }
/* One-sided bleed: on very wide viewports there's real unused space between
   the capped 1280px container and the actual edge of the screen — let the
   text column alone break into it while the collage stays put, an
   intentional asymmetric tension rather than two perfectly mirrored columns.
   min-width guard keeps this off anything without genuine spare room. */
@media (min-width: 1500px) { .intro-content { margin-left: -70px; } }

.intro-text {
  font-family: var(--sans); font-weight: 300;
  font-size: clamp(24px, 2.6vw, 36px);
  line-height: 1.45;
  color: var(--black);
  text-align: justify;
  hyphens: auto;
  -webkit-hyphens: auto;
}
.intro-text em { font-family: var(--serif); font-style: italic; color: var(--black); }
.intro-meta { margin-top: 50px; }
.intro-meta-num { font-family: var(--serif); font-size: 42px; font-weight: 300; color: var(--black); font-variant-numeric: tabular-nums; }
.intro-meta-label { font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--taupe); margin-top: 8px; }

/* Circular photo collage — a scattered cluster of framed portraits instead of one
   single crop, like a curated moodboard rather than a stock headshot. */
.intro-collage { position: relative; aspect-ratio: 4/5; }
.intro-collage-circle {
  position: absolute; aspect-ratio: 1; border-radius: 50%; overflow: hidden;
  background: var(--bg);
  border: 6px solid var(--white);
  box-shadow: 0 20px 50px -18px rgba(0,0,0,0.25);
  transition: opacity .7s ease, transform .7s ease;
}
.intro-collage-circle img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transition: transform .6s cubic-bezier(.16,1,.3,1);
}
.intro-collage-circle:hover img { transform: scale(1.08); }

.intro-collage-circle--1 { width: 50%; top: 0;   left: 2%;  }
.intro-collage-circle--2 { width: 36%; top: 44%; left: 56%; transition-delay: .1s; }
.intro-collage-circle--3 { width: 28%; top: 64%; left: 8%;  transition-delay: .2s; }
.intro-collage-circle--4 { width: 24%; top: 2%;  left: 68%; transition-delay: .3s; }
.intro-collage-circle--5 { width: 26%; top: 78%; left: 62%; transition-delay: .4s; }

/* Scroll-reveal base state (JS adds .in on intersect) */
.reveal { opacity: 0; transform: translateY(20px); transition: opacity .7s ease, transform .7s ease; }
.reveal.in { opacity: 1; transform: translateY(0); }

/* Links to pages not built yet: href="#", rendered inert — clicking does
   nothing and stays in place (no navigation), removed from tab order (paired
   with aria-disabled + tabindex=-1). Kept visually identical to live links —
   no graying — per request. */
a.is-soon { pointer-events: none; cursor: default; }

/* Branded text selection — a considered micro-detail (top-design Pillar 7);
   soft gold wash that stays legible on both the light page and dark sections. */
::selection { background: rgba(201,169,110,0.30); color: var(--black); }
::-moz-selection { background: rgba(201,169,110,0.30); color: var(--black); }

/* =====================================================
   GLOBAL UTILITY CLASSES
   ===================================================== */
.eyebrow {
  font-size: 11px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--taupe);
  font-weight: 500;
  display: inline-block;
  margin-bottom: 18px;
}

.section-pad { padding: 140px 8vw; }
@media (max-width: 768px) {
  .section-pad { padding: 90px 6vw; }
}

/* =====================================================
   CATEGORIES GRID
   ===================================================== */
.categories { background: var(--white); padding-top: 70px; padding-bottom: 70px; }
@media (max-width: 768px) { .categories { padding-top: 45px; padding-bottom: 45px; } }
.intro { padding-bottom: 70px; }
@media (max-width: 768px) { .intro { padding-bottom: 45px; } }

.cat-head { display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: 60px; flex-wrap: wrap; gap: 24px; }
.cat-head h2 { font-family: var(--sans); font-weight: 300; font-size: clamp(32px, 4vw, 56px); letter-spacing: -0.01em; color: var(--black); }
.cat-head h2 em { font-family: var(--serif); font-style: italic; color: var(--black); }

.cat-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
@media (max-width: 900px) { .cat-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .cat-grid { grid-template-columns: 1fr; } }

.cat-card { position: relative; background: var(--white); overflow: hidden; cursor: pointer; text-decoration: none; display: block; }
.cat-card-img { position: relative; aspect-ratio: 3/4; overflow: hidden; background: var(--bg); }
.cat-card-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: transform 1.1s cubic-bezier(.16,1,.3,1); }
.cat-card:hover .cat-card-img img { transform: scale(1.15); }

.cat-card-scrim {
  position: absolute; inset: 0; z-index: 2;
  background: rgba(10,10,10,0.78);
  display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center;
  opacity: 0; transition: opacity .55s ease;
}
.cat-card:hover .cat-card-scrim, .cat-card:focus-visible .cat-card-scrim { opacity: 1; }

.cat-card-scrim-name {
  font-family: var(--serif); font-style: italic; font-weight: 300; color: #fff;
  font-size: clamp(22px, 2.4vw, 30px);
  transform: translateY(14px); transition: transform .55s cubic-bezier(.16,1,.3,1);
}
.cat-card:hover .cat-card-scrim-name, .cat-card:focus-visible .cat-card-scrim-name { transform: translateY(0); }

.cat-card-scrim-meta {
  margin-top: 12px; font-family: var(--sans); font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase;
  color: rgba(255,255,255,0.65);
  transform: translateY(14px); transition: transform .55s cubic-bezier(.16,1,.3,1) .05s;
}
.cat-card:hover .cat-card-scrim-meta, .cat-card:focus-visible .cat-card-scrim-meta { transform: translateY(0); }

.cat-card-label { padding: 20px 4px 8px; display: flex; justify-content: space-between; align-items: center; }
.cat-card-label h3 { font-family: var(--sans); font-weight: 400; font-size: 14px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--black); transition: color .3s ease; }
.cat-card:hover .cat-card-label h3, .cat-card:focus-visible .cat-card-label h3 { color: var(--gold); }
.cat-card-num { font-size: 11px; letter-spacing: 0.1em; color: var(--taupe); }

.cat-card-arrow {
  position: absolute; top: 18px; right: 18px;
  width: 36px; height: 36px; border-radius: 50%;
  background: rgba(255,255,255,0.92);
  display: flex; align-items: center; justify-content: center;
  color: var(--black); font-size: 14px;
  transform: translateY(-8px); opacity: 0;
  transition: transform .4s ease, opacity .4s ease;
}
.cat-card-arrow span { display: block; transition: transform .25s ease-out; }
.cat-card:hover .cat-card-arrow, .cat-card:focus-visible .cat-card-arrow { transform: translateY(0); opacity: 1; }
.cat-card:focus-visible { outline: 2px solid var(--gold); outline-offset: -2px; }

/* Cosmétique card — Visage/Corps collage, each half its own link, so the
   card itself picks the range instead of duplicating "Cosmétique X" cards. */
.cat-card--split { cursor: default; }
.cat-card-split { display: flex; }
.cat-card-split-half {
  position: relative; width: 50%; height: 100%; overflow: hidden;
  display: block; text-decoration: none;
}
.cat-card-split-half:nth-child(2)::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 1px;
  background: rgba(255,255,255,0.5); z-index: 2;
}
.cat-card-split-half img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.1s cubic-bezier(.16,1,.3,1);
}
.cat-card-split-half:hover img, .cat-card-split-half:focus-visible img { transform: scale(1.15); }
.cat-card-split-half::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(10,10,10,0.5), rgba(10,10,10,0) 45%);
  pointer-events: none;
}
.cat-card-split-tag {
  position: absolute; left: 0; right: 0; bottom: 14px; text-align: center;
  font-family: var(--sans); font-size: 11px; font-weight: 400;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--white);
  z-index: 1; transition: color .3s ease;
}
.cat-card-split-half:hover .cat-card-split-tag, .cat-card-split-half:focus-visible .cat-card-split-tag { color: var(--gold); }
.cat-card-split-half:focus-visible { outline: 2px solid var(--gold); outline-offset: -3px; z-index: 3; }

/* =====================================================
   INGREDIENTS — PINNED SCROLL SECTION
   ===================================================== */
.ingredients-pin {
  position: relative;
  background: var(--white);
  color: var(--black);
  height: 500vh;
}
.ingredients-sticky {
  position: sticky; top: 0; height: 100vh; overflow: hidden;
  display: flex; flex-direction: column; justify-content: center;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.ing-head {
  position: absolute; top: 70px; left: 8vw; right: 8vw;
  display: flex; justify-content: space-between; align-items: flex-start;
  z-index: 5;
}
.ing-head h2 { font-family: var(--sans); font-weight: 300; font-size: clamp(24px, 3vw, 36px); color: var(--black); }
.ing-head h2 em { font-family: var(--serif); font-style: italic; color: var(--black); }
.ing-progress { display: flex; gap: 2px; }
/* Dots are real <button>s now (jump-to-slide nav, not just a read-only
   progress indicator) — visual dot stays 6px via ::after, but the clickable
   box is a full 20px so the hit target doesn't stay needle-thin. */
.ing-progress-dot {
  position: relative; width: 20px; height: 20px; padding: 0;
  border: none; background: none; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.ing-progress-dot::after {
  content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--line);
  transition: background .4s ease, transform .4s ease;
}
.ing-progress-dot:hover::after, .ing-progress-dot:focus-visible::after { background: var(--taupe); }
.ing-progress-dot.active::after { background: var(--gold); transform: scale(1.4); }
.ing-progress-dot:focus-visible { outline: 1px solid var(--gold); outline-offset: 2px; border-radius: 50%; }

.ing-slide {
  position: absolute; inset: 0;
  display: flex; align-items: center;
  opacity: 0; transition: opacity .9s ease;
  pointer-events: none;
}
.ing-slide.active { opacity: 1; pointer-events: auto; }
.ing-slide-inner {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0;
  width: 100%; height: 100%; align-items: center;
}
@media (max-width: 900px) { .ing-slide-inner { grid-template-columns: 1fr; } }
/* Grid/flex items default to min-width:auto, which floors their size at their
   content's intrinsic (unwrapped) width instead of the track's actual size —
   on mobile this let "Acide Hyaluronique" push .ing-visual/.ing-text (grid
   items) and .ing-slide (flex item of .ingredients-sticky) wider than the
   viewport instead of wrapping, clipping the card's right edge off-screen. */
.ing-slide, .ing-visual, .ing-text { min-width: 0; }

.ing-visual {
  position: relative; height: 100%;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; background: var(--bg);
}
.ing-visual-blob {
  width: 52%; aspect-ratio: 1; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 30px 80px -20px rgba(0,0,0,0.15);
  transition: transform .4s cubic-bezier(.16,1,.3,1);
  will-change: transform;
}
/* Real product photo — floats inside the circle, doesn't fill it */
.ing-visual-blob--product img {
  width: 82%; height: 82%; object-fit: contain;
  filter: drop-shadow(0 20px 30px rgba(0,0,0,0.18));
}
/* Padding is CAPPED, not plain 8vw. The grid column is capped at
   --container/2 = 640px, but 8vw keeps growing with the viewport — at 1920px
   it took 305px (48% of the column), leaving .ing-name a 285px content box
   while "Hyaluronique" measures 331px. background-clip:text can only paint a
   glyph where the background box reaches, so the 46px of overflow rendered
   transparent (the "ue cut off" bug — visible only when NOT selected, since
   selection bypasses the mask and force-fills). Same cause as the earlier
   descender bug, on the horizontal axis. 96px = 8vw at 1200px, so every
   viewport at or below 1200 is byte-identical to before; only wide screens
   change, and there the column was already capped anyway. */
.ing-text { padding: 0 clamp(0px, 8vw, 96px); }
@media (max-width: 900px) { .ing-text { padding: 40px 8vw 0; } }
.ing-num { font-family: var(--sans); font-size: 12px; color: #9A7A4A; letter-spacing: 0.2em; margin-bottom: 20px; display: block; text-transform: uppercase; }
/* Soft backing card behind the headline — wraps .ing-name in the markup
   (.ing-name-card) rather than using a ::before on .ing-name itself. A
   pseudo-element CANNOT sit behind its own parent's background — an
   element's own background is always the bottom-most paint layer of its box,
   below even a negative z-index child — and .ing-name's "text" here IS its
   background (via background-clip:text), so a ::before card always ended up
   painted on top of it, covering the words entirely. A real wrapper element
   sidesteps the problem: the card is a different element's background, and
   .ing-name's masked text paints on top of it normally, as any element's
   content does over a sibling/ancestor's background. */
.ing-name-card {
  display: inline-block; max-width: 100%; box-sizing: border-box; margin-bottom: 24px;
  /* Generous bottom padding is load-bearing, not decorative: line-height:1 on
     .ing-name is tighter than Cormorant/DM Sans's own glyph metrics, so
     descenders (g, y, q) already extend past the text's own line box by
     design — with only 8px of clearance they were poking straight through
     the card's bottom edge and getting visually truncated (the "g" in
     Collagène, the "y" tail in Hyaluronique reading as a "v"). */
  padding: 14px 24px 28px; border-radius: 14px;
  /* Pure #fff read as a glaring, eye-catching blank patch wherever a word
     SPACE falls (a space has no glyph, so background-clip:text can never
     paint it — the card's flat color always shows through there, e.g. the
     gap between "Blue" and "Spirulina"). A soft warm off-white keeps the
     card clearly distinct from the page (border + shadow do that work) while
     making that unavoidable gap read as a quiet pause instead of a hole. */
  background: #fdfbf7; border: 1px solid rgba(10,10,10,0.06);
  box-shadow: 0 18px 40px -16px rgba(0,0,0,0.18), 0 2px 10px rgba(0,0,0,0.06);
}
.ing-name {
  font-family: var(--sans); font-weight: 300; font-size: clamp(36px, 5vw, 68px);
  /* line-height was 1, which made the element's background box exactly
     font-size tall — but Cormorant italic's g/y descenders (Collagène,
     Hyaluronique) hang BELOW that box, and since background-clip:text can
     only paint a glyph where the background actually reaches, the descender
     fell outside the gradient and rendered unpainted/transparent — the
     "g/y cut off" bug (visible only when NOT selected; selecting text
     bypasses background-clip and force-fills the glyph, which is why it
     looked fine highlighted). Raising line-height and adding padding-bottom
     extends the background box below the baseline so descenders are covered.
     Verified at production size against the real 2-col layout. */
  line-height: 1.15; padding-bottom: 0.22em; color: var(--black);
}
/* No color set here on purpose — inherits from .ing-name, which is exactly
   what lets the text-mask rules below paint through both the roman and
   italic words as one continuous image instead of two separately-cropped
   ones (confirmed: background-clip:text on the parent alone is sufficient,
   an em with its own color override would block the image from showing). */
.ing-name em { font-family: var(--serif); font-style: italic; }
.ing-desc { font-size: 15px; line-height: 1.8; color: var(--taupe); max-width: 420px; font-weight: 300; }

/* Darkening/tinting each fill below is done via a second background LAYER (a
   translucent dark tint stacked on top of the photo, both clipped to text) —
   NOT via `filter` on .ing-name, which would composite the whole element
   (including anything painted behind it) as one bitmap. */

/* Ingredient name text-mask — each slide's headline is filled with that
   ingredient's own product/texture photo instead of solid black, so the
   image reinforces the word instead of just sitting beside it (ties into
   the project's existing rule that ingredient imagery must read as
   unmistakably what it claims to be). Falls back to solid var(--black),
   set above, on any browser without background-clip:text support. */
@supports (background-clip: text) or (-webkit-background-clip: text) {
  /* Gradient darkened at BOTH ends (was #bdeee0 -> #2f8267; the #bdeee0 end
     was a near-white pale mint). That pale end filled the word "Blue" with a
     color barely distinguishable from a light card — light-on-light, which
     read as a bright washed-out patch ("the white that hurts the eyes"),
     made worse when the card itself was tinted pale mint. Same root cause and
     same fix as the three photo slides below: keep the fill dark enough to
     stay legible everywhere, so the inter-word gap reads as ordinary spacing
     between two dark words rather than a bright hole. */
  .ing-slide[data-i="0"] .ing-name {
    background-image: radial-gradient(circle at 30% 25%, #2f8267, #123a2e 90%);
    -webkit-background-clip: text; background-clip: text; color: transparent;
  }
  /* Slides 1-3 converted from photo-in-text to per-ingredient dark gradients,
     matching slide 0 (Blue Spirulina) which is the only one that always
     worked. Photo-in-text was the root cause of this entire bug saga: a photo
     has bright regions somewhere, and wherever one lands on a thin stroke that
     stroke washes out to near-invisible against the light card ("g cut off",
     "y looks like a v"). Any tint dark enough to prevent that (0.85) buries
     the photo so completely it reads as plain black — pointless as imagery.
     A controlled dark gradient has NO bright regions to wash out letters,
     stays fully legible, AND keeps a real ingredient color instead of black.
     Colors echo each slide's visual-blob palette: amber (Vitamine C), rose
     (Collagène), blue (Hyaluronique). Same light-to-dark radial shape as
     slide 0, both stops dark enough to read on the cream card. */
  .ing-slide[data-i="1"] .ing-name {
    background-image: radial-gradient(circle at 30% 25%, #b57d1a, #5c3d0a 90%);
    -webkit-background-clip: text; background-clip: text; color: transparent;
  }
  .ing-slide[data-i="2"] .ing-name {
    background-image: radial-gradient(circle at 30% 25%, #b13c54, #5c1523 90%);
    -webkit-background-clip: text; background-clip: text; color: transparent;
  }
  .ing-slide[data-i="3"] .ing-name {
    background-image: radial-gradient(circle at 30% 25%, #2f6f96, #123a5e 90%);
    -webkit-background-clip: text; background-clip: text; color: transparent;
  }
}
/* (Removed the earlier per-slide pale-mint card override for slide 0 — with
   the gradient now dark at both ends, the standard cream card gives the same
   strong dark-text-on-light-card contrast as the other three slides, and a
   light gap between two dark words reads as normal spacing, not a bright
   patch. Tinting the card was the weaker of the two possible fixes and, with
   pale text, actively hurt legibility.) */

/* =====================================================
   STORY / BRAND HISTORY + TRUST BARS
   ===================================================== */
.story {
  background: var(--white);
  display: grid; grid-template-columns: 1fr 1fr; gap: 80px; align-items: center;
}
@media (max-width: 900px) { .story { grid-template-columns: 1fr; gap: 50px; } }

/* Photo variant — kept for when client delivers real assets */
.story-img {
  position: relative; aspect-ratio: 4/5; overflow: hidden; background: var(--bg);
  clip-path: inset(0 100% 0 0);
  transition: clip-path 1.4s cubic-bezier(.76,0,.24,1) .15s;
}
.story-img.in { clip-path: inset(0 0 0 0); }
.story-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

.story-text h2 {
  font-family: var(--sans); font-weight: 300;
  font-size: clamp(30px, 3.6vw, 50px); line-height: 1.15; margin-bottom: 28px;
}
.story-text h2 em { font-family: var(--serif); font-style: italic; color: var(--black); }
.story-text p { font-size: 15px; line-height: 1.85; color: var(--taupe); max-width: 460px; margin-bottom: 36px; }

.story-stats {
  display: flex; gap: 48px;
  border-top: 1px solid var(--line); padding-top: 32px; margin-bottom: 36px;
}
.story-stat-num { font-family: var(--serif); font-size: 34px; color: var(--black); font-variant-numeric: tabular-nums; }
.story-stat-label { font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--taupe); margin-top: 6px; }

.trust-bars { max-width: 420px; display: flex; flex-direction: column; gap: 18px; }
.trust-bar-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 8px; }
.trust-bar-head span { font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--black); }
.trust-bar-pct { font-family: var(--serif); font-size: 15px; color: var(--gold); }
.trust-bar-track { height: 1px; background: var(--line); position: relative; }
.trust-bar-fill {
  position: absolute; left: 0; top: 0; height: 100%;
  background: var(--gold); width: 0;
  transition: width 1.2s cubic-bezier(.16,1,.3,1);
}

/* Particle canvas — story left column */
.story-canvas-wrap { order: -1; }
@media (min-width: 901px) {
  .story-canvas-wrap { order: 0; }
}

/* Press marquee */
.press{background:var(--grey);}
.press-label{font-size:15px;letter-spacing:0.25em;text-transform:uppercase;color:var(--taupe);margin-bottom:24px;}
.press-marquee{overflow:hidden;-webkit-mask-image:linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);mask-image:linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);}
.press-track{display:flex;align-items:center;width:max-content;animation:pressMarquee 26s linear infinite;}
.press-track img{display:inline-block;height:130px;width:auto;padding:0 80px;filter:grayscale(1);opacity:0.45;transition:opacity .4s ease, filter .4s ease, transform .5s cubic-bezier(.16,1,.3,1);}
.press-track img:hover{opacity:1;filter:grayscale(0);transform:translateY(-6px) scale(1.05);}
@keyframes pressMarquee{from{transform:translateX(0);}to{transform:translateX(-50%);}}

/* =====================================================
   NEWSLETTER
   ===================================================== */
/* Newsletter vertical padding halved from section-pad's 140px so the gaps
   above (from the press marquee) and below (to the footer) are tighter. */
.newsletter { background: var(--grey); text-align: center; padding-top: 70px; padding-bottom: 70px; }
@media (max-width: 768px) { .newsletter { padding-top: 45px; padding-bottom: 45px; } }
.newsletter h2 {
  font-family: var(--sans); font-weight: 300;
  font-size: clamp(30px, 4vw, 54px); margin-bottom: 20px; color: var(--black);
}
.newsletter h2 em { font-family: var(--serif); font-style: italic; color: var(--black); }
.newsletter > p { color: var(--taupe); font-size: 15px; margin-bottom: 44px; }

.news-form {
  position: relative;
  display: flex; max-width: 440px; margin: 0 auto;
  border-bottom: 1px solid var(--black);
  padding-bottom: 14px;
}
.news-form input {
  flex: 1; background: transparent; border: none; color: var(--black);
  font-family: var(--sans); font-size: 14px; letter-spacing: 0.05em; outline: none;
}
.news-form input::placeholder { color: var(--taupe); }
.news-form button {
  display: flex; align-items: center; gap: 8px;
  background: none; border: none; color: var(--gold);
  font-family: var(--sans); font-size: 11px; letter-spacing: 0.2em; text-transform: uppercase;
  cursor: pointer;
}
.news-form button svg { transition: transform .3s cubic-bezier(.16,1,.3,1); }
.news-form button:hover svg { transform: translateX(4px); }

.news-form::after {
  content: ''; position: absolute; left: 50%; right: 50%; bottom: -1px; height: 1px; background: var(--gold);
  transition: left .5s cubic-bezier(.16,1,.3,1), right .5s cubic-bezier(.16,1,.3,1);
}
.news-form.focused::after { left: 0; right: 0; }

.news-form-msg {
  margin-top: 20px; font-size: 13px; color: var(--gold); min-height: 1.4em;
  opacity: 0; transition: opacity .5s ease;
}
.news-form-msg.show { opacity: 1; }
.news-form-msg.error, .news-popup-msg.error { color: #A85C4A; }

/* =====================================================
   FOOTER
   ===================================================== */
.site-footer {
  position: relative;
  background: var(--white);
  color: var(--taupe);
  padding: 70px 8vw 30px;
  font-size: 13px;
}
/* Inset hairline (matches the 8vw content padding, rather than a full-bleed edge-to-edge rule)
   plus a small centered gold accent — same thin-gold-rule motif as the story-canvas caption
   and the trust bars, used here to mark the page/footer boundary. */
.site-footer::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--line) 15%, var(--line) 85%, transparent);
}
.site-footer::after {
  content: ''; position: absolute; top: -1px; left: 50%; transform: translateX(-50%);
  width: 48px; height: 2px; background: var(--gold);
}
.footer-grid {
  display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: 40px;
  padding-bottom: 50px; border-bottom: 1px solid var(--line);
}
.footer-logo {
  font-family: var(--sans); font-size: 18px; font-weight: 500; letter-spacing: 0.3em;
  text-transform: uppercase; color: var(--black); margin-bottom: 18px;
}
.footer-logo em { font-family: var(--serif); font-style: italic; font-weight: 300; text-transform: none; letter-spacing: 0; }
.footer-tagline { font-family: var(--serif); font-style: italic; font-size: 15px; color: var(--taupe); max-width: 240px; }
.footer-col h4 { font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--black); margin-bottom: 18px; }
.footer-col a { display: block; margin-bottom: 11px; color: var(--taupe); transition: color .3s ease; }
.footer-col a:hover { color: var(--gold); }
.footer-bottom {
  display: flex; justify-content: space-between; padding-top: 26px;
  font-size: 11px; letter-spacing: 0.05em; flex-wrap: wrap; gap: 12px; color: var(--taupe);
}

/* =====================================================
   NEWSLETTER POPUP — once-per-session modal (site-wide, footer.php)
   Deliberately NOT a clone of the full-bleed split-screen popup
   pattern (kuos.es reference) — floating centered card, pill CTA,
   welcome-offer framing, distinct from the inline homepage form.
   ===================================================== */
.news-popup {
  position: fixed; inset: 0; z-index: 1200;
  display: none;
  align-items: center; justify-content: center;
  padding: 24px;
}
.news-popup.is-open { display: flex; }

.news-popup-backdrop {
  position: absolute; inset: 0;
  background: rgba(10,10,10,0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  opacity: 0;
  transition: opacity .4s ease;
}
.news-popup.is-visible .news-popup-backdrop { opacity: 1; }

.news-popup-card {
  position: relative;
  display: grid; grid-template-columns: 1fr 1.15fr;
  width: min(920px, 100%);
  max-height: 90vh;
  background: var(--white);
  box-shadow: 0 40px 100px -20px rgba(0,0,0,0.35);
  overflow: hidden;
  transform: translateY(24px) scale(0.98);
  opacity: 0;
  transition: transform .5s cubic-bezier(.16,1,.3,1), opacity .5s ease;
}
.news-popup.is-visible .news-popup-card { transform: translateY(0) scale(1); opacity: 1; }

/* Brand panel: the wordmark on a warm champagne wash instead of a stock photo.
   The centre of the gradient is held at pure white on purpose — kuos-logo.svg
   is a trace whose letter counters are OPAQUE white, not transparent, so they
   only disappear against a near-white backdrop. The tint is pushed out to the
   corners, which still separates this half from the white content half. */
.news-popup-visual {
  position: relative;
  min-height: 260px;
  display: flex; align-items: center; justify-content: center;
  padding: 44px 34px 64px;
  background:
    radial-gradient(68% 54% at 50% 42%, #FFFFFF 0%, #FDFBF8 46%, rgba(253,251,248,0) 100%),
    linear-gradient(145deg, #F7F3EC 0%, #EFE6D6 58%, #E6D9C2 100%);
}
/* Hairline inset frame — same thin-line language as .cat-card-arrow / .nav-social-link. */
.news-popup-visual::after {
  content: ''; position: absolute; inset: 14px;
  border: 1px solid rgba(201,169,110,0.45);
  pointer-events: none;
}
.news-popup-logo { position: relative; width: min(212px, 64%); height: auto; }
.news-popup-visual-tag {
  position: absolute; left: 30px; right: 30px; bottom: 26px;
  display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 18px;
}
.news-popup-visual-tag span {
  font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--taupe);
}

.news-popup-content { padding: 56px 44px; display: flex; flex-direction: column; }
.news-popup-content h3 {
  font-family: var(--sans); font-weight: 300;
  font-size: clamp(24px, 2.4vw, 32px); line-height: 1.25; color: var(--black);
  margin-bottom: 18px;
}
.news-popup-content h3 em { font-family: var(--serif); font-style: italic; color: var(--gold); }
.news-popup-text { font-size: 14px; line-height: 1.8; color: var(--taupe); margin-bottom: 30px; }
.news-popup-text strong { color: var(--black); font-weight: 500; }

/* pill input+button row — distinct from the underline-style .news-form on the homepage */
.news-popup-form {
  border-bottom: none; padding-bottom: 0; gap: 10px; margin-bottom: 18px;
}
.news-popup-form::after { display: none; }
.news-popup-form input {
  border: 1px solid var(--line); border-radius: 999px;
  padding: 12px 18px;
}
.news-popup-form button {
  background: var(--black); color: var(--white);
  padding: 10px 20px; border-radius: 999px;
  gap: 8px;
  transition: background .3s ease;
}
.news-popup-form button:hover { background: var(--gold); }
.news-popup-form button svg { transition: transform .3s cubic-bezier(.16,1,.3,1); }
.news-popup-form button:hover svg { transform: translateX(4px); }

.news-popup-msg {
  font-size: 12px; color: var(--gold); min-height: 1.4em;
  opacity: 0; transition: opacity .4s ease; margin-bottom: 14px;
}
.news-popup-msg.show { opacity: 1; }

.news-popup-skip {
  align-self: flex-start;
  background: none; border: none; padding: 0;
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--taupe); text-decoration: underline; text-underline-offset: 3px;
  cursor: pointer; transition: color .3s ease;
}
.news-popup-skip:hover { color: var(--gold); }

.news-popup-close {
  position: absolute; top: 18px; right: 18px; z-index: 2;
  width: 32px; height: 32px; border-radius: 50%;
  background: rgba(255,255,255,0.9); border: none;
  display: flex; align-items: center; justify-content: center;
  color: var(--black); cursor: pointer;
  transition: background .3s ease, color .3s ease, transform .3s ease;
}
.news-popup-close:hover { background: var(--gold); color: var(--white); transform: rotate(90deg); }

body.news-popup-open { overflow: hidden; }

@media (max-width: 760px) {
  .news-popup-card { grid-template-columns: 1fr; max-height: 92vh; overflow-y: auto; }
  .news-popup-visual { min-height: 180px; }
  .news-popup-content { padding: 36px 28px; }
}
@media (max-width: 480px) {
  .news-popup-form { flex-direction: column; align-items: stretch; }
  .news-popup-form button { justify-content: center; }
}

/* =====================================================
   NEWSLETTER + FOOTER — MOBILE
   ===================================================== */
@media (max-width: 760px) {
  .footer-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 480px) {
  .news-form { flex-direction: column; align-items: stretch; gap: 12px; }
  .news-form button { justify-content: center; }
}

/* =====================================================
   PRESS — MOBILE
   ===================================================== */
@media (max-width: 768px) {
  .press-track img { height: 72px; padding: 0 36px; }
}

/* =====================================================
   INGREDIENTS — MOBILE
   ===================================================== */
@media (max-width: 768px) {
  .ingredients-pin { height: auto; }
  .ingredients-sticky { position: relative; height: auto; overflow: visible; padding: 60px 6vw; }
  .ing-head { position: relative; top: auto; left: auto; right: auto; margin-bottom: 40px; }
  .ing-slide { position: relative; opacity: 1; pointer-events: auto; inset: auto; display: block; }
  .ing-slide:not(:last-child) { margin-bottom: 60px; }
  .ing-slide-inner { grid-template-columns: 1fr; }
  .ing-visual { height: 280px; }
  .ing-progress { display: none; }
}

/* =====================================================
   "NOUS ?" (ABOUT) PAGE — scoped to .page-nous
   ===================================================== */

/* Hero / manifesto — a diagonal editorial photo strip behind the text, like a magazine spread */
.page-nous .nous-hero {
  position: relative; overflow: hidden;
  min-height: 100vh;
  background: var(--black); color: var(--white);
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 160px 8vw 90px;
}
.page-nous .nous-hero-collage {
  position: absolute; top: 0; bottom: 0; left: -5vw; right: -5vw;
  display: flex; z-index: 0;
}
.page-nous .nous-hero-panel {
  flex: 1; position: relative; overflow: hidden;
  transform: skewX(-9deg);
}
.page-nous .nous-hero-panel img {
  position: absolute; top: 50%; left: 50%;
  width: 145%; height: 125%;
  transform: translate(-50%, -50%) skewX(9deg) scale(1.15);
  object-fit: cover;
}
.page-nous .nous-hero-scrim {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(10,10,10,0.55) 0%, rgba(10,10,10,0.32) 45%, rgba(10,10,10,0.88) 100%);
}
.page-nous .nous-hero-inner { position: relative; z-index: 2; max-width: 1000px; }
.page-nous .nous-hero-title {
  font-family: var(--sans); font-weight: 300;
  font-size: clamp(36px, 5.5vw, 84px); line-height: 1.12; letter-spacing: -0.01em;
  color: var(--white); margin-bottom: 32px;
}
.page-nous .nous-hero-title em { font-family: var(--serif); font-style: italic; color: var(--gold); }
.page-nous .nous-hero-sub {
  max-width: 520px; font-size: 16px; line-height: 1.8;
  color: rgba(255,255,255,0.7); font-weight: 300;
}

/* Tighter vertical rhythm than the homepage — scoped so it doesn't touch other pages.
   section-pad is 140px/90px; here ~60px/40px (~57% less) to close the big gaps. */
.page-nous .section-pad { padding-top: 60px; padding-bottom: 60px; }
@media (max-width: 768px) { .page-nous .section-pad { padding-top: 40px; padding-bottom: 40px; } }
@media (max-width: 700px) {
  /* 4 thin skewed panels read as clutter on narrow screens — show 2, less dramatic angle */
  .page-nous .nous-hero-panel--3, .page-nous .nous-hero-panel--4 { display: none; }
  .page-nous .nous-hero-panel { transform: skewX(-6deg); }
  .page-nous .nous-hero-panel img { transform: translate(-50%, -50%) skewX(6deg) scale(1.15); }
}
.page-nous .nous-section-head { margin-bottom: 40px; }

/* Shared section heading */
.page-nous h2 {
  font-family: var(--sans); font-weight: 300;
  font-size: clamp(30px, 4vw, 54px); line-height: 1.15; letter-spacing: -0.01em; color: var(--black);
}
.page-nous h2 em { font-family: var(--serif); font-style: italic; color: var(--black); }
.page-nous .nous-section-head { max-width: 720px; margin-bottom: 60px; }

/* Origine */
.page-nous .nous-origin { background: var(--white); }
.page-nous .nous-origin-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 80px; }
@media (max-width: 900px) { .page-nous .nous-origin-grid { grid-template-columns: 1fr; gap: 40px; } }
.page-nous .nous-origin-body p { font-size: 16px; line-height: 1.9; color: var(--taupe); margin-bottom: 20px; max-width: 480px; }
.page-nous .nous-values { display: flex; flex-wrap: wrap; gap: 32px; margin-top: 40px; }
.page-nous .nous-value { flex: 1; min-width: 150px; }
.page-nous .nous-value h4 {
  font-family: var(--sans); font-weight: 500; font-size: 13px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--black); margin-bottom: 10px;
}
.page-nous .nous-value p { font-size: 13px; line-height: 1.7; color: var(--taupe); }

/* Founder quote */
.page-nous .nous-quote-section { background: var(--grey); }
.page-nous .nous-quote { max-width: 780px; margin: 0 auto; text-align: center; }
.page-nous .nous-quote p {
  font-family: var(--serif); font-style: italic; font-weight: 300;
  font-size: clamp(24px, 3vw, 40px); line-height: 1.4; color: var(--black);
}
.page-nous .nous-quote-sig { margin-top: 28px; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--taupe); }
.page-nous .nous-quote-sig strong {
  display: block; font-family: var(--serif); font-style: italic; font-weight: 300;
  font-size: 22px; letter-spacing: 0; text-transform: none; color: var(--gold); margin-bottom: 6px;
}

/* Timeline — the gold thread, now a snake: two columns, row 1 reads left-to-right,
   the thread drops down to row 2's start column, row 2 reads right-to-left, etc.
   DOM/reading order stays strictly chronological (1..N) for a11y/tab order — only
   the visual column alternates per row via nth-of-type, so screen readers and
   keyboard nav still encounter events in date order even though row 2 is visually
   reversed. The connecting path is built in JS from each dot's real rendered
   center (see main.js) rather than assumed here, so it self-adjusts if content
   height varies per item, and collapses to a straight vertical line on mobile
   once the grid drops to a single column below. */
.page-nous .nous-timeline-section { background: var(--white); }
.page-nous .nous-timeline-section {
  /* content is now ~half the height of the old single-column list — tighten the
     bottom gap so it doesn't read as leftover dead space before the next section */
  padding-bottom: 30px;
}
@media (max-width: 768px) {
  .page-nous .nous-timeline-section { padding-bottom: 24px; }
}
.page-nous .nous-timeline {
  /* No width cap — full section width, same as .nous-origin-grid/.nous-split,
     which is the point of the 2-col snake (use the horizontal space a single
     vertical list wasted). */
  position: relative;
}
.page-nous .nous-timeline-path {
  position: absolute; inset: 0; width: 100%; height: 100%;
  overflow: visible; pointer-events: none; z-index: 0;
}
.page-nous .nous-tl-path-bg { fill: none; stroke: var(--line); stroke-width: 1; }
.page-nous .nous-tl-path-fill {
  fill: none; stroke: var(--gold); stroke-width: 1;
  stroke-linejoin: round; stroke-linecap: round;
}
/* Each row is an explicit flex pair — sidesteps CSS Grid auto-placement, whose
   forward-only cursor leaves dead cells (and the vertical gaps that come with
   them) when a fixed column is requested out of a simple left/right sequence.
   --rev flips the *visual* order only (row-reverse); DOM/reading order inside
   stays chronological, so a11y/tab order is unaffected. */
.page-nous .nous-tl-row { display: flex; gap: 56px; }
.page-nous .nous-tl-row--rev { flex-direction: row-reverse; }
.page-nous .nous-tl-row + .nous-tl-row { margin-top: 24px; }
/* Dot sits to the LEFT of its own text (not above it) — same technique the old
   single-column spine used. That leaves a permanently empty vertical channel
   directly under/over each dot, for the item's full height, regardless of how
   much text wraps. Vertical connectors between rows travel through that empty
   channel instead of through whatever paragraph happens to be in that column —
   putting the dot above the text (my first attempt) had no such channel, so a
   tall paragraph in the row above would sit directly in the line's path.
   padding-top:18 + dot at top:0 (not top:5) is the OTHER axis of the same
   problem: with no top clearance, the horizontal line (drawn through the dot's
   vertical center, ~7.5px down) mathematically overlapped the year label's own
   text height (~14px, starting at y:0) on every row, not just some — it was
   only more visually obvious depending on label width. Pushing the label down
   18px while keeping the dot pinned to the true top gives the line real
   clearance above every label, both columns, unconditionally. */
.page-nous .nous-tl-item {
  position: relative; z-index: 1;
  flex: 0 0 calc(50% - 28px);
  padding: 18px 20px 4px 28px;
  /* Opacity-only reveal (no translateY, unlike the shared .reveal class) —
     the shared class's transform was deliberately dropped in main.js because
     it shifted each item's rendered position after buildNousPath() already
     measured it, desyncing the gold thread from the dots. Opacity alone
     can't move anything, so it's safe to bring back just for entrance-motion
     consistency with every other section on the site. */
  opacity: 0;
  transition: opacity .7s ease;
}
.page-nous .nous-tl-item.in { opacity: 1; }
.page-nous .nous-tl-dot {
  position: absolute; left: 0; top: 0; width: 15px; height: 15px; border-radius: 50%;
  background: var(--white); border: 1px solid var(--line);
  transition: background .5s ease, border-color .5s ease;
}
.page-nous .nous-tl-item.in .nous-tl-dot { background: var(--gold); border-color: var(--gold); }
/* Ignition pulse — a gold ring that expands and fades out once, right as the
   thread reaches this dot (see the traveled >= dotOffsets[i] check in
   main.js). Plays once because .in only ever gets added, never removed. */
.page-nous .nous-tl-dot::after {
  content: ''; position: absolute; inset: -4px; border-radius: 50%;
  border: 1px solid var(--gold); opacity: 0; transform: scale(0.6);
}
.page-nous .nous-tl-item.in .nous-tl-dot::after {
  animation: nousDotPulse .7s cubic-bezier(.16,1,.3,1);
}
@keyframes nousDotPulse {
  0% { opacity: .8; transform: scale(0.6); }
  100% { opacity: 0; transform: scale(1.9); }
}
.page-nous .nous-tl-year {
  display: block; font-family: var(--sans); font-size: 12px; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--gold); margin-bottom: 8px;
}
.page-nous .nous-tl-body h3 {
  font-family: var(--sans); font-weight: 400; font-size: 19px; color: var(--black); margin-bottom: 8px;
}
.page-nous .nous-tl-body p { font-size: 14px; line-height: 1.7; color: var(--taupe); }
.page-nous .nous-tl-item--highlight h3 { color: var(--gold); }

/* Mobile — collapse each row to a single stacked column (kill the row-reverse
   too, so DOM order = visual order); the JS path-builder re-measures dot
   positions on resize, so the snake automatically becomes a straight vertical
   thread again with zero extra code. */
@media (max-width: 700px) {
  .page-nous .nous-tl-row,
  .page-nous .nous-tl-row--rev { flex-direction: column; gap: 40px; }
  .page-nous .nous-tl-row + .nous-tl-row { margin-top: 40px; }
  .page-nous .nous-tl-item { flex: 1 1 100%; }
}

/* Split image/text blocks (Fabriqué, Maroc) */
.page-nous .nous-made { background: var(--grey); }
.page-nous .nous-maroc { background: var(--white); }
.page-nous .nous-split { display: grid; grid-template-columns: 1fr 1fr; gap: 80px; align-items: center; }
@media (max-width: 900px) { .page-nous .nous-split { grid-template-columns: 1fr; gap: 48px; } }
.page-nous .nous-split-text h2 { margin-bottom: 24px; }
.page-nous .nous-split-text p { font-size: 16px; line-height: 1.9; color: var(--taupe); max-width: 460px; }
.page-nous .nous-split-img { position: relative; aspect-ratio: 4/5; overflow: hidden; background: var(--bg); }
.page-nous .nous-split-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* Certifications — a gold-framed dark "award plaque" that pops against the light section.
   Double frame (border + offset outline) reads as a certificate/seal; dark bg makes the
   gold numbers and inverted badges catch the eye. */
.page-nous .nous-cert-panel {
  position: relative; margin: 56px 8px 0;
  background: #14110d;
  border: 1px solid rgba(201,169,110,0.55);
  outline: 1px solid rgba(201,169,110,0.35);
  outline-offset: 7px;
  padding: 60px 6vw;
}
.page-nous .nous-cert-panel-label {
  text-align: center; font-family: var(--sans); font-weight: 500; font-size: 12px;
  letter-spacing: 0.24em; text-transform: uppercase; color: var(--gold); margin-bottom: 48px;
}
.page-nous .nous-certs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; margin-top: 0; }
.page-nous .nous-cert { padding: 6px 30px; border-left: 1px solid rgba(201,169,110,0.2); text-align: center; }
.page-nous .nous-cert:first-child { border-left: none; }
@media (max-width: 760px) {
  .page-nous .nous-certs { grid-template-columns: 1fr; }
  .page-nous .nous-cert { border-left: none; border-top: 1px solid rgba(201,169,110,0.2); padding: 24px 0; }
  .page-nous .nous-cert:first-child { border-top: none; }
}
.page-nous .nous-cert-num { font-family: var(--serif); font-size: 25px; color: var(--gold); margin-bottom: 12px; }
.page-nous .nous-cert-label { font-size: 13px; line-height: 1.7; color: rgba(255,255,255,0.58); }
.page-nous .nous-cert-badges { margin-top: 48px; padding-top: 44px; border-top: 1px solid rgba(201,169,110,0.2); text-align: center; }
/* Was filter:invert(1) to read against the dark plaque — but ACENE's seals are
   multi-color, and a blanket invert shifts each one to its photographic
   negative rather than producing a real "light" version (e.g. green→magenta).
   That both looks off and risks showing an official third-party mark in
   colors it was never issued in. Inset the untouched badge on its own light
   card instead — same "pops against the dark plaque" effect, real colors. */
.page-nous .nous-cert-badges img {
  max-width: 460px; width: 100%; height: auto;
  background: var(--white); border-radius: 6px; padding: 20px 26px;
}

/* Engagement durable */
/* Engagement section — the fresh eucalyptus photo IS the background (anchored
   right, where the plant sits), text overlaid on the bright left side. A
   left-to-right cream scrim keeps the plant visible on the right while giving
   the text a near-solid light backing on the left for legibility. Replaces
   the old black-band-then-photo-strip layout entirely. */
.page-nous .nous-eco {
  position: relative; overflow: hidden;
  background: var(--bg);
  min-height: 560px;
  display: flex; align-items: center;
  padding: 90px 8vw;
}
.page-nous .nous-eco-bg {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: right center;
}
/* Cream scrim, opaque on the left (text zone) fading to clear on the right so
   the eucalyptus reads through. */
.page-nous .nous-eco::before {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(100deg,
    var(--bg) 0%, var(--bg) 30%,
    rgba(250,248,245,0.86) 48%,
    rgba(250,248,245,0.35) 68%,
    rgba(250,248,245,0) 88%);
}
.page-nous .nous-eco-inner {
  position: relative; z-index: 2;
  width: 100%; max-width: var(--container);
  margin: 0 auto;
}
.page-nous .nous-eco-head { max-width: 560px; }
.page-nous .nous-eco h2 { color: var(--black); }
.page-nous .nous-eco h2 em { color: var(--gold); }
.page-nous .nous-eco-lead { margin-top: 22px; max-width: 480px; font-size: 15px; line-height: 1.8; color: var(--taupe); }
/* The 3 R's as a pillar row on the left, under the heading. */
.page-nous .nous-eco-pillars {
  display: flex; flex-wrap: wrap; gap: 32px;
  margin-top: 48px; max-width: 620px;
}
.page-nous .nous-eco-pillar { flex: 1 1 150px; min-width: 0; }
/* Thin-line circle icon — same 1px-border-circle language as .nav-social-link
   / .cat-card-arrow elsewhere in the theme. Gold-on-cream now (section is
   light), fills gold on hover. */
.page-nous .nous-eco-icon {
  width: 56px; height: 56px; margin-bottom: 18px;
  border: 1px solid rgba(201,169,110,0.7); border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: var(--gold); background: rgba(255,255,255,0.5);
  transition: background .35s cubic-bezier(.16,1,.3,1), border-color .35s cubic-bezier(.16,1,.3,1), color .35s cubic-bezier(.16,1,.3,1);
}
.page-nous .nous-eco-pillar:hover .nous-eco-icon { background: var(--gold); border-color: var(--gold); color: var(--white); }
.page-nous .nous-eco-pillar h4 { font-family: var(--sans); font-weight: 500; font-size: 13px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--black); margin-bottom: 10px; }
.page-nous .nous-eco-pillar p { font-size: 13.5px; line-height: 1.7; color: var(--taupe); }
@media (max-width: 860px) {
  /* On narrow screens the plant can't share the row with text — push the
     scrim to cover most of the frame so text stays legible, image reads as a
     soft tint behind. */
  .page-nous .nous-eco { min-height: 0; padding: 70px 6vw; }
  .page-nous .nous-eco::before {
    background: linear-gradient(180deg,
      var(--bg) 0%, rgba(250,248,245,0.9) 55%, rgba(250,248,245,0.78) 100%);
  }
  .page-nous .nous-eco-pillars { gap: 28px; }
  /* Icon left, label + copy stacked to its right. Must be grid, not flex: the
     pillar's children are icon + h4 + p as three siblings (no text wrapper),
     so flex lays all three out in one row and strands the label in its own
     column at the top of the block instead of directly above its paragraph. */
  .page-nous .nous-eco-pillar {
    flex: 1 1 100%;
    display: grid; grid-template-columns: 48px 1fr; column-gap: 16px;
  }
  .page-nous .nous-eco-icon { grid-column: 1; grid-row: 1 / 3; align-self: start; margin-bottom: 0; width: 48px; height: 48px; }
  .page-nous .nous-eco-pillar h4 { grid-column: 2; grid-row: 1; margin-bottom: 6px; }
  .page-nous .nous-eco-pillar p { grid-column: 2; grid-row: 2; }
}

/* CTA */
.page-nous .nous-cta { background: var(--grey); text-align: center; }
.page-nous .nous-cta-inner { max-width: 620px; margin: 0 auto; }
.page-nous .nous-cta h2 { margin-bottom: 18px; }
.page-nous .nous-cta p { font-size: 15px; color: var(--taupe); margin-bottom: 40px; }
.page-nous .nous-cta-btn {
  display: inline-flex; align-items: center; gap: 10px;
  background: var(--black); color: var(--white);
  padding: 16px 34px; border-radius: 999px;
  font-family: var(--sans); font-size: 12px; letter-spacing: 0.16em; text-transform: uppercase;
  transition: background .3s ease;
}
.page-nous .nous-cta-btn:hover { background: var(--gold); }
.page-nous .nous-cta-btn svg { transition: transform .3s cubic-bezier(.16,1,.3,1); }
.page-nous .nous-cta-btn:hover svg { transform: translateX(4px); }

/* =====================================================
   CONTACT PAGE (page-contact.php)
   ===================================================== */
.page-contact .contact-layout {
  padding: 150px 8vw 80px;
  max-width: var(--container); margin: 0 auto;
}
@media (max-width: 768px) { .page-contact .contact-layout { padding: 120px 6vw 56px; } }

/* Two columns: left holds the hero headline + coordonnées; the form (right)
   starts at the top, parallel with the headline, instead of below the hero. */
.page-contact .contact-grid {
  display: grid; grid-template-columns: 1.1fr 0.9fr; gap: 72px; align-items: start;
}
@media (max-width: 900px) {
  .page-contact .contact-grid { grid-template-columns: 1fr; gap: 56px; }
}

.page-contact .contact-hero-inner { max-width: none; margin-bottom: 56px; }
@media (max-width: 900px) { .page-contact .contact-hero-inner { margin-bottom: 40px; } }
.page-contact .contact-hero-title {
  font-family: var(--sans); font-weight: 300;
  font-size: clamp(38px, 5.2vw, 76px); line-height: 1.06; letter-spacing: -0.02em;
  color: var(--black); margin-bottom: 24px; text-wrap: balance;
}
.page-contact .contact-hero-title em { font-family: var(--serif); font-style: italic; color: var(--gold); }
.page-contact .contact-hero-sub {
  max-width: 520px; font-size: 16px; line-height: 1.8; color: var(--taupe); font-weight: 300;
}

/* LEFT — coordonnées */
.page-contact .contact-detail { display: flex; gap: 18px; margin-bottom: 34px; }
.page-contact .contact-detail-icon {
  flex: 0 0 auto; width: 48px; height: 48px; border-radius: 50%;
  border: 1px solid rgba(201,169,110,0.6);
  display: flex; align-items: center; justify-content: center; color: var(--gold);
}
.page-contact .contact-detail-body h3 {
  font-family: var(--sans); font-weight: 500; font-size: 12px;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--black); margin: 4px 0 8px;
}
.page-contact .contact-detail-body a,
.page-contact .contact-detail-body p {
  font-size: 15px; line-height: 1.7; color: var(--taupe); font-weight: 300;
}
.page-contact .contact-detail-body a { transition: color .25s ease; }
.page-contact .contact-detail-body a:hover { color: var(--gold); }
.page-contact .contact-detail-muted { color: var(--taupe); opacity: 0.7; font-size: 13px; }

.page-contact .contact-social { margin-top: 44px; padding-top: 32px; border-top: 1px solid rgba(10,10,10,0.08); }
.page-contact .contact-social-label {
  display: block; font-size: 11px; letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--taupe); margin-bottom: 16px;
}
.page-contact .contact-social-links { display: flex; gap: 12px; }
.page-contact .contact-social-links a {
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid rgba(10,10,10,0.14); color: var(--black);
  display: flex; align-items: center; justify-content: center;
  transition: background .3s ease, border-color .3s ease, color .3s ease;
}
.page-contact .contact-social-links a:hover { background: var(--gold); border-color: var(--gold); color: var(--white); }

/* RIGHT — formulaire */
.page-contact .contact-form-wrap {
  background: var(--white); border: 1px solid rgba(10,10,10,0.06); border-radius: 16px;
  padding: 44px; box-shadow: 0 24px 60px -30px rgba(0,0,0,0.22);
}
@media (max-width: 560px) { .page-contact .contact-form-wrap { padding: 28px 22px; } }
.page-contact .contact-form-head { margin-bottom: 30px; }
.page-contact .contact-form-head h2 {
  font-family: var(--serif); font-style: italic; font-weight: 400;
  font-size: 30px; line-height: 1.1; color: var(--black); margin: 6px 0 0;
}
.page-contact .contact-field { margin-bottom: 22px; }
.page-contact .contact-field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
@media (max-width: 480px) { .page-contact .contact-field-row { grid-template-columns: 1fr; gap: 0; } }
.page-contact .contact-field label {
  display: block; font-size: 12px; letter-spacing: 0.06em; color: var(--black);
  font-weight: 500; margin-bottom: 9px;
}
.page-contact .contact-field-opt { color: var(--taupe); font-weight: 300; letter-spacing: 0; text-transform: none; }
.page-contact .contact-field input,
.page-contact .contact-field textarea {
  width: 100%; box-sizing: border-box;
  font-family: var(--sans); font-size: 15px; font-weight: 300; color: var(--black);
  /* Resting border must be clearly visible (refactoring-ui "Input States":
     default = border-gray-300, not a barely-there hairline). Warm taupe tint
     rather than cold grey to match the palette. */
  background: var(--bg); border: 1px solid rgba(110,110,110,0.34); border-radius: 9px;
  padding: 13px 15px; transition: border-color .2s ease, background .2s ease, box-shadow .2s ease;
}
.page-contact .contact-field textarea { resize: vertical; min-height: 120px; line-height: 1.6; }
.page-contact .contact-field input::placeholder,
.page-contact .contact-field textarea::placeholder { color: var(--taupe); }
/* Focus = gold border + soft gold ring (the "ring-2" half of the spec). */
.page-contact .contact-field input:focus,
.page-contact .contact-field textarea:focus {
  outline: none; border-color: var(--gold); background: var(--white);
  box-shadow: 0 0 0 3px rgba(201,169,110,0.18);
}
/* Field-level error state — the invalid input itself is marked, not just the
   status line, so the user sees exactly which field to fix. */
.page-contact .contact-field.has-error input,
.page-contact .contact-field.has-error textarea {
  border-color: #C2705B; box-shadow: 0 0 0 3px rgba(194,112,91,0.15);
}
/* Honeypot — visually removed but still focusable-by-bots, off-screen not display:none
   so headless form-fillers still see it as a real field to trip on. */
.page-contact .contact-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.page-contact .contact-submit {
  display: inline-flex; align-items: center; gap: 10px;
  background: var(--black); color: var(--white);
  padding: 15px 32px; border: none; border-radius: 999px; cursor: pointer;
  font-family: var(--sans); font-size: 12px; letter-spacing: 0.16em; text-transform: uppercase;
  transition: background .3s ease;
}
.page-contact .contact-submit:hover { background: var(--gold); }
.page-contact .contact-submit:disabled { opacity: 0.6; cursor: default; }
.page-contact .contact-submit svg { transition: transform .3s cubic-bezier(.16,1,.3,1); }
.page-contact .contact-submit:hover:not(:disabled) svg { transform: translateX(4px); }
/* Keyboard focus — on-brand AND clearly visible (Pillar 7 + WCAG). */
.page-contact .contact-submit:focus-visible,
.page-contact .contact-social-links a:focus-visible {
  outline: 2px solid var(--gold); outline-offset: 3px;
}
.page-contact .contact-form-msg {
  margin-top: 18px; font-size: 14px; color: var(--gold);
  opacity: 0; transition: opacity .3s ease;
}
.page-contact .contact-form-msg.show { opacity: 1; }
.page-contact .contact-form-msg.error { color: #A85C4A; }

/* MAP — full container-width, below the form */
.page-contact .contact-map { max-width: var(--container); margin: 0 auto; padding: 0 8vw 100px; }
@media (max-width: 768px) { .page-contact .contact-map { padding: 0 6vw 64px; } }
.page-contact .contact-map-frame {
  position: relative; width: 100%; aspect-ratio: 16 / 6;
  border-radius: 16px; overflow: hidden;
  border: 1px solid rgba(10,10,10,0.08);
  box-shadow: 0 30px 60px -30px rgba(0,0,0,0.22);
}
@media (max-width: 768px) { .page-contact .contact-map-frame { aspect-ratio: 4 / 3; } }
.page-contact .contact-map-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.page-contact .contact-map-link {
  display: inline-flex; align-items: center; gap: 8px; margin-top: 18px;
  font-family: var(--sans); font-size: 12px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--black); transition: color .25s ease;
}
.page-contact .contact-map-link:hover { color: var(--gold); }
.page-contact .contact-map-link svg { transition: transform .3s cubic-bezier(.16,1,.3,1); }
.page-contact .contact-map-link:hover svg { transform: translate(3px,-3px); }

/* =====================================================
   REDUCED MOTION — WCAG 2.1 AA
   ===================================================== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .reveal { opacity: 1; transform: none; }
  .page-nous .nous-tl-item { opacity: 1; }
  .brand-film-title .word { opacity: 1; transform: none; animation: none; }
  .page-nous .nous-tl-dot::after { animation: none; opacity: 0; }
  .marquee-track { animation: none; }
  .press-track { animation: none; }
  .cat-card-img img { transition: none; }
  .page-nous .nous-eco-bg { transition: none; }
  .ing-visual-blob { transition: none; }
  .trust-bar-fill { transition: none; }
  .brand-stamp { transition: none; }
  .news-form::after { transition: none; }
  .news-form button svg { transition: none; }
  .news-popup-backdrop { transition: none; }
  .news-popup-card { transition: none; transform: none; }
  .news-popup-close { transition: none; }
  .news-popup-form button, .news-popup-form button svg { transition: none; }
  .nav-social-link { transition: none; }
  .page-nous .nous-eco-icon { transition: none; }
  .page-contact .contact-social-links a,
  .page-contact .contact-submit,
  .page-contact .contact-submit svg,
  .page-contact .contact-field input,
  .page-contact .contact-field textarea { transition: none; }
}

/* =====================================================
   GAMME PAGES (template-parts/gamme.php)

   Concept: every KUO'S bottle is the same white cylinder, distinguished only
   by one small printed colour square identifying its ligne. The page performs
   the sort — white mass first, then the key, then the colour-ordered lines.

   Two rules that hold the whole thing together:
   - ONE accent colour active at a time. --accent is set per ligne on the rail
     item and its panel; nothing else is coloured.
   - Colour appears as chips and hairlines only, never as a background wash.
     A white page plus one precise colour reads more expensive than ten at once.
   ===================================================== */

/* ---------- S1 · Hero ---------- */
.page-gamme .gm-hero {
  position: relative; min-height: 82vh;
  display: flex; align-items: flex-end; overflow: hidden;
}
.page-gamme .gm-hero-media { position: absolute; inset: 0; }
.page-gamme .gm-hero-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.page-gamme .gm-hero-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(14,14,14,.80) 0%, rgba(14,14,14,.42) 45%, rgba(14,14,14,.18) 100%);
}
.page-gamme .gm-hero-inner {
  position: relative; width: 100%;
  max-width: var(--container); margin: 0 auto;
  padding: 0 8vw 92px; color: var(--white);
}
.page-gamme .gm-hero-eyebrow { color: rgba(255,255,255,0.62); }
.page-gamme .gm-hero-title {
  font-family: var(--serif); font-weight: 300;
  font-size: clamp(40px, 6.4vw, 88px); line-height: 1.06;
  letter-spacing: -0.01em; margin-bottom: 26px;
}
.page-gamme .gm-hero-title em { font-style: italic; color: var(--gold); }
.page-gamme .gm-hero-lede {
  max-width: 560px; font-size: 15px; line-height: 1.75;
  color: rgba(255,255,255,0.80);
}

/* ---------- Shared section headings ---------- */
.page-gamme .gm-range-head,
.page-gamme .gm-lignes-head,
.page-gamme .gm-protocol-head {
  max-width: var(--container); margin: 0 auto 60px; text-align: center;
}
.page-gamme .gm-range-head h2,
.page-gamme .gm-lignes-head h2,
.page-gamme .gm-protocol-head h2,
.page-gamme .gm-key-text h2,
.page-gamme .gm-cta h2 {
  font-family: var(--serif); font-weight: 300;
  font-size: clamp(30px, 3.9vw, 52px); line-height: 1.14; letter-spacing: -0.01em;
}
.page-gamme .gm-range-head em,
.page-gamme .gm-lignes-head em,
.page-gamme .gm-protocol-head em,
.page-gamme .gm-key-text em,
.page-gamme .gm-cta em { font-style: italic; color: var(--gold); }

/* Bootstrap's reboot sets `ol, ul { padding-left: 2rem }` — specificity (0,0,1),
   which BEATS the `* { padding: 0 }` global reset (0,0,0) no matter the order.
   Every list on this page needs the indent killed explicitly or it sits 32px
   off-centre inside its own container. */
.page-gamme .gm-range-wall,
.page-gamme .gm-products,
.page-gamme .gm-service-list,
.page-gamme .gm-protocol-steps { padding-left: 0; }

/* ---------- S2 · The white range ----------
   Deliberately small and tightly packed: at this scale the chips are not yet
   readable, which is the problem the next section solves. */
.page-gamme .gm-range { background: var(--white); }
.page-gamme .gm-range-note {
  max-width: 520px; margin: 20px auto 0;
  font-size: 14px; line-height: 1.75; color: var(--taupe);
}
.page-gamme .gm-range-wall {
  display: flex; flex-wrap: wrap;
  justify-content: center; align-items: flex-end;
  max-width: var(--container); margin: 0 auto; list-style: none;
}
.page-gamme .gm-range-wall li { width: clamp(26px, 3vw, 44px); margin: 0 -1px; }
.page-gamme .gm-range-wall img {
  width: 100%; height: auto; display: block;
  opacity: .92; filter: saturate(.25);
}

/* ---------- S3 · The key ---------- */
.page-gamme .gm-key { background: var(--bg); }
.page-gamme .gm-key-grid {
  display: grid; grid-template-columns: 0.85fr 1.15fr;
  gap: clamp(36px, 6vw, 96px); align-items: center;
  max-width: var(--container); margin: 0 auto; padding: 140px 8vw;
}
/* width:max-content so the loupe/leader percentages resolve against the
   BOTTLE box, not the column — otherwise they drift with the viewport. */
.page-gamme .gm-key-visual { position: relative; width: max-content; margin: 0 auto; }
.page-gamme .gm-key-bottle { height: clamp(360px, 40vw, 520px); width: auto; display: block; }

/* Chip sits at 49% / 71.8% of the packshot on every KUO'S bottle (measured
   across the range, consistent at 120/200/400ml). */
.page-gamme .gm-key-ring {
  position: absolute; left: 49%; top: 71.8%;
  width: 26px; height: 26px; margin: -13px 0 0 -13px;
  border: 1px solid var(--gold); border-radius: 50%;
}
.page-gamme .gm-key-leader {
  position: absolute; left: calc(49% + 13px); top: 71.8%;
  width: 96px; height: 1px; background: var(--gold);
}
.page-gamme .gm-key-loupe {
  position: absolute; left: calc(49% + 109px); top: 71.8%;
  width: 172px; height: 172px; margin-top: -86px;
  border-radius: 50%; background: #fff center/cover no-repeat;
  box-shadow: 0 0 0 1px var(--line), 0 26px 54px rgba(0,0,0,.14);
}
.page-gamme .gm-key-text p {
  font-size: 15px; line-height: 1.8; color: var(--taupe); margin-top: 22px; max-width: 480px;
}
/* Needs the extra .gm-key-text to outrank `.page-gamme .gm-key-text p`, which
   is (0,2,1) and would otherwise keep this paragraph taupe. */
.page-gamme .gm-key-text .gm-key-note { font-style: italic; color: var(--black); }

/* ---------- S4 · Ligne rail ----------
   Each ligne hangs from one shared horizontal axis by a hairline thread, chip
   at the bottom. Objects suspended on an axis rather than boxed in a grid —
   this is what survives of the Newton's-cradle idea, minus the physics. */
.page-gamme .gm-lignes { background: var(--white); padding: 140px 0; }
.page-gamme .gm-rail-wrap { position: relative; max-width: var(--container); margin: 0 auto; padding: 0 8vw; }
.page-gamme .gm-rail-axis {
  position: absolute; left: 8vw; right: 8vw; top: 0; height: 1px; background: var(--line);
}
.page-gamme .gm-rail { display: flex; align-items: flex-start; gap: 8px; }
/* The thread and chip are ABSOLUTE inside a fixed 88px "hanger" zone so that
   every label starts at the same y no matter how far its bob has dropped. If
   they were in flow, the taller active thread would push its own label down and
   the labels would sit at four different heights. */
.page-gamme .gm-rail-item {
  position: relative;
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center;
  background: none; border: 0; padding: 88px 4px 8px; cursor: pointer;
  font: inherit; color: inherit; text-align: center;
  /* --d is set per item by main.js: distance from the newly-active item, so
     the change ripples outward instead of all switching at once. */
  --d: 0ms;
}
.page-gamme .gm-rail-thread {
  position: absolute; top: 0; left: 50%;
  width: 1px; height: 30px; background: var(--line);
  transition: height .55s cubic-bezier(.16,1,.3,1) var(--d),
              background-color .55s ease var(--d);
}
.page-gamme .gm-rail-item:hover .gm-rail-thread { height: 40px; }
.page-gamme .gm-rail-item.is-active .gm-rail-thread { height: 62px; background: var(--accent); }
.page-gamme .gm-rail-chip {
  position: absolute; top: 30px; left: 50%; transform: translateX(-50%);
  width: 11px; height: 11px;
  border: 1px solid var(--accent); background: transparent;
  transition: top .55s cubic-bezier(.16,1,.3,1) var(--d),
              width .55s cubic-bezier(.16,1,.3,1) var(--d),
              height .55s cubic-bezier(.16,1,.3,1) var(--d),
              background-color .55s ease var(--d);
}
.page-gamme .gm-rail-item:hover .gm-rail-chip { top: 40px; }
.page-gamme .gm-rail-item.is-active .gm-rail-chip { top: 62px; width: 17px; height: 17px; background: var(--accent); }
/* Renewal carries no printed square — neutral marker, never an invented colour */
.page-gamme .gm-rail-chip.is-nochip { border-style: dashed; border-color: var(--taupe); }
.page-gamme .gm-rail-item.is-active .gm-rail-chip.is-nochip { background: transparent; border-style: solid; }
.page-gamme .gm-rail-label { transition: opacity .4s ease var(--d); opacity: .62; }
.page-gamme .gm-rail-item:hover .gm-rail-label,
.page-gamme .gm-rail-item.is-active .gm-rail-label { opacity: 1; }
/* min-height reserves two lines for every name, so the longer ones ("Tenso &
   Supreme", "Bambou & Argan") don't push their own concern text below the
   others'. Keeps the concern row on one baseline across the rail. */
.page-gamme .gm-rail-name {
  display: block; font-family: var(--serif); font-size: clamp(15px, 1.4vw, 20px);
  line-height: 1.2; margin-bottom: 6px; min-height: 2.4em;
}
.page-gamme .gm-rail-concern {
  display: block; font-size: 10px; letter-spacing: 0.11em; text-transform: uppercase;
  color: var(--taupe); line-height: 1.4;
}
.page-gamme .gm-rail-item:focus-visible { outline: 1px solid var(--gold); outline-offset: 4px; }

/* ---------- S5 · Ligne panel ---------- */
.page-gamme .gm-panel { max-width: var(--container); margin: 0 auto; padding: 72px 8vw 0; }
.page-gamme .gm-panel[hidden] { display: none; }
.page-gamme .gm-panel-intro { text-align: center; max-width: 560px; margin: 0 auto 54px; }
.page-gamme .gm-panel-claim {
  font-size: 11px; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--accent); margin-bottom: 14px; font-weight: 500;
}
.page-gamme .gm-panel-name {
  font-family: var(--serif); font-weight: 300; font-size: clamp(28px, 3.4vw, 44px);
  line-height: 1.15; margin-bottom: 16px;
}
.page-gamme .gm-panel-desc { font-size: 15px; line-height: 1.8; color: var(--taupe); }
.page-gamme .gm-panel-nochip {
  margin-top: 18px; font-size: 12px; font-style: italic; color: var(--taupe);
  padding-top: 14px; border-top: 1px solid var(--line); display: inline-block;
}
.page-gamme .gm-products {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: clamp(16px, 2.4vw, 34px); justify-items: center; list-style: none;
}
.page-gamme .gm-product { text-align: center; max-width: 240px; }
.page-gamme .gm-product-shot {
  padding-top: 18px; border-top: 1px solid var(--line);
  margin-bottom: 20px; transition: border-color .4s ease;
}
.page-gamme .gm-product:hover .gm-product-shot { border-color: var(--accent); }
/* Fixed box + contain, rather than fixed height + width:auto. The range mixes
   tall bottles (205x900) with landscape boxes (560x217); with width:auto a
   landscape pack resolves to ~670px wide at this height and spills across its
   neighbour's grid cell. Containing inside a shared box also puts every shot
   on one baseline, which is what makes a row of mixed formats read as a set. */
.page-gamme .gm-product-shot img {
  height: clamp(180px, 20vw, 260px); width: 100%; object-fit: contain;
  display: block; margin: 0 auto;
  transition: transform .5s cubic-bezier(.16,1,.3,1);
}
.page-gamme .gm-product:hover .gm-product-shot img { transform: translateY(-6px); }
.page-gamme .gm-product-type {
  font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--accent); margin-bottom: 8px;
}
.page-gamme .gm-product-name { font-family: var(--serif); font-weight: 400; font-size: 17px; line-height: 1.3; }
.page-gamme .gm-product-size { font-size: 12px; color: var(--taupe); margin-top: 6px; }

/* ---------- Mode B · photography-led (no packshots) ---------- */
.page-gamme .gm-services { background: var(--white); }
.page-gamme .gm-service-list { max-width: 860px; margin: 0 auto; list-style: none; }
.page-gamme .gm-service {
  display: grid; grid-template-columns: 64px 1fr; gap: 24px;
  padding: 32px 0; border-top: 1px solid var(--line);
}
.page-gamme .gm-service-num { font-family: var(--serif); font-size: 22px; color: var(--gold); }
.page-gamme .gm-service h3 { font-family: var(--serif); font-weight: 400; font-size: 24px; margin-bottom: 8px; }
.page-gamme .gm-service p { font-size: 14px; line-height: 1.75; color: var(--taupe); }

/* ---------- S6 · Protocole ---------- */
.page-gamme .gm-protocol { background: var(--grey); }
.page-gamme .gm-protocol-steps {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 1px;
  max-width: var(--container); margin: 0 auto; list-style: none;
  background: var(--line); border: 1px solid var(--line);
}
.page-gamme .gm-protocol-steps li {
  background: var(--grey); padding: 34px 24px; text-align: center;
}
.page-gamme .gm-protocol-num {
  display: block; font-family: var(--serif); font-size: 20px; color: var(--gold); margin-bottom: 12px;
}
.page-gamme .gm-protocol-name {
  display: block; font-family: var(--serif); font-size: 21px; margin-bottom: 8px;
}
.page-gamme .gm-protocol-desc { display: block; font-size: 12px; line-height: 1.6; color: var(--taupe); }

/* ---------- S7 · CTA ---------- */
.page-gamme .gm-cta { background: var(--white); text-align: center; }
.page-gamme .gm-cta-inner { max-width: 620px; margin: 0 auto; }
.page-gamme .gm-cta h2 { margin-bottom: 18px; }
.page-gamme .gm-cta p { font-size: 15px; color: var(--taupe); margin-bottom: 40px; }
.page-gamme .gm-cta-btn {
  display: inline-flex; align-items: center; gap: 10px;
  background: var(--black); color: var(--white);
  padding: 16px 34px; border-radius: 999px;
  font-family: var(--sans); font-size: 12px; letter-spacing: 0.16em; text-transform: uppercase;
  transition: background .3s ease;
}
.page-gamme .gm-cta-btn:hover { background: var(--gold); }
.page-gamme .gm-cta-btn svg { transition: transform .3s cubic-bezier(.16,1,.3,1); }
.page-gamme .gm-cta-btn:hover svg { transform: translateX(4px); }

/* ---------- Responsive ---------- */
@media (max-width: 1024px) {
  .page-gamme .gm-key-grid { grid-template-columns: 1fr; padding: 100px 8vw; }
  .page-gamme .gm-key-text { text-align: center; }
  .page-gamme .gm-key-text p { margin-left: auto; margin-right: auto; }
  .page-gamme .gm-products { grid-template-columns: repeat(2, 1fr); }
  .page-gamme .gm-protocol-steps { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 860px) {
  /* Rail becomes a horizontal scroller — 7 items can't share a narrow row and
     stay tappable. The axis still runs behind them so the suspended read holds. */
  .page-gamme .gm-rail { overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: 8px; }
  .page-gamme .gm-rail-item { flex: 0 0 132px; scroll-snap-align: center; }
  /* Fade the right edge so it's obvious the rail continues past the viewport —
     a half-cut item alone reads as a layout bug to some users. */
  .page-gamme .gm-rail-wrap {
    -webkit-mask-image: linear-gradient(to right, #000 84%, transparent 100%);
            mask-image: linear-gradient(to right, #000 84%, transparent 100%);
  }
  .page-gamme .gm-lignes { padding: 90px 0; }
  .page-gamme .gm-panel { padding-top: 48px; }
}
@media (max-width: 768px) {
  .page-gamme .gm-hero { min-height: 74vh; }
  .page-gamme .gm-hero-inner { padding: 0 6vw 64px; }
  .page-gamme .gm-rail-wrap { padding: 0 6vw; }
  .page-gamme .gm-rail-axis { left: 6vw; right: 6vw; }
  .page-gamme .gm-panel { padding-left: 6vw; padding-right: 6vw; }
  .page-gamme .gm-key-grid { padding: 80px 6vw; }
  /* Leader + loupe would overflow the bottle box on narrow screens; the bottle
     alone still carries the section. */
  .page-gamme .gm-key-leader { display: none; }
  .page-gamme .gm-key-ring { display: none; }
  .page-gamme .gm-key-visual { width: auto; }
  .page-gamme .gm-key-bottle { margin: 0 auto; }
  .page-gamme .gm-key-loupe {
    position: static; margin: 28px auto 0; display: block; width: 148px; height: 148px;
  }
  .page-gamme .gm-protocol-steps { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .page-gamme .gm-products { grid-template-columns: 1fr; }
  .page-gamme .gm-service { grid-template-columns: 44px 1fr; gap: 14px; }
}

@media (prefers-reduced-motion: reduce) {
  .page-gamme .gm-rail-thread,
  .page-gamme .gm-rail-chip,
  .page-gamme .gm-rail-label,
  .page-gamme .gm-product-shot,
  .page-gamme .gm-product-shot img,
  .page-gamme .gm-cta-btn,
  .page-gamme .gm-cta-btn svg { transition: none; }
  .page-gamme .gm-product:hover .gm-product-shot img { transform: none; }
}

/* Products fade up in sequence when a ligne is selected. display:none ->
   display:grid re-triggers the animation, so it replays on every switch. */
.page-gamme .gm-panel.is-active .gm-product {
  animation: gmProductIn .55s cubic-bezier(.16,1,.3,1) backwards;
  animation-delay: calc(var(--j) * 60ms);
}
@keyframes gmProductIn {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .page-gamme .gm-panel.is-active .gm-product { animation: none; }
}

/* =====================================================
   GAMME — SHADE MODE (page-ongles.php)

   Ongles inverts the Cosmetique problem. There the range is one white mass
   and colour is the key that sorts it. Here colour IS the product, so the
   page leads with the whole collection at once and sorts it afterwards.

   Every chip is a CSS colour sampled from that shade's own painted swatch
   render — 217 <img> would be megabytes to say the same thing less sharply.
   ===================================================== */

.page-gamme .gm-wallsec { background: var(--white); }

/* Nail-shaped rather than square: the source swatches are painted nail tips,
   and a grid of rounded rectangles reads as a paint chart instead of a
   nuancier. Asymmetric radius = wider curve at the tip than at the cuticle. */
.page-gamme .gm-wall {
  display: flex; flex-wrap: wrap;
  justify-content: center; align-content: flex-start;
  gap: clamp(5px, 0.7vw, 9px);
  max-width: 1120px; margin: 0 auto; padding-left: 0; list-style: none;
}
.page-gamme .gm-wall li {
  width: clamp(20px, 2.1vw, 30px);
  aspect-ratio: 3 / 4;
  border-radius: 46% 46% 38% 38% / 34% 34% 22% 22%;
  background: var(--c);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.05);
  transition: transform .35s cubic-bezier(.16,1,.3,1), box-shadow .35s ease;
}
.page-gamme .gm-wall li:hover {
  transform: translateY(-5px) scale(1.14);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.05), 0 10px 22px rgba(0,0,0,.16);
}
/* The wall arrives shade by shade in hue order — 6ms apart, so 217 chips land
   in about 1.3s. Long enough to read as a sweep, short enough not to stall. */
.page-gamme .gm-wall.in li {
  animation: gmChipIn .5s cubic-bezier(.16,1,.3,1) backwards;
  animation-delay: calc(var(--i) * 6ms);
}
@keyframes gmChipIn {
  from { opacity: 0; transform: translateY(10px) scale(.7); }
  to   { opacity: 1; transform: none; }
}

/* ---------- S3 variant · the shade number ---------- */
.page-gamme .gm-num { background: var(--bg); }
.page-gamme .gm-num-grid {
  display: grid; grid-template-columns: 0.85fr 1.15fr;
  gap: clamp(36px, 6vw, 96px); align-items: center;
  max-width: var(--container); margin: 0 auto; padding: 140px 8vw;
}
.page-gamme .gm-num-visual { display: flex; justify-content: center; gap: clamp(12px, 2vw, 26px); }
.page-gamme .gm-num-drop {
  display: grid; place-items: center;
  width: clamp(74px, 8vw, 108px); aspect-ratio: 3 / 4;
  border-radius: 46% 46% 38% 38% / 34% 34% 22% 22%;
  background: var(--c);
  box-shadow: 0 14px 30px rgba(0,0,0,.14);
  /* Stagger the three demo shades so they settle like a hand of swatches */
  transform: translateY(calc(var(--k) * 14px)) rotate(calc((var(--k) - 1) * 5deg));
}
.page-gamme .gm-num-drop b {
  font-family: var(--sans); font-weight: 500;
  font-size: clamp(13px, 1.3vw, 17px); letter-spacing: .06em;
  color: #fff; text-shadow: 0 1px 5px rgba(0,0,0,.42);
}
.page-gamme .gm-num-text p {
  font-size: 15px; line-height: 1.8; color: var(--taupe); margin-top: 22px; max-width: 480px;
}
.page-gamme .gm-num-text .gm-key-note { font-style: italic; color: var(--black); }

/* ---------- Per-family shade card ---------- */
.page-gamme .gm-shades-lead {
  text-align: center; font-size: 11px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--taupe); margin-bottom: 26px;
}
.page-gamme .gm-shades {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
  gap: 4px 18px; max-width: 1000px; margin: 0 auto 64px;
  padding-left: 0; list-style: none;
}
.page-gamme .gm-shade {
  display: grid; grid-template-columns: 15px 1fr auto; align-items: center; gap: 10px;
  padding: 7px 2px; border-bottom: 1px solid transparent;
  transition: border-color .3s ease;
}
.page-gamme .gm-shade:hover { border-bottom-color: var(--line); }
.page-gamme .gm-shade-chip {
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--c); box-shadow: inset 0 0 0 1px rgba(0,0,0,.07);
}
.page-gamme .gm-shade-name {
  font-size: 12.5px; color: var(--black); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.page-gamme .gm-shade-num {
  font-size: 11px; letter-spacing: .07em; color: var(--taupe); font-variant-numeric: tabular-nums;
}

/* =====================================================
   GAMME — FRAGRANCE PYRAMID (page-aromatherapie.php)

   Tête / cœur / fond, transcribed from the brand's own NOTAS PRINCIPALES
   plate. Laid out as three stacked tiers so the structure of the scent is
   visible at a glance, which is what turns a name into something sellable.
   ===================================================== */
.page-gamme .gm-notes {
  max-width: 660px; margin: 0 auto 58px; padding-left: 0; list-style: none;
  border-top: 1px solid var(--line);
}
.page-gamme .gm-note {
  display: grid; grid-template-columns: 92px 1fr; gap: 20px; align-items: baseline;
  padding: 17px 0; border-bottom: 1px solid var(--line);
}
.page-gamme .gm-note-tier {
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase; color: var(--accent);
  font-weight: 500;
}
.page-gamme .gm-note-items {
  font-family: var(--serif); font-size: clamp(16px, 1.7vw, 21px); line-height: 1.5; color: var(--black);
}

@media (max-width: 1024px) {
  .page-gamme .gm-num-grid { grid-template-columns: 1fr; padding: 100px 8vw; }
  .page-gamme .gm-num-text { text-align: center; }
  .page-gamme .gm-num-text p { margin-left: auto; margin-right: auto; }
}
@media (max-width: 768px) {
  .page-gamme .gm-num-grid { padding: 80px 6vw; }
  .page-gamme .gm-shades { grid-template-columns: repeat(auto-fill, minmax(138px, 1fr)); }
  .page-gamme .gm-note { grid-template-columns: 1fr; gap: 6px; }
}

@media (prefers-reduced-motion: reduce) {
  .page-gamme .gm-wall li,
  .page-gamme .gm-shade { transition: none; }
  .page-gamme .gm-wall.in li { animation: none; }
  .page-gamme .gm-wall li:hover { transform: none; }
}

/* =====================================================
   GALERIE (page-galerie.php)

   Editorial grid built with explicit spans rather than a masonry library —
   the rhythm is authored, not computed, and nothing depends on JS to lay out.
   ===================================================== */

.page-galerie .gal-hero {
  background: var(--bg);
  padding: clamp(120px, 15vw, 190px) 8vw clamp(56px, 7vw, 90px);
}
.page-galerie .gal-hero-inner { max-width: var(--container); margin: 0 auto; }
.page-galerie .gal-hero-title {
  font-family: var(--serif); font-weight: 300;
  font-size: clamp(40px, 6.4vw, 88px); line-height: 1.06;
  letter-spacing: -0.01em; margin-bottom: 26px;
}
.page-galerie .gal-hero-title em { font-style: italic; color: var(--gold); }
.page-galerie .gal-hero-lede {
  max-width: 560px; font-size: 15px; line-height: 1.8; color: var(--taupe);
}

.page-galerie .gal-grid-sec { background: var(--bg); padding: 0 8vw clamp(70px, 9vw, 130px); }
.page-galerie .gal-grid {
  display: grid; grid-template-columns: repeat(6, 1fr);
  gap: clamp(20px, 2.6vw, 40px);
  max-width: var(--container); margin: 0 auto;
  padding-left: 0; list-style: none;
}
/* 6-column base: a portrait card takes 2, a landscape one 3. Two different
   widths are enough to break the grid read without the layout going ragged. */
.page-galerie .gal-item--tall { grid-column: span 2; }
.page-galerie .gal-item--wide { grid-column: span 3; }

/* The sources run from 611x784 portrait to 1080x1080 square. Left at their
   natural heights the grid rows size to the tallest card and open ragged gaps
   beside the short ones, so each span gets a fixed ratio and the photo is
   cropped to fill it. Rows then align and the varied crops read as authored. */
.page-galerie .gal-media {
  overflow: hidden; background: var(--grey);
  margin-bottom: 18px;
}
.page-galerie .gal-item--tall .gal-media { aspect-ratio: 3 / 4; }
.page-galerie .gal-item--wide .gal-media { aspect-ratio: 4 / 3; }
.page-galerie .gal-media img {
  width: 100%; height: 100%; display: block; object-fit: cover;
  transition: transform .8s cubic-bezier(.16,1,.3,1);
}
.page-galerie .gal-item:hover .gal-media img { transform: scale(1.045); }

.page-galerie .gal-kind {
  display: block; font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--gold); margin-bottom: 9px;
}
.page-galerie .gal-name {
  font-family: var(--serif); font-weight: 300;
  font-size: clamp(21px, 2.1vw, 30px); line-height: 1.2; margin-bottom: 9px;
}
.page-galerie .gal-text {
  font-size: 13.5px; line-height: 1.75; color: var(--taupe); max-width: 46ch;
}

.page-galerie .gal-cta { background: var(--white); text-align: center; }
.page-galerie .gal-cta-inner { max-width: 620px; margin: 0 auto; }
.page-galerie .gal-cta h2 {
  font-family: var(--serif); font-weight: 300;
  font-size: clamp(30px, 3.9vw, 52px); line-height: 1.14; margin-bottom: 18px;
}
.page-galerie .gal-cta h2 em { font-style: italic; color: var(--gold); }
.page-galerie .gal-cta p { font-size: 15px; color: var(--taupe); margin-bottom: 40px; }

@media (max-width: 1024px) {
  .page-galerie .gal-grid { grid-template-columns: repeat(4, 1fr); }
  .page-galerie .gal-item--tall { grid-column: span 2; }
  .page-galerie .gal-item--wide { grid-column: span 2; }
}
@media (max-width: 700px) {
  .page-galerie .gal-hero { padding-left: 6vw; padding-right: 6vw; }
  .page-galerie .gal-grid-sec { padding-left: 6vw; padding-right: 6vw; }
  .page-galerie .gal-grid { grid-template-columns: 1fr; }
  .page-galerie .gal-item--tall,
  .page-galerie .gal-item--wide { grid-column: span 1; }
}
@media (prefers-reduced-motion: reduce) {
  .page-galerie .gal-media img { transition: none; }
  .page-galerie .gal-item:hover .gal-media img { transform: none; }
}

/* ---------- Contact: person block, stacked phones, split hours ---------- */
/* Two phone numbers now sit in one detail block; the shared rule renders <a>
   inline, so without this they run together on one line. */
.page-contact .contact-detail-body a { display: block; }
.page-contact .contact-detail-body .contact-person {
  font-family: var(--serif); font-size: 21px; line-height: 1.35;
  color: var(--black); font-weight: 400;
}
.page-contact .contact-detail-body .contact-person .contact-detail-muted {
  font-family: var(--sans); font-size: 11px; letter-spacing: 0.16em;
  text-transform: uppercase; opacity: 1; color: var(--gold);
}
.page-contact .contact-detail-body .contact-hours-sat {
  margin-top: 10px; padding-top: 10px;
  border-top: 1px solid rgba(10,10,10,0.07);
}

/* Wall items share one box so mixed pack formats align on a common baseline.
   Without this a 560x228 candle box renders 44x18 next to a 371x900 bottle at
   44x107, and the row reads as broken rather than as a range. Only the facial
   gamme is genuinely all one cylinder; every other gamme mixes tubs, cartons
   and bottles, so the shared box is what makes them scan as a set. */
.page-gamme .gm-range-wall li { height: clamp(64px, 7.2vw, 108px); }
.page-gamme .gm-range-wall img {
  height: 100%; object-fit: contain; object-position: bottom;
}

/* =====================================================
   [A11Y-TAPTARGETS] WCAG 2.5.8 — minimum 44x44px touch targets
   -----------------------------------------------------
   Measured on the live site at 390x844: the hamburger resolved to 30x23px and
   every off-canvas nav link to 144x20px — i.e. the entire primary means of
   navigating the site on a phone was below the touch minimum. These rules grow
   the HIT AREA only; the visible hamburger bars stay 22px wide as designed, they
   are just centred inside a 44x44 box now.
   ===================================================== */
@media (max-width: 1199.98px) {

  #kuos-header .navbar-toggler {
    min-width: 44px; min-height: 44px;
    padding: 0 !important;
    align-items: center; justify-content: center;
  }

  /* Nav links and the Services dropdown items alike — the dropdown children were
     the worst offenders because the menu's own padding override zeroed theirs. */
  #kuos-header .nav-link,
  #kuos-header .dropdown-item,
  #kuos-header .dropdown-item--sub {
    min-height: 44px;
    display: flex; align-items: center;
  }

  /* The group label is a <span>, not a link — it must NOT get a tap target, or it
     reads as interactive when it isn't. Height matched for rhythm only. */
  #kuos-header .dropdown-item--group { min-height: 40px; display: flex; align-items: center; }

  .lang-switch-link { min-height: 44px; display: inline-flex; align-items: center; }
  #kuos-header .nav-social-link { min-width: 44px; min-height: 44px; }

  /* The logo is the "go home" affordance on mobile and measured 90x32. */
  #kuos-header .navbar-brand.site-logo { min-height: 44px; display: flex; align-items: center; }
}

/* Footer navigation — every link measured 144x20. These are ordinary text links
   in a stacked column, so the 44px comes from line-box height plus the existing
   11px rhythm, not from a box: the visual spacing is unchanged, the hit area
   grows to meet it. Applies at all widths — the footer is a single column on
   mobile and the targets were undersized on desktop pointers too. */
.footer-col a {
  min-height: 44px;
  display: flex;
  align-items: center;
  margin-bottom: 0;
}

/* .is-soon links are aria-disabled placeholders (tabindex="-1"), so they are not
   reachable targets and must not advertise themselves as tappable. Kept in the
   flow at the same rhythm, without the enlarged hit area. */
.footer-col a.is-soon {
  min-height: 0;
  display: block;
  margin-bottom: 11px;
  cursor: default;
}

/* Newsletter form — input measured 343x21, submit 343x17. The visual design is a
   single hairline-underlined row, so height is added via padding rather than a box. */
.news-form input,
.news-form button {
  min-height: 44px;
}
.news-form { padding-bottom: 6px; }

/* Marquee pause controls (32x32) — WCAG 2.2.2 pause affordance, so it has to be
   reachable, not just present. */
.marquee-pause-btn { min-width: 44px; min-height: 44px; }


/* =====================================================
   [A11Y-CONTRAST] WCAG 1.4.3 — gold used as SMALL text
   -----------------------------------------------------
   --gold (#C9A96E) is the brand accent and is deliberately left untouched for
   rules, borders, icon circles, hover states and large display type (the italic
   <em> in every section heading), where it either isn't text or clears the 3:1
   large-text threshold.
   As small text on a light ground it does not pass: measured 2.24:1 on #FFF and
   2.11:1 on the cream #FAF8F5 — against a 4.5:1 floor.
   --gold-text is the SAME hue and saturation with lightness dropped to 0.378:
   4.83:1 on white, 4.55:1 on cream. Reach for it on any gold text under ~19px.
   It also supersedes the one-off #9A7A4A on .ing-num, which was itself only
   3.99:1 and never actually passed.
   Selectors below are the exhaustive set measured as failing on the live site —
   do not blanket-apply this to .eyebrow, which is --taupe, nor to anything
   sitting on hero photography (that is [A11Y-HERO-SCRIM]'s job).
   ===================================================== */
:root { --gold-text: #8C6D34; }

.ing-num,
.trust-bar-pct,
.news-form button,
.news-form-msg,
.news-popup-msg,
.page-nous .nous-tl-year,
.page-nous .nous-tl-item--highlight h3,
.page-nous .nous-cert-panel-label,
.page-galerie .gal-kind,
.page-contact .contact-form-msg,
.page-contact .contact-detail-body .contact-person .contact-detail-muted {
  color: var(--gold-text);
}

/* Header dropdown: the current-page marker. Bootstrap owns .active/:focus/:active
   here (see the note further up), so this has to match that specificity and carry
   !important the same way, or the gold reverts. */
#kuos-header .dropdown-item:hover,
#kuos-header .dropdown-item:focus,
#kuos-header .dropdown-item:active,
#kuos-header .dropdown-item.active,
#kuos-header .dropdown-item:focus-visible {
  color: var(--gold-text) !important;
}

/* Contact page — remaining WCAG 2.5.8 targets measured at 390x844.
   These are the page's primary conversion affordances (tap-to-call, tap-to-mail,
   the map link and the form itself), so undersized targets cost more here than
   anywhere else on the site. */
.page-contact .contact-detail-body a,
.page-contact .contact-map-link {
  min-height: 44px;
  display: flex;
  align-items: center;
}
.page-contact .contact-social-links a {
  min-width: 44px;
  min-height: 44px;
}
.page-contact .contact-field input,
.page-contact .contact-field textarea,
.page-contact .contact-form button[type="submit"] {
  min-height: 44px;
}
