/* ==========================================================================
   Le Taillant — SHARED base stylesheet (both sites)
   Every reusable component (type scale, buttons, header, footer, cards,
   sections, forms) lives here, styled ONLY through the design tokens that
   theme.css defines per site. Never hard-code a brand color, font or shadow
   tint here — add a token to BOTH theme.css files instead.
   Canonical copy: 03_SITE_WEB/_shared/assets/css/base.css — edit it there
   and run sync-shared.sh; never edit this per-site copy directly.
   ========================================================================== */

/* ============ Structural tokens (shared, identical on both sites) ============ */
:root {
  --universal-margin: .375em;
  --universal-padding: .375em;
  --universal-border-radius: 1.25em;
  --container-padding: clamp(16px, 4vh, 48px);

  --btn-fill: var(--back-color);
  --btn-fill-secondary: var(--fore-color);
  --btn-text: var(--fore-color);
  --btn-text-secondary: var(--back-color);
  /* --btn-radius is intentionally NOT set here — each site's theme.css
     defines its own (couteaux: small/square; ciseaux: pill), so this must
     resolve via var(--btn-radius, <fallback>) wherever it's used below,
     never assumed to exist. */

  --ease-out-soft: cubic-bezier(.22, 1, .36, 1);
}

@media (min-width: 375px) {
  :root {
    --universal-margin: .5em;
    --universal-padding: .5em;
    --container-padding: 5vw;
  }
}

* { box-sizing: border-box; }
html { font-size: 14px; scroll-behavior: smooth; }
/* #reserver (atelier.php's booking calendar) — clears the fixed header pill
   when jumped to via an in-page anchor (nav CTA, hero CTA, sticky mobile
   bar), same idea as .gallery-sticky's padding-top. */
#reserver { scroll-margin-top: 6rem; }
@media (min-width: 375px) { html { font-size: 16px; } }
@media (min-width: 768px)  { html { font-size: 17px; } }
@media (min-width: 1280px) { html { font-size: 18px; } }

html, body {
  font-family: var(--font-body);
  font-weight: 300;
  line-height: 1.5;
  background: var(--paper);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}

::selection { background: var(--e1-color); color: var(--fore-color); }

/* ============ Type scale (fd1–fd8) ============
   fd5/fd6 (section and hero headings) carry the display voice in the site's
   --font-display; everything else (labels, card titles, body, buttons) stays
   in --font-body — two voices, not a costume change. Both faces are set per
   site in theme.css. */
.fd1,.fd2,.fd3,.fd4,.fd5,.fd6,.fd7,.fd8 { margin: 0; }
.fd1 { font-size: calc(.55em * 1.275); font-weight: 400; letter-spacing: .16em; line-height: 1; text-transform: uppercase; }
.fd2 { font-size: calc(.85em * 1.275); font-weight: 500; line-height: 1.4; }
.fd3 { font-size: calc(1.5em * 1.275); font-weight: 400; letter-spacing: -.04em; line-height: 1.2; }
.fd4 { font-size: calc(1.375em * 1.275); font-weight: 500; letter-spacing: -.04em; line-height: 1.15; }
/* --heading-font / --heading-weight let a site swap fd5/fd6 away from
   --font-display without forcing the other site to follow — unset on a
   site, these fall back to the original --font-display / 500 behavior. */
.fd5 { font-family: var(--heading-font, var(--font-display)); font-size: calc(2em * 1.275); font-weight: var(--heading-weight, 500); letter-spacing: -.01em; line-height: 1.08; }
.fd6 { font-family: var(--heading-font, var(--font-display)); font-size: calc(3.5em * 1.275); font-weight: var(--heading-weight, 500); letter-spacing: -.015em; line-height: .98; }

/* Manually applied to a FEW hand-picked accent moments (a hero word, a
   pull-quote) — never a whole heading tier. Always --font-display, so a
   site that keeps --font-display as its heading font (e.g. via no
   --heading-font override) simply gets the same face here, no visual jump. */
.accent-serif { font-family: var(--font-display); font-style: italic; }
.fd7 { font-size: calc(.85em * 1.275); font-weight: 700; letter-spacing: .1em; line-height: 1; text-transform: uppercase; }
.fd8 { font-size: .85em; font-weight: 300; line-height: 1.5; }

@media (max-width: 640px) {
  .fd6 { font-size: calc(2.35em * 1.275); }
  .fd5 { font-size: calc(1.6em * 1.275); }
  .fd4 { font-size: calc(1.2em * 1.275); }
  .fd3 { font-size: calc(1.3em * 1.275); }
}

.container-x { padding-left: var(--container-padding); padding-right: var(--container-padding); }
.eyebrow-accent { color: var(--e1-color); }

/* ============ Links: underlined only inside body-copy paragraphs ============
   Nav items, buttons, cards and footer lists stay clean (no underline);
   an inline link inside a flowing sentence gets one so it still reads as a link. */
a { text-decoration: none; }
p a { text-decoration: underline; text-underline-offset: .15em; }

/* ============ Buttons (two-layer pill, per design system) ============ */
.button {
  background-color: var(--btn-fill);
  background-image: linear-gradient(180deg, rgba(255,255,255,.25), rgba(255,255,255,0));
  color: var(--btn-text);
  text-align: center;
  letter-spacing: .02em;
  white-space: nowrap;
  border-radius: var(--btn-radius, 32rem);
  display: inline-flex;
  justify-content: center;
  align-items: center;
  width: fit-content;
  padding: .125rem;
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 500;
  line-height: 1em;
  text-decoration: none;
  position: relative;
  border: none;
  cursor: pointer;
  transition: transform .3s var(--ease-out-soft), box-shadow .3s var(--ease-out-soft);
}
.button-inner {
  background-color: var(--btn-fill);
  border-radius: var(--btn-radius, 32rem);
  display: flex;
  justify-content: center;
  align-items: center;
  gap: .5em;
  width: 100%;
  height: 100%;
  padding: 1.05rem 2.5rem;
  position: relative;
  overflow: hidden;
  white-space: nowrap;
}
.button.is--accent { --btn-fill: var(--e1-color); }
.button.is--secondary {
  background-color: var(--btn-fill-secondary);
  background-image: linear-gradient(rgba(0,0,0,0), rgba(0,0,0,.18));
  color: var(--btn-text-secondary);
}
.button.is--secondary .button-inner { background-color: var(--btn-fill-secondary); }
.button.is--ghost {
  background-color: transparent;
  background-image: none;
  color: var(--ink);
  border: 1px solid var(--hairline);
  padding: 0;
}
.button.is--ghost .button-inner { background-color: transparent; padding: 1rem 2.25rem; }
.button.is--ghost.on-dark { color: var(--fore-color); border-color: var(--hairline-dark); }
.button.is--sm .button-inner { padding: .7rem 1.6rem; font-size: .92rem; }

.button--shadow {
  position: absolute; inset: 0; border-radius: var(--btn-radius, 32rem); pointer-events: none;
  box-shadow:
    0 1.375rem .375rem rgba(20,20,20,0),
    0 .875rem .375rem rgba(20,20,20,.02),
    0 .5rem .3125rem rgba(20,20,20,.06),
    0 .25rem .25rem rgba(20,20,20,.11),
    0 .0625rem .125rem rgba(20,20,20,.12);
  transition: box-shadow .35s var(--ease-out-soft);
}
.button:hover .button--shadow {
  box-shadow:
    0 5.6875rem 1.5625rem rgba(20,20,20,0),
    0 3.625rem 1.4375rem rgba(20,20,20,.04),
    0 2.0625rem 1.25rem rgba(20,20,20,.13),
    0 .9375rem .9375rem rgba(20,20,20,.16),
    0 .25rem .5rem rgba(var(--e1-rgb),.22);
}
.button:hover { transform: translateY(-3px); }
.button:active { transform: translateY(-1px) scale(.98); }
.button:focus-visible {
  outline: 2px solid var(--e1-color);
  outline-offset: 3px;
}

/* ============ Depth / surfaces ============ */
.surface-card {
  background: var(--paper-raised);
  border-radius: var(--universal-border-radius);
  border: 1px solid var(--hairline);
  box-shadow:
    0 1px 1px rgba(var(--ink-rgb),.02),
    0 8px 16px -8px rgba(var(--ink-rgb),.06),
    0 24px 48px -24px rgba(var(--ink-rgb),.10);
  transition: transform .35s var(--ease-out-soft), box-shadow .35s var(--ease-out-soft), border-color .35s var(--ease-out-soft);
}
.surface-card.is--floating:hover {
  transform: translateY(-6px);
  border-color: rgba(var(--e1-rgb),.35);
  box-shadow:
    0 1px 1px rgba(var(--ink-rgb),.02),
    0 16px 24px -10px rgba(var(--ink-rgb),.10),
    0 40px 64px -24px rgba(var(--e1-rgb),.18);
}

/* ============ Grain texture (used on dark sections) ============ */
.grain { position: relative; isolation: isolate; }
.grain::after {
  content: "";
  position: absolute; inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.35'/></svg>");
  opacity: .05;
  pointer-events: none;
  mix-blend-mode: overlay;
  z-index: 1;
}
.grain > * { position: relative; z-index: 2; }

/* ============ Header (floating rounded bar) ============ */
#site-header-wrap {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  display: flex; justify-content: center;
  padding: 1.1rem var(--container-padding) 0;
  pointer-events: none;
}
#site-header {
  pointer-events: auto;
  width: 100%; max-width: 1360px;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; column-gap: 1rem;
  padding: .6rem 1rem;
  border-radius: 1.6em;
  background-color: rgba(var(--ink-rgb),.6);
  border: 1px solid rgba(255,255,255,.09);
  backdrop-filter: blur(16px) saturate(150%);
  -webkit-backdrop-filter: blur(16px) saturate(150%);
  box-shadow: 0 1px 1px rgba(0,0,0,.1), 0 18px 36px -18px rgba(0,0,0,.55);
  transition: background-color .4s var(--ease-out-soft), box-shadow .4s var(--ease-out-soft), transform .4s var(--ease-out-soft);
}
#site-header.is-scrolled {
  background-color: rgba(var(--ink-rgb),.86);
  box-shadow: 0 1px 1px rgba(0,0,0,.15), 0 24px 48px -16px rgba(0,0,0,.65);
  transform: translateY(-2px) scale(.99);
}

.brand { justify-self: start; display: flex; align-items: center; }

/* Brand mark in the round badge — same on every breakpoint, desktop and mobile alike */
.brand-icon {
  display: flex; align-items: center; justify-content: center;
  width: 2.9rem; height: 2.9rem; border-radius: 50%;
  background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.08);
  transition: background-color .25s ease, transform .3s var(--ease-out-soft);
}
.brand-icon:hover { background: rgba(255,255,255,.12); transform: scale(1.05); }
.brand-icon img { height: 1.6rem; width: auto; display: block; filter: invert(1) brightness(1.6); }
.brand:hover .brand-icon { opacity: .85; }

/* Explicit grid-column, not just DOM order — #site-header's 3 children
   (.brand, nav.desktop-nav, .header-actions) rely on CSS Grid
   auto-placement to land in the 3 `1fr auto 1fr` columns. Below 900px
   nav.desktop-nav becomes display:none, which REMOVES it from grid flow
   entirely — auto-placement then slots .header-actions into the now-empty
   middle column instead of the 3rd one, leaving the real 3rd column empty
   and .header-actions sitting mid-header instead of flush right (Arnaud
   2026-08-22: "the language button... not [flush right] on mobile").
   Pinning both ends explicitly makes the layout immune to either child
   being hidden. */
.brand { grid-column: 1; }
.header-actions { grid-column: 3; justify-self: end; }
.desktop-nav { justify-self: center; }


.nav-link {
  color: rgba(255,255,255,.82); text-decoration: none; font-size: .95rem; font-weight: 500;
  position: relative; padding: .4em 0;
  transition: color .25s var(--ease-out-soft);
}
.nav-link::after {
  content: ""; position: absolute; left: 0; bottom: -2px; height: 1px; width: 100%;
  background: var(--e1-color); transform: scaleX(0); transform-origin: left;
  transition: transform .3s var(--ease-out-soft);
}
.nav-link:hover, .nav-link:focus-visible { color: var(--fore-color); }
.nav-link:hover::after, .nav-link:focus-visible::after { transform: scaleX(1); }
.nav-link:focus-visible { outline: none; }
.nav-link[aria-current="page"] { color: var(--fore-color); }
.nav-link[aria-current="page"]::after { transform: scaleX(1); }

.nav-dropdown { position: relative; }
/* Invisible bridge over the gap between the trigger and the panel — without it,
   the mouse crosses a dead zone on the way down and :hover drops before the
   panel is reached, so the menu closes right as you try to click an item. */
.nav-dropdown::after {
  content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  width: 220px; height: .9rem;
}
.nav-dropdown-panel {
  position: absolute; top: calc(100% + .9rem); left: 50%; transform: translateX(-50%) translateY(-6px);
  background: var(--back-color); border: 1px solid var(--hairline-dark); border-radius: 1em;
  padding: .5rem; min-width: 220px;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .25s var(--ease-out-soft), transform .25s var(--ease-out-soft);
  box-shadow: 0 24px 48px -16px rgba(0,0,0,.5);
}
.nav-dropdown:hover .nav-dropdown-panel,
.nav-dropdown:focus-within .nav-dropdown-panel {
  opacity: 1; visibility: visible; pointer-events: auto; transform: translateX(-50%) translateY(0);
}
.nav-dropdown-item {
  display: flex; flex-direction: column; gap: .1em; padding: .7em .9em; border-radius: .6em;
  color: rgba(255,255,255,.85); text-decoration: none; transition: background-color .2s ease;
}
.nav-dropdown-item:hover, .nav-dropdown-item:focus-visible { background: rgba(255,255,255,.06); color: #fff; outline: none; }
.nav-dropdown-item .dd-title { font-size: .92rem; font-weight: 500; }
.nav-dropdown-item .dd-desc { font-size: .76rem; color: var(--secondary-fore-color); }

/* ============ Language switcher (desktop dropdown + mobile row) ============ */
.lang-switch { position: relative; }
.lang-switch-trigger {
  display: flex; align-items: center; gap: .35em;
  background: none; border: 1px solid var(--hairline-dark); border-radius: 32rem;
  color: rgba(255,255,255,.82); font-size: .85rem; font-weight: 500; font-family: inherit;
  padding: .5em .8em; cursor: pointer;
  transition: border-color .25s ease, color .25s ease;
}
.lang-switch-trigger:hover, .lang-switch-trigger:focus-visible { border-color: rgba(255,255,255,.3); color: #fff; outline: none; }
.lang-switch-trigger svg { transition: transform .25s var(--ease-out-soft); }
.lang-switch.is-open .lang-switch-trigger svg,
.lang-switch-trigger[aria-expanded="true"] svg { transform: rotate(180deg); }
.lang-switch-panel {
  position: absolute; top: calc(100% + .6rem); right: 0; min-width: 9rem;
  background: var(--back-color); border: 1px solid var(--hairline-dark); border-radius: 1em; padding: .4rem;
  opacity: 0; visibility: hidden; pointer-events: none; transform: translateY(-6px);
  transition: opacity .25s var(--ease-out-soft), transform .25s var(--ease-out-soft);
  box-shadow: 0 24px 48px -16px rgba(0,0,0,.5);
}
.lang-switch-panel.is-open { opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0); }
.lang-switch-item {
  display: block; padding: .55em .8em; border-radius: .6em; font-size: .88rem;
  color: rgba(255,255,255,.85); text-decoration: none; transition: background-color .2s ease;
}
.lang-switch-item:hover, .lang-switch-item:focus-visible { background: rgba(255,255,255,.06); color: #fff; outline: none; }
.lang-switch-item[aria-current="true"] { color: var(--e2-color); font-weight: 600; }

#mobile-menu-btn {
  display: none; flex-direction: column; gap: 5px; width: 26px; background: none; border: none; cursor: pointer; padding: .5em;
}
#mobile-menu-btn span { display: block; height: 2px; width: 100%; background: #fff; border-radius: 2px; transition: transform .3s var(--ease-out-soft), opacity .3s var(--ease-out-soft); }
#mobile-menu-btn.is-open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
#mobile-menu-btn.is-open span:nth-child(2) { opacity: 0; }
#mobile-menu-btn.is-open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

#mobile-menu {
  position: fixed; inset: 0; z-index: 90; background: var(--back-color);
  display: flex; flex-direction: column; justify-content: center; gap: 1.6rem;
  padding: 2rem var(--container-padding);
  opacity: 0; visibility: hidden; transform: translateY(-12px);
  transition: opacity .35s var(--ease-out-soft), transform .35s var(--ease-out-soft), visibility .35s;
}
#mobile-menu.is-open { opacity: 1; visibility: visible; transform: translateY(0); }
/* :not(.button) — the CTA button at the bottom of this menu is also an <a>,
   but it sets its own text color via the --btn-text variable (inverted to
   navy-on-white by theme.css's dark-surface rule below); this plain white
   was beating that with a hardcoded `color`, same specificity fight
   `.button` always loses against an ID-scoped selector, leaving the button
   invisible (white text on its own white fill). */
#mobile-menu a:not(.button) { color: #fff; font-size: 1.6rem; font-weight: 500; text-decoration: none; }
#mobile-menu .mm-sub { display: flex; flex-direction: column; gap: .6rem; padding-left: 1.2rem; margin-top: -.6rem; }
#mobile-menu .mm-sub a { font-size: 1.05rem; color: var(--secondary-fore-color); font-weight: 400; }

/* Mobile-only language trigger — sits in the header bar itself (same round-badge
   treatment as .brand-icon) so the current language is visible before the menu
   is opened at all, rather than buried inside the mobile menu overlay. */
.lang-switch--mobile { display: none; }
.lang-switch-trigger--mobile {
  display: flex; align-items: center; justify-content: center;
  width: 2.9rem; height: 2.9rem; border-radius: 50%;
  background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.08);
  color: #fff; font-family: inherit; font-size: .78rem; font-weight: 600; letter-spacing: .02em;
  cursor: pointer;
  transition: background-color .25s ease, transform .3s var(--ease-out-soft);
}
.lang-switch-trigger--mobile:hover, .lang-switch-trigger--mobile:focus-visible { background: rgba(255,255,255,.12); outline: none; }
.lang-switch--mobile .lang-switch-trigger--mobile[aria-expanded="true"] { background: rgba(255,255,255,.12); }

@media (max-width: 900px) {
  .desktop-nav { display: none !important; }
  #mobile-menu-btn { display: flex; }
  .lang-switch--mobile { display: block; }
}

/* ============ Hero (light — same mist background as the rest of the page) ============ */
#hero {
  position: relative; min-height: 100svh; display: flex; align-items: flex-end;
  background: var(--paper); color: var(--ink); overflow: hidden;
}
/* A single soft band (paper → white → paper) sweeps across, like a blade pass */
#hero .hero-sheen { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
#hero .hero-sheen::before {
  content: "";
  position: absolute; top: -10%; left: 0; width: 42%; height: 120%;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,.9) 48%, rgba(255,255,255,.9) 52%, transparent);
  transform: translateX(-160%);
  animation: sheen-sweep 7s cubic-bezier(.65,0,.35,1) infinite;
}
@keyframes sheen-sweep {
  0%   { transform: translateX(-160%); }
  24%  { transform: translateX(260%); }
  100% { transform: translateX(260%); }
}
@media (prefers-reduced-motion: reduce) {
  #hero .hero-sheen::before { animation: none; opacity: 0; }
}
/* Shared crossfade-hero-media component — two sites, two content types:
   couteaux uses .hero-media-frames (sharpening process photos), ciseaux
   uses .hero-media-shears (open/closing/closed shear PNGs). Same mechanism
   either way: 3 <picture>-wrapped frames, scroll-driven opacity crossfade,
   desktop-only (see index.php's <picture><source min-width:901px>). */
#hero .hero-media-frames, #hero .hero-media-shears {
  position: absolute; inset: 0; z-index: 0;
  display: flex; align-items: center; justify-content: center;
  pointer-events: none;
}
#hero .hero-media-frames img, #hero .hero-media-shears img {
  position: absolute; height: clamp(16rem, 42vh, 34rem); width: auto;
  object-fit: contain; opacity: 0;
  transition: opacity .22s ease-out;
}
/* Full opacity, not a faint watermark — desktop shows these as real
   images (rounded + shadowed like every other picture on the site, see
   the min-width:901px block below). Harmless on mobile too: below 901px
   each <img> falls back to a 1x1 placeholder (see index.php <picture>),
   so there's nothing to see either way — the real fix for mobile is that
   the .webp/.png never downloads at all. */
#hero .hero-media-frames img.is-active, #hero .hero-media-shears img.is-active { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  /* No scroll-linked flipping for reduced-motion — just the still open frame.
     Each frame is wrapped in its own <picture>, so "first frame" means
     the img inside the first <picture>, not img:first-child (which would
     match all three, one per picture wrapper). */
  #hero .hero-media-frames img, #hero .hero-media-shears img { transition: none; opacity: 0 !important; }
  #hero .hero-media-frames picture:first-child img, #hero .hero-media-shears picture:first-child img { opacity: 1 !important; }
}
/* Desktop: shift the frames out from behind the title to sit in the open
   space to its right (mobile keeps the centered layout, which already reads
   well against the stacked/shorter title there). Constrained to the same
   max-width/padding as .hero-content so its right edge lines up with the
   title column's right edge instead of the full viewport's. */
@media (min-width: 901px) {
  #hero .hero-media-frames, #hero .hero-media-shears {
    justify-content: flex-end;
    max-width: 1360px; margin: 0 auto; padding: 0 var(--container-padding);
  }
  #hero .hero-media-frames img, #hero .hero-media-shears img {
    height: clamp(17.6rem, 46.2vh, 37.4rem);
    /* Explicit position instead of leaning on the flex container's
       justify-content/align-items "static position" fallback for an
       absolutely-positioned child — that fallback overshoots the
       container's own right edge by ~200px (invisible at low opacity,
       obvious once fully visible). .hero-media-frames/-shears is itself
       `position:absolute` (see base rule above), so this resolves against
       ITS padding box, which is what keeps it inside #hero's
       `overflow:hidden` bounds. */
    top: 50%; right: var(--container-padding); left: auto;
    transform: translateY(-50%);
  }
  /* couteaux-only: same treatment as .gallery-item (universal radius +
     layered, ink-tinted shadow) — these are rectangular photos, so a card
     treatment reads correctly. ciseaux's shears are cutout PNGs with a
     transparent background — a rounded/shadowed card behind them shows as
     an unwanted white box (2026-08-22, Arnaud: "je veux juste le PNG
     pure"), so .hero-media-shears deliberately does NOT get this. */
  #hero .hero-media-frames img {
    border-radius: var(--universal-border-radius);
    box-shadow:
      0 1px 1px rgba(var(--ink-rgb),.03),
      0 10px 18px -10px rgba(var(--ink-rgb),.16),
      0 26px 40px -20px rgba(var(--ink-rgb),.16);
  }
  /* Only the homepage hero has an image sitting beside the H1 (:has() scopes
     this away from every other hero, which uses the same .max-w-4xl utility
     at its normal 1008px width with nothing beside it to collide with).
     The generic 1008px column was wide enough for French/English's shorter
     phrasing to render on one line without wrapping, but not Dutch's —
     "Je messen scherp geslepen" rendered ~950px wide at this font-size,
     right up against the image's left edge (~1050px). 44rem forces it to
     wrap onto its own second line instead, with real clearance regardless
     of which language is active. 2026-08-22. */
  #hero:has(.hero-media-frames) .hero-content h1,
  #hero:has(.hero-media-shears) .hero-content h1 {
    max-width: 44rem;
  }
}
#hero .hero-media-tag {
  position: absolute; top: 6.5rem; right: var(--container-padding); z-index: 2;
  display: flex; align-items: center; gap: .55em;
  background: rgba(255,255,255,.6); border: 1px solid var(--hairline);
  backdrop-filter: blur(6px);
  padding: .5em .9em .5em .7em; border-radius: 32rem;
  color: var(--ink-soft); font-size: .72rem; letter-spacing: .06em;
}
#hero .hero-media-tag .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--e1-color); animation: pulse 2.2s var(--ease-out-soft) infinite; }
@keyframes pulse { 0%,100% { opacity: 1; transform: scale(1); } 50% { opacity: .4; transform: scale(1.3); } }

/* Capped at the same 1360px as #site-header so the hero's content column
   lines up with the nav bar and every other centered section instead of
   stretching edge-to-edge on wide screens. */
#hero .hero-content { position: relative; z-index: 2; width: 100%; max-width: 1360px; margin: 0 auto; padding: 9rem var(--container-padding) 4.5rem; }

/* Title → lead paragraph → button row rhythm. Higher specificity than the
   per-instance mb-* utility classes in the markup, so it's the one source
   of truth for hero spacing across all six pages without editing each page. */
#hero .hero-content h1 { margin-bottom: 2rem; }
#hero .hero-content p.fd2 { margin-bottom: 2.75rem; }

/* Lower/shorter hero used on interior pages (services, FAQ, contact) */
#hero.is--interior { min-height: auto; align-items: flex-start; }
#hero.is--interior .hero-content { padding: 10.5rem var(--container-padding) 4rem; }

.badge {
  display: inline-flex; align-items: center; gap: .6em;
  border: 1px solid var(--hairline-dark); border-radius: 32rem;
  padding: .5em 1.1em .5em .5em; font-size: .82rem; color: rgba(255,255,255,.85);
}
.badge .badge-icon {
  display: flex; align-items: center; justify-content: center;
  width: 1.9em; height: 1.9em; border-radius: 50%; background: var(--e1-color); color: #fff; flex-shrink: 0;
}
.badge.on-light { border-color: var(--hairline); color: var(--ink-soft); }

/* Reviews badge is the one badge that's an actual link (through to Google Maps) */
a.badge { transition: border-color .25s ease, background-color .25s ease, transform .3s var(--ease-out-soft); }
a.badge:hover, a.badge:focus-visible { border-color: var(--e1-color); background: rgba(var(--e1-rgb),.06); transform: translateY(-1px); }
.reviews-badge .badge-icon { background: var(--warning-color); color: var(--back-color); }

/* ============ Process steps ============ */
.step-card { position: relative; }
.step-num {
  font-size: calc(2.6em * 1.275); font-weight: 600; letter-spacing: -.04em;
  color: transparent; -webkit-text-stroke: 1.5px rgba(var(--ink-rgb),.18);
  line-height: 1;
}
.step-connector {
  position: absolute; top: 1.9rem; left: calc(100% - .3rem); width: calc(100% - 1.4rem); height: 1px;
  background: repeating-linear-gradient(90deg, var(--hairline) 0 8px, transparent 8px 14px);
}

/* ============ Gallery pin (scroll-jack: vertical scroll drives horizontal pan) ============
   .gallery-pin-wrap is a tall runway with no content of its own height —
   .gallery-sticky pins at the top of the viewport (position: sticky) for
   the whole runway, so scrolling through it visually "locks" the section in
   place while assets/js/app.js's `gallery` component (unchanged logic,
   reads this.$el.offsetHeight = the runway's height) translates the track
   horizontally. Once the runway is exhausted, sticky releases and normal
   page scroll continues below. Height is a compromise: tall enough that
   each image gets real scroll-distance to be seen (the old, much shorter
   section made the pan feel instant), short enough not to feel like a
   forced detour. */
.gallery-pin-wrap { position: relative; height: 260vh; }
.gallery-sticky {
  position: sticky; top: 0; height: 100vh;
  display: flex; flex-direction: column; justify-content: center;
  overflow: hidden;
  padding-top: 6rem; /* clears the fixed header pill, same idea as .is--interior .hero-content */
}
@media (max-width: 640px) {
  .gallery-pin-wrap { height: 180vh; }
}

/* ============ Gallery (zigzag, auto-advances with page scroll — no manual interaction) ============ */
.gallery-scroll {
  position: relative;
  overflow: hidden;
  padding: 1.5rem 0 3rem;
}
.gallery-track {
  display: flex; align-items: flex-start; gap: 1.75rem; width: max-content;
  padding: 0 var(--container-padding);
  will-change: transform;
}
.gallery-item {
  flex: 0 0 auto; width: 15rem;
  border-radius: var(--universal-border-radius);
  overflow: hidden;
  background: var(--paper-raised);
  scroll-snap-align: start;
  box-shadow:
    0 1px 1px rgba(var(--ink-rgb),.03),
    0 10px 18px -10px rgba(var(--ink-rgb),.16),
    0 26px 40px -20px rgba(var(--ink-rgb),.16);
  transition: box-shadow .4s var(--ease-out-soft), transform .4s var(--ease-out-soft);
}
.gallery-item:hover {
  transform: translateY(-6px);
  box-shadow:
    0 1px 1px rgba(var(--ink-rgb),.03),
    0 16px 24px -10px rgba(var(--ink-rgb),.18),
    0 34px 52px -20px rgba(var(--e1-rgb),.22);
}
.gallery-item.is--tall { height: 22rem; margin-top: 0; }
.gallery-item.is--short { height: 22rem; margin-top: 3.25rem; }
.gallery-item img { display: block; width: 100%; height: 100%; object-fit: cover; user-select: none; -webkit-user-drag: none; }
@media (min-width: 640px) {
  .gallery-item { width: 17rem; }
  .gallery-item.is--tall, .gallery-item.is--short { height: 25rem; }
  .gallery-item.is--short { margin-top: 4rem; }
}

/* ============ Pillars ============ */
.pillar-icon {
  width: 3.1rem; height: 3.1rem; border-radius: 1em; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(155deg, rgba(var(--e1-rgb),.14), rgba(var(--e1-rgb),.06));
  color: var(--e1-color); border: 1px solid rgba(var(--e1-rgb),.18);
}

/* ============ Subscription (floating box) ============ */
#abonnement .sub-glow {
  position: absolute; width: 60rem; height: 60rem; border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--e1-rgb),.28), transparent 65%);
  top: -20rem; right: -18rem; z-index: 0; filter: blur(10px);
}
.freq-chip {
  border: 1px solid var(--hairline-dark); border-radius: 32rem; padding: .8em 1.4em;
  display: flex; flex-direction: column; align-items: center; gap: .15em; min-width: 8.5rem;
  transition: border-color .3s ease, background-color .3s ease, transform .3s var(--ease-out-soft);
}
.freq-chip:hover { border-color: var(--e2-color); background: rgba(255,255,255,.04); transform: translateY(-3px); }
.freq-chip b { font-size: 1.3rem; font-weight: 600; }
.freq-chip span { font-size: .72rem; letter-spacing: .1em; text-transform: uppercase; color: var(--secondary-fore-color); }

/* ============ Service cards ============ */
.service-card { display: flex; flex-direction: column; height: 100%; padding: 2.1rem 1.9rem 1.9rem; }
.service-icon {
  width: 3.3rem; height: 3.3rem; border-radius: 1em; display: flex; align-items: center; justify-content: center;
  background: var(--ink); color: #fff; margin-bottom: 1.4rem;
  transition: background-color .3s ease, transform .3s var(--ease-out-soft);
}
.surface-card.is--floating:hover .service-icon { background: var(--e1-color); transform: rotate(-6deg) scale(1.05); }
.price-tag { font-weight: 600; color: var(--e1-color); }

/* ============ Floating dark box (shared by any dark section — footer, abonnement) ============ */
.floating-box-wrap { background: var(--paper); padding: 2.5rem var(--container-padding); position: relative; }
.floating-box {
  background: var(--back-color); color: rgba(255,255,255,.75);
  border-radius: 2.25em; overflow: hidden; position: relative; z-index: 1;
  max-width: 1360px; margin: 0 auto;
}

/* Footer-only: extra room below the card for the watermark to hang into,
   with a hard clip at the page's true bottom edge (see .footer-watermark). */
.footer-watermark-clip { overflow: hidden; padding-bottom: 8.5rem; }
@media (min-width: 768px) {
  .footer-watermark-clip { padding-bottom: 11.5rem; }
}

/* ============ Footer ============ */
#site-footer a { color: rgba(255,255,255,.75); text-decoration: none; transition: color .25s ease; }
#site-footer a:hover, #site-footer a:focus-visible { color: #fff; }
#site-footer p a { text-decoration: underline; text-underline-offset: .15em; }
.footer-heading { color: #fff; font-size: .78rem; letter-spacing: .14em; text-transform: uppercase; font-weight: 600; margin-bottom: 1rem; }

/* Brand column (logo + tagline + seal + socials) vs. the nav-column group —
   a 2-track grid rather than one flat 4-column row, so the nav columns can
   be centered as their own block within the space beside the brand column
   instead of being spread edge-to-edge with it. align-items:start keeps
   every column top — including the nav-column headings — level with the
   top of the logo, regardless of how much content each column holds. */
.footer-top { display: grid; grid-template-columns: 1fr; gap: 3rem; align-items: start; }
@media (min-width: 768px) {
  .footer-top { grid-template-columns: minmax(auto, 22rem) 1fr; gap: 2rem; }
}

.footer-nav-cols { display: grid; grid-template-columns: 1fr; gap: 2.5rem; align-items: start; }
@media (min-width: 768px) {
  .footer-nav-cols { grid-template-columns: repeat(3, 11rem); gap: 3.5rem; justify-content: center; }
}

/* Footer logo — 2/3 the width of the paragraph column below it (20rem), so
   it reads as a lockup with the description text rather than a full-width banner.
   Tight margin-bottom keeps it close to the tagline directly under it. */
.footer-logo-link { display: inline-block; margin-bottom: .6rem; }
.footer-logo { width: 13.3rem; max-width: 100%; height: auto; display: block; filter: invert(1) brightness(1.6); }

/* Certification seal, lockup'd with the brand mark rather than buried in a
   link list — a trust mark reads strongest next to the identity it backs,
   and this is the one footer element every page shares. Linked through to
   the verified profile on lesartisans.be. */
.footer-artisan-badge { display: flex; align-items: center; gap: .7em; margin-top: 1.1rem; width: fit-content; }
.footer-artisan-badge img { width: 2.6rem; height: 2.6rem; flex-shrink: 0; }
.footer-artisan-badge span { color: rgba(255,255,255,.75); max-width: 12rem; transition: color .25s ease; }
.footer-artisan-badge:hover span, .footer-artisan-badge:focus-visible span { color: #fff; }

/* Background watermark — massive wordmark hanging just below the footer
   card, coming up from the very bottom of the page. Only its top ~75% is
   visible: .footer-watermark-clip's overflow:hidden hard-cuts the bottom
   quarter off at the page's true edge instead of fading it out. A mask
   gradient fades it in from transparent at its own top toward a low
   opacity ceiling, so it stays a quiet, barely-there mark rather than a
   bold ghost. Sized off height (not width) so it stays anchored low and
   never grows tall enough to climb up into the nav columns above it. */
.footer-watermark {
  position: absolute; left: 50%; bottom: -2.75rem; transform: translateX(-50%);
  height: 11rem; width: auto; max-width: none;
  opacity: .09; pointer-events: none; z-index: 0; user-select: none;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, black 100%);
}
@media (min-width: 768px) {
  .footer-watermark { height: 15rem; bottom: -3.75rem; }
}

.social-btn {
  width: 2.6rem; height: 2.6rem; border-radius: 50%; border: 1px solid var(--hairline-dark);
  display: flex; align-items: center; justify-content: center; color: #fff;
  transition: border-color .25s ease, background-color .25s ease, transform .3s var(--ease-out-soft);
}
.social-btn:hover { border-color: var(--e1-color); background: rgba(var(--e1-rgb),.12); transform: translateY(-2px); }

/* ============ Booking embed (Google Calendar appointment schedules) ============
   The widget's own scroll area is boxed inside a clearly-bordered card so it
   reads as "a scrollable thing", not the page itself — and overscroll-behavior
   stops a scroll that hits the top/bottom of the widget from also dragging the
   whole page with it, which is what made mobile navigation feel ambiguous. */
.booking-embed {
  border-radius: var(--universal-border-radius);
  overflow: hidden;
  border: 1px solid var(--hairline-dark);
  background: #fff;
  box-shadow: 0 24px 48px -24px rgba(0,0,0,.5);
  overscroll-behavior: contain;
}
.booking-embed iframe {
  display: block; width: 100%; border: 0;
  height: 640px;
  overscroll-behavior: contain;
}
@media (max-width: 640px) {
  .booking-embed iframe { height: 62vh; min-height: 420px; max-height: 560px; }
}
/* Placeholder state shown until a real Google Calendar / Calendly appointment
   link is wired in — same card treatment as the real embed so the layout
   doesn't jump once the iframe is added, just centered explanatory text
   instead of a live widget. */
.booking-embed.is--empty {
  display: flex; align-items: center; justify-content: center; text-align: center;
  padding: 2.5rem; min-height: 420px;
}
.booking-hint {
  display: flex; align-items: center; gap: .5em;
  font-size: .78rem; color: var(--secondary-fore-color); margin-bottom: .9rem;
}
.booking-hint svg { flex-shrink: 0; }

/* ============ Logo marquee (partner/client logos, e.g. professionnels.php) ============
   The logo list is duplicated once in the markup so a 50%-width translateX
   loops seamlessly; reduced-motion gets a plain scrollable strip instead. */
.logo-marquee-wrap {
  overflow: hidden; position: relative;
  -webkit-mask-image: linear-gradient(90deg, transparent, black 8%, black 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, black 8%, black 92%, transparent);
}
.logo-marquee-track {
  display: flex; align-items: center; gap: 3.5rem; width: max-content;
  animation: logo-scroll 32s linear infinite;
}
.logo-marquee-wrap:hover .logo-marquee-track { animation-play-state: paused; }
/* Fixed-size box, not content-sized — the old `flex:0 0 auto` + `width:auto`
   combo sized each item purely from its own <img>'s rendered dimensions,
   which depend on load timing (these are loading="lazy"): mid-load or on a
   slow connection the box has nothing to size itself from and collapses to
   0 width (invisible logos), or briefly renders at native/attribute size
   before object-fit applies (oversized, edges clipped by the marquee's own
   overflow:hidden). A stable box + max-height/max-width on the img (never
   just height/width) fixes both regardless of load state. 2026-08-22. */
.logo-marquee-item { flex: 0 0 auto; width: 9rem; height: 3.25rem; display: flex; align-items: center; justify-content: center; }
.logo-marquee-item img {
  max-height: 100%; max-width: 100%; width: auto; height: auto; object-fit: contain;
  filter: grayscale(1) opacity(.55); transition: filter .3s ease;
}
.logo-marquee-item img:hover { filter: grayscale(0) opacity(1); }
@keyframes logo-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) {
  .logo-marquee-wrap { mask-image: none; -webkit-mask-image: none; }
  .logo-marquee-track { animation: none; overflow-x: auto; padding-bottom: .5rem; }
}

/* ============ Review carousel (Trustindex embed host) ============ */
.review-carousel-placeholder {
  display: flex; align-items: center; justify-content: center; text-align: center;
  padding: 3rem 2rem; min-height: 220px;
  border-radius: var(--universal-border-radius); border: 1px dashed var(--hairline);
  background: var(--paper-raised);
}

/* ============ Reviews carousel (real, auto-scrolling Google review cards) ============
   Same duplicated-track / seamless-loop technique as .logo-marquee above,
   sized for review copy instead of a logo strip. Pauses on hover so a
   review is easy to actually read; reduced-motion gets a plain scrollable
   row instead of the marquee animation. */
.reviews-marquee-wrap {
  overflow: hidden; position: relative;
  -webkit-mask-image: linear-gradient(90deg, transparent, black 6%, black 94%, transparent);
  mask-image: linear-gradient(90deg, transparent, black 6%, black 94%, transparent);
}
.reviews-marquee-track {
  display: flex; align-items: stretch; gap: 1.5rem; width: max-content;
  animation: reviews-scroll 50s linear infinite;
}
.reviews-marquee-wrap:hover .reviews-marquee-track { animation-play-state: paused; }
.review-card {
  flex: 0 0 auto; width: 20rem; padding: 1.9rem 1.75rem;
  display: flex; flex-direction: column; gap: 1.1rem;
}
.review-card-stars { display: flex; gap: .2em; color: var(--warning-color); }
.review-card-stars svg { width: 13px; height: 13px; }
.review-card-text { color: var(--ink-soft); line-height: 1.65; flex: 1; }
.review-card-author { display: flex; align-items: center; gap: .7em; }
.review-card-avatar {
  width: 2.3rem; height: 2.3rem; border-radius: 50%; flex-shrink: 0;
  background: var(--ink); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: .8rem; font-weight: 600;
}
.review-card-name { font-weight: 500; font-size: .92rem; line-height: 1.3; }
.review-card-date { font-size: .74rem; color: var(--ink-soft); }
@keyframes reviews-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) {
  .reviews-marquee-wrap { mask-image: none; -webkit-mask-image: none; }
  .reviews-marquee-track { animation: none; overflow-x: auto; padding-bottom: .5rem; }
}

/* ============ Price table (tarifs.php) ============ */
.price-table-wrap {
  overflow-x: auto;
  border-radius: var(--universal-border-radius);
  border: 1px solid var(--hairline);
  background: var(--paper-raised);
  box-shadow:
    0 1px 1px rgba(var(--ink-rgb),.02),
    0 8px 16px -8px rgba(var(--ink-rgb),.06),
    0 24px 48px -24px rgba(var(--ink-rgb),.10);
}
.price-table { width: 100%; border-collapse: collapse; }
.price-table th, .price-table td { text-align: left; padding: 1.1rem 1.5rem; border-bottom: 1px solid var(--hairline); }
.price-table tbody tr:last-child td { border-bottom: none; }
.price-table thead th {
  font-size: .7rem; text-transform: uppercase; letter-spacing: .08em; font-weight: 600;
  color: var(--ink-soft); background: var(--paper);
}
.price-table tbody tr { transition: background-color .25s ease; }
.price-table tbody tr:hover { background: rgba(var(--e1-rgb),.05); }
.price-table td.price-table-amount { font-weight: 600; color: var(--e1-color); white-space: nowrap; font-variant-numeric: tabular-nums; }
.price-table-amount a { text-decoration: underline; text-underline-offset: .15em; }

/* One or more price tables side by side (e.g. a page with separate
   "knives" / "tools" lists) — stacked on mobile, columns on wide screens. */
.price-table-groups { display: grid; grid-template-columns: 1fr; gap: 2rem; align-items: start; }
@media (min-width: 700px) {
  .price-table-groups.has-2-cols { grid-template-columns: 1fr 1fr; }
}

/* ============ Blog (blog.php / article.php) ============ */
.blog-grid { display: grid; grid-template-columns: 1fr; gap: 1.75rem; }
@media (min-width: 768px) { .blog-grid { grid-template-columns: repeat(3, 1fr); } }
.blog-card { display: block; }
.blog-card-body { display: flex; flex-direction: column; height: 100%; padding: 2.1rem 1.9rem 1.9rem; }
.blog-card-meta {
  font-size: .74rem; letter-spacing: .04em; color: var(--ink-soft);
  margin-bottom: .9rem; font-variant-numeric: tabular-nums;
}
.blog-card-link {
  display: inline-flex; align-items: center; gap: .4em;
  font-size: .88rem; font-weight: 500; color: var(--e1-color); margin-top: auto;
  transition: gap .25s var(--ease-out-soft);
}
.blog-card:hover .blog-card-link { gap: .65em; }
.blog-back-link {
  display: inline-flex; align-items: center; font-size: .85rem; font-weight: 500;
  color: var(--ink-soft); text-decoration: none; transition: color .25s ease;
}
.blog-back-link:hover, .blog-back-link:focus-visible { color: var(--e1-color); }

/* Article prose — the one place long-form copy flows freely instead of
   being broken into fd*-scale fragments by hand. */
.prose { max-width: 42rem; margin: 0 auto; }
.prose h2 {
  font-family: var(--heading-font, var(--font-display)); font-size: calc(1.375em * 1.275); font-weight: 500;
  letter-spacing: -.02em; line-height: 1.2; margin: 2.75rem 0 1.1rem;
}
.prose h2:first-child { margin-top: 0; }
.prose p { margin: 0 0 1.35rem; color: var(--ink-soft); line-height: 1.75; }
.prose ul, .prose ol { margin: 0 0 1.35rem 1.3rem; color: var(--ink-soft); line-height: 1.65; }
.prose li { margin-bottom: .55rem; }
.prose li::marker { color: var(--e1-color); }
.prose strong { color: var(--ink); font-weight: 600; }
.prose a { color: var(--e1-color); text-decoration: underline; text-underline-offset: .15em; }
.prose figure { margin: 1.75rem auto 2.25rem; max-width: 22rem; }
.prose figure img {
  display: block; width: 100%; height: auto;
  border-radius: var(--universal-border-radius);
  border: 1px solid var(--hairline);
  box-shadow:
    0 1px 1px rgba(var(--ink-rgb),.02),
    0 8px 16px -8px rgba(var(--ink-rgb),.06),
    0 24px 48px -24px rgba(var(--ink-rgb),.10);
}
.prose figcaption { margin-top: .65rem; font-size: .82rem; color: var(--ink-soft); text-align: center; }

/* Vertical (Shorts-style) video embed inside article prose — sized for a
   9:16 clip rather than stretched into a 16:9 box like a horizontal embed. */
.prose-video {
  max-width: 20rem; margin: 1.75rem auto 2.25rem;
  aspect-ratio: 9 / 16;
  border-radius: var(--universal-border-radius);
  overflow: hidden;
  border: 1px solid var(--hairline);
  box-shadow:
    0 1px 1px rgba(var(--ink-rgb),.02),
    0 8px 16px -8px rgba(var(--ink-rgb),.06),
    0 24px 48px -24px rgba(var(--ink-rgb),.10);
}
.prose-video iframe { display: block; width: 100%; height: 100%; border: 0; }

/* ============ Interior page building blocks (services, FAQ, contact) ============ */
.faq-item {
  border: 1px solid var(--hairline); border-radius: var(--universal-border-radius);
  background: var(--paper-raised); overflow: hidden;
  transition: border-color .3s ease, box-shadow .3s ease;
}
.faq-item[open] { border-color: rgba(var(--e1-rgb),.3); box-shadow: 0 16px 32px -20px rgba(var(--ink-rgb),.18); }
.faq-item summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 1.25rem 1.5rem; font-weight: 500; font-size: 1.02rem;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary .faq-plus {
  flex-shrink: 0; width: 1.6rem; height: 1.6rem; border-radius: 50%; border: 1px solid var(--hairline);
  display: flex; align-items: center; justify-content: center; position: relative; transition: transform .3s var(--ease-out-soft), background-color .3s ease;
}
.faq-item summary .faq-plus::before, .faq-item summary .faq-plus::after {
  content: ""; position: absolute; background: var(--ink); transition: opacity .2s ease;
}
.faq-item summary .faq-plus::before { width: 9px; height: 1.5px; }
.faq-item summary .faq-plus::after { width: 1.5px; height: 9px; }
.faq-item[open] summary .faq-plus { transform: rotate(45deg); background: var(--e1-color); border-color: var(--e1-color); }
.faq-item[open] summary .faq-plus::before, .faq-item[open] summary .faq-plus::after { background: #fff; }
.faq-item .faq-answer { padding: 0 1.5rem 1.5rem; color: var(--ink-soft); max-width: 46rem; }
.faq-answer a { color: var(--e1-color); text-decoration: underline; text-underline-offset: .15em; }

/* The About entry (faq.php's first, always-open item) — a photo + the
   studio's own story, instead of a plain one-paragraph answer. */
.faq-item--about .faq-answer { max-width: none; }
.faq-about { display: grid; grid-template-columns: 1fr; gap: 1.75rem; }
.faq-about-photos { display: flex; flex-direction: row; gap: .85rem; }
.faq-about-photo { border-radius: calc(var(--universal-border-radius) - .5rem); overflow: hidden; flex-shrink: 0; flex: 1 1 0; }
.faq-about-photo img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 5; object-fit: cover; }
.faq-about-text p { margin: 0 0 1.1rem; line-height: 1.7; }
.faq-about-text p:last-child { margin-bottom: 0; }
@media (min-width: 640px) {
  .faq-about { grid-template-columns: 13rem 1fr; align-items: start; }
  /* flex: 1 1 0 (set above for the mobile side-by-side split, where the
     row-direction container has a definite width to grow into) would
     collapse both photos to 0 height here: column direction + an
     intrinsic-height container means there's no free space to grow into,
     so flex-basis: 0 wins outright. Natural, aspect-ratio-driven height
     instead. */
  .faq-about-photos { flex-direction: column; }
  .faq-about-photos .faq-about-photo { flex: 0 0 auto; }
}

.faq-group-label {
  display: inline-block; margin-bottom: 1.25rem;
}

.info-row {
  display: flex; align-items: flex-start; gap: 1rem;
  padding: 1.25rem 0; border-bottom: 1px solid var(--hairline);
}
.info-row:last-child { border-bottom: none; }
.info-row .info-icon {
  flex-shrink: 0; width: 2.6rem; height: 2.6rem; border-radius: .85em;
  background: linear-gradient(155deg, rgba(var(--e1-rgb),.14), rgba(var(--e1-rgb),.06));
  color: var(--e1-color); display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(var(--e1-rgb),.18);
}
/* Coordonnées as a 2-column grid on desktop — :last-child alone (the mobile
   single-column rule above) only drops the border from item 4, but in a
   2-col layout items 3 AND 4 form the bottom row, so both need it gone. */
@media (min-width: 640px) {
  .contact-coords-grid .info-row:nth-last-child(-n+2) { border-bottom: none; }
}

.contact-map {
  margin-top: 2rem; border-radius: var(--universal-border-radius);
  overflow: hidden; border: 1px solid var(--hairline);
}

/* Team portrait (contact page) — puts a face on the service right next to
   the form. The form's own content sets the row's height (it's reliably the
   taller of the two); the card then stretches to match it (items-stretch on
   the parent grid) with its image filling the extra space. flex-basis:0 on
   the image (not auto) is what makes that direction-of-fit work: with
   `auto`, the browser derives the image's contribution to the row's height
   from its native aspect ratio — for this portrait crop that can outgrow
   the form's own height, flipping who-stretches-to-match-whom and leaving
   dead space in the form. Basis 0 keeps the image's intrinsic contribution
   at ~0 so the form's content height wins, then flex-grow fills the image in. */
.contact-team-card {
  border-radius: var(--universal-border-radius); overflow: hidden;
  background: var(--paper-raised); border: 1px solid var(--hairline);
  box-shadow:
    0 1px 1px rgba(var(--ink-rgb),.03),
    0 10px 18px -10px rgba(var(--ink-rgb),.16),
    0 26px 40px -20px rgba(var(--ink-rgb),.16);
}
.contact-team-card img { display: block; width: 100%; aspect-ratio: 4 / 5; object-fit: cover; object-position: 50% 22%; }
.contact-team-card figcaption { padding: 1.1rem 1.25rem 1.25rem; }
.contact-team-names { font-weight: 600; color: var(--ink); margin-bottom: .2em; }
.contact-team-role { color: var(--ink-soft); }
@media (min-width: 1024px) {
  .contact-team-card { display: flex; flex-direction: column; height: 100%; }
  .contact-team-card img { flex: 1 1 0; min-height: 0; aspect-ratio: auto; }
}

/* Simple form controls (contact page) */
.field-label { display: block; font-size: .82rem; font-weight: 500; margin-bottom: .5em; color: var(--ink); }
.field-input {
  width: 100%; border: 1px solid var(--hairline); border-radius: 1em; background: var(--paper-raised);
  padding: .9rem 1.1rem; font-family: inherit; font-size: 1rem; font-weight: 300; color: var(--ink);
  transition: border-color .25s ease, box-shadow .25s ease;
}
.field-input:focus {
  outline: none; border-color: var(--e1-color);
  box-shadow: 0 0 0 3px rgba(var(--e1-rgb),.14);
}
textarea.field-input { resize: vertical; min-height: 9rem; }
.field-honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.form-alert {
  border-radius: var(--universal-border-radius); padding: 1rem 1.25rem; font-size: .92rem; margin-bottom: 2rem;
}
.form-alert.is--success { background: rgba(76,175,80,.1); border: 1px solid rgba(76,175,80,.35); color: #1f6b23; }
.form-alert.is--error { background: rgba(147,25,4,.08); border: 1px solid rgba(147,25,4,.3); color: var(--e1-color); }

/* fade-up on scroll — visible by default; JS opts elements into the animated state
   so content never depends on JS running (no-JS, crawlers, static captures). */
.reveal { opacity: 1; transform: none; }
html.js .reveal {
  opacity: 0; transform: translateY(18px);
  transition: opacity .7s var(--ease-out-soft), transform .7s var(--ease-out-soft);
}
html.js .reveal.is-visible { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  html.js .reveal { opacity: 1; transform: none; transition: none; }
  * { scroll-behavior: auto !important; }
}

a, button { -webkit-tap-highlight-color: transparent; }
a:focus-visible, button:focus-visible { outline: 2px solid var(--e1-color); outline-offset: 2px; }

/* Alpine safety net: the current components use :class toggling (safe by
   default, nothing hidden until JS decides to hide it), not x-show — but
   this rule is cheap insurance against a flash-of-unstyled-content if a
   future component uses x-show/x-cloak. */
[x-cloak] { display: none !important; }

/* ============ Cookie consent banner ============
   [hidden] wins the specificity fight with flex, so the element genuinely
   collapses instead of being an invisible flex box sitting over content. */
.cookie-consent {
  position: fixed; left: 1rem; right: 1rem; bottom: 1rem; z-index: 200;
  max-width: 34rem; margin: 0 auto;
  background: var(--back-color); color: rgba(255,255,255,.85);
  border-radius: var(--universal-border-radius); padding: 1.25rem 1.5rem;
  box-shadow: 0 24px 48px -16px rgba(0,0,0,.45);
  display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.5rem;
}
.cookie-consent[hidden] { display: none; }
.cookie-consent p { margin: 0; flex: 1 1 16rem; }
.cookie-consent a { color: var(--e2-color); text-decoration: underline; text-underline-offset: .15em; }
.cookie-consent-actions { display: flex; gap: .75rem; flex-shrink: 0; }
.cookie-consent .button.is--ghost { color: rgba(255,255,255,.85); border-color: var(--hairline-dark); }

/* ============ Sticky mobile booking bar — disabled ============
   Was: mirrors the header's accent CTA for thumb reach on small screens,
   shown below 900px since the header's own CTA is hidden there. Removed
   site-wide on both sites per Arnaud, 2026-08-22 ("retire le bouton...
   constamment en bas de l'écran" — a persistent bottom-of-screen button on
   every mobile page was more nuisance than help). Left the component's CSS
   in place (just permanently non-displayed) rather than deleting it, and
   left header.php's markup as-is — cheap to revive later if wanted, and
   nothing to break by removing dead markup right now. */
.sticky-cta { display: none !important; }
.sticky-cta .button { width: 100%; }

/* ============ Breadcrumb trail ============ */
.breadcrumb-nav { font-size: .8rem; color: var(--ink-soft); }
.breadcrumb-nav ol { list-style: none; display: flex; flex-wrap: wrap; align-items: center; gap: .4em; margin: 0; padding: 0; }
.breadcrumb-nav a { color: var(--ink-soft); text-decoration: none; transition: color .2s ease; }
.breadcrumb-nav a:hover, .breadcrumb-nav a:focus-visible { color: var(--e1-color); }
.breadcrumb-nav li:not(:last-child)::after { content: "/"; margin-left: .4em; color: var(--hairline); }
.breadcrumb-nav li[aria-current="page"] { color: var(--ink); }
