/* ============================================================
   LILIANE KISS — DESIGN SYSTEM
   Sections: 0) Fonts (self-hosted)  1) Reset  2) Tokens  3) Typography
             4) Layout utils  5) Nav  6) Footer  7) Buttons  8) Badges
   ============================================================ */

/* 0) FONTS
   Self-hosted (not loaded from fonts.googleapis.com/fonts.gstatic.com) so no
   visitor IP is sent to Google before consent — see docs/confidentialite.
   Two voices, recalibrated (Aug 2026, after Matyas's review) around what's
   tied to a specific painting vs what's generic site prose: Cormorant
   Garamond stays on every heading (h1/h2/h3, .sec-title), a tableau's own
   title *and* its histoire/description (the text is written about that one
   painting, right next to it — same voice as the title), plus actual
   citations. Geist (variable, one file) takes generic running text not
   anchored to a single painting — bio, démarche, série/sous-groupe intros —
   because that's where stacking paragraphs of serif italic had started
   reading as "harmony" instead of the intended rigueur/organique contrast.
   Geist also keeps its original practical territory: nav, badges, prix,
   technique/dimensions/année, cours, horaires, contact, the admin tool. The
   site's wordmark ("Liliane Kiss" in nav/footer/hero) stays serif as a
   logotype, independent of this split. See the --font / --font-serif
   tokens below and section 3) TYPOGRAPHY for exactly where each one
   applies.
   latin + latin-ext subsets (2 files per style) cover French accents. */
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/geist-variable.woff2') format('woff2');
}
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: normal;
  font-weight: 300 500;
  font-display: swap;
  src: url('../fonts/cormorant-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: normal;
  font-weight: 300 500;
  font-display: swap;
  src: url('../fonts/cormorant-normal-latinext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/cormorant-italic400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/cormorant-italic400-latinext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* 1) RESET */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body { min-height: 100vh; overflow-x: hidden; }
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
ul { list-style: none; }

/* 2) TOKENS */
:root {
  /* The site is light-only — no dark theme is offered. Without this,
     mobile browsers whose OS is set to dark mode can render native form
     chrome (the <select> dropdown's own popup, in particular) using their
     own dark-mode guess instead of this page's actual (light) design —
     e.g. light-gray text on a white popup, unreadable until you scroll it
     into different lighting/contrast. Declaring the scheme explicitly
     stops the browser from guessing. */
  color-scheme: light;
  --bg: #FAF8F5;
  --bg-alt: #F3F0EB;
  --text: #2C2A25;
  --dark-bg: #2C2A25;
  --dark-text: #E8E4DD;
  --accent: #C4B8A8;
  --text-secondary: #666153;
  --text-tertiary: #726D60;
  --text-secondary-on-dark: #A8A296;
  --text-tertiary-on-dark: #9A9488;

  --badge-vendu-bg: rgba(44,42,37,0.85);
  --badge-vendu-text: #E8E4DD;
  --badge-reserve-bg: rgba(180,160,120,0.88);
  --badge-reserve-text: #FFFFFF;
  --badge-expo-bg: rgba(90,120,90,0.85);
  --badge-expo-text: #FFFFFF;
  --badge-a-vendre-bg: rgba(163,94,66,0.88);
  --badge-a-vendre-text: #FFFFFF;

  --font: 'Geist', sans-serif;
  --font-serif: 'Cormorant Garamond', serif;

  --ease-standard: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --nav-height: 72px;
  --subnav-height: 58px;
}

/* 2a-bis) ACCESSIBILITY UTILITIES */
/* Visually hides content while keeping it in the accessibility tree — for
   labels a sighted user doesn't need (the newsletter field's placeholder +
   the submit button's own text already convey its purpose visually) but a
   screen reader user still does (a placeholder alone isn't a substitute
   for a real <label>: it's not consistently announced, and it vanishes
   the moment the field is focused/typed into). */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* 2b) LAZY IMAGE FADE-IN */
img[loading="lazy"] { opacity: 0; transition: opacity 300ms var(--ease-standard); }
img[loading="lazy"].is-loaded { opacity: 1; }

/* 2c) SCROLL REVEAL */
.reveal { opacity: 0; transform: translateY(24px); transition: opacity 700ms var(--ease-standard), transform 700ms var(--ease-standard); }
.reveal.is-visible { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
}

/* 2d) REVEAL-TEXT (word-stagger headings/ledes) / REVEAL-WIPE (clip-path image reveal) */
/* Pre-emptively hides [data-split] content only once JS is confirmed present
   (see the `.js` class added inline in <head>), so main.js can split it into
   word-spans before first paint without a flash of unsplit text. A no-JS
   visitor never gets the `js` class, so the plain sentence stays visible. */
.js .reveal-text [data-split]:not([data-split-done]) { visibility: hidden; }

.reveal-text-word {
  display: inline-block;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 500ms var(--ease-standard), transform 550ms var(--ease-standard);
  transition-delay: calc(var(--i) * 30ms);
}
.reveal-text.is-visible .reveal-text-word { opacity: 1; transform: translateY(0); }
.reveal-text .kicker { opacity: 0; transform: translateY(8px); transition: opacity 500ms var(--ease-standard), transform 500ms var(--ease-standard); }
.reveal-text.is-visible .kicker { opacity: 1; transform: translateY(0); }

/* The clip lives on an inner .reveal-wipe-clip wrapper, never on the
   .reveal-wipe element itself: IntersectionObserver computes a target's
   intersection against its own post-clip painted area, so an element
   clipped to 0 width by its own clip-path permanently reports
   isIntersecting: false — a deadlock where .is-visible (the class that
   would undo the clip) can never be added, because the clip that's
   supposed to be undone is what's hiding the element from the observer
   in the first place. Keeping the clip one DOM level down breaks that
   cycle: observeReveal() watches the unclipped outer element, whose real
   geometry drives the intersection check correctly. */
.reveal-wipe .reveal-wipe-clip { clip-path: inset(0 100% 0 0); transition: clip-path 900ms var(--ease-standard); }
.reveal-wipe.is-visible .reveal-wipe-clip { clip-path: inset(0 0 0 0); }

@media (prefers-reduced-motion: reduce) {
  .reveal-text-word, .reveal-text .kicker { opacity: 1; transform: none; transition: none; }
  .reveal-wipe .reveal-wipe-clip { clip-path: none; transition: none; }
}

/* 3) TYPOGRAPHY
   Two voices (see section 0 FONTS for the reasoning). var(--font-serif) —
   Cormorant Garamond — covers every heading (h1/h2/h3, .sec-title), a
   tableau's own title and its histoire/description (vedette, lightbox —
   text written *about that specific painting* stays in the same voice as
   its title, right next to the image), and actual citations (the artist's
   own words, or a literary excerpt like the Silènes text). var(--font) —
   Geist — covers generic site-wide prose not tied to one painting (bio,
   démarche, série/sous-groupe intros and labels) plus the original
   practical territory (nav, badges, prix, technique/dimensions/année,
   cours, horaires, contact, admin). The site's own wordmark ("Liliane
   Kiss" in nav/footer/hero) stays serif as a logotype, not as body
   typography — untouched here. */
body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  font-size: 16px;
  line-height: 1.6;
}
h1, h2, h3 { font-family: var(--font-serif); font-weight: 400; }
.kicker {
  font-family: var(--font);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: var(--text-secondary);
  margin-bottom: 12px;
}
.sec-title {
  font-family: var(--font-serif);
  font-size: 36px;
  font-weight: 400;
  margin-bottom: 24px;
}
.section-intro { margin-bottom: 40px; }
.section-intro .sec-title { font-size: 44px; }
.section-lede {
  font-family: var(--font);
  font-weight: 400;
  font-size: 19px;
  color: var(--text-secondary);
  max-width: 560px;
  margin-top: 12px;
}
/* The one .section-lede that's an actual quote (apropos's "Je peins ce que
   la nature m'a appris…") rather than a plain intro sentence — see
   apropos.html. */
.section-lede--citation { font-family: var(--font-serif); font-style: italic; }

/* 4) LAYOUT UTILS */
.container { max-width: 1200px; margin: 0 auto; padding: 0 32px; }
.section { padding: 96px 0; background: var(--bg); }
.section--alt { background: var(--bg-alt); }
.section--dark { background: var(--dark-bg); color: var(--dark-text); }
.section--dark .text-secondary { color: var(--text-tertiary-on-dark); }

/* 5) NAV */
.site-nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: var(--nav-height);
  z-index: 100;
  transition: background-color 300ms var(--ease-standard), backdrop-filter 300ms var(--ease-standard),
    top 300ms var(--ease-standard), left 300ms var(--ease-standard), right 300ms var(--ease-standard),
    border-radius 300ms var(--ease-standard), box-shadow 300ms var(--ease-standard);
}
.site-nav.nav--scrolled {
  background-color: rgba(250, 248, 245, 0.72);
  box-shadow: 0 1px 0 rgba(44,42,37,0.06);
}
@media (min-width: 861px) {
  .site-nav.nav--scrolled {
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    /* Detach into a floating bar once the page has scrolled, instead of
       staying flush with the viewport edges. */
    top: 14px; left: 14px; right: 14px;
    border-radius: 10px;
    box-shadow: 0 10px 30px rgba(44,42,37,0.14);
  }
  /* The à propos subnav sticks right below the nav; once the nav floats
     down 14px it must follow, or it ends up partly hidden underneath it. */
  #siteNav.nav--scrolled ~ .apropos-subnav {
    top: calc(var(--nav-height) + 14px);
  }
}

/* The homepage hero sits directly under the nav with no offset, and is now
   a dark image — the nav's default dark text is unreadable over it until
   the scrolled (light, semi-opaque) background kicks in. Flip to light
   text for that unscrolled-over-the-hero state only. */
.page-home .site-nav:not(.nav--scrolled) .nav-logo-name,
.page-home .site-nav:not(.nav--scrolled) .nav-logo-sub,
.page-home .site-nav:not(.nav--scrolled) .nav-link {
  color: var(--dark-text);
}
.page-home .site-nav:not(.nav--scrolled) .nav-link.active { border-bottom-color: var(--dark-text); }
.page-home .site-nav:not(.nav--scrolled) .nav-link:hover { color: var(--text-secondary-on-dark); }
.page-home .site-nav:not(.nav--scrolled) .nav-toggle span { background: var(--dark-text); }
.nav-inner {
  max-width: 1200px;
  margin: 0 auto;
  height: 100%;
  padding: 0 32px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.nav-logo { display: flex; flex-direction: column; line-height: 1.2; }
.nav-logo-name { font-family: var(--font-serif); font-weight: 500; letter-spacing: 0.01em; font-size: 26px; color: var(--text); }
.nav-logo-sub {
  font-family: var(--font);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-secondary);
}
.nav-links { display: flex; gap: 32px; }
.nav-link {
  font-family: var(--font);
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding-bottom: 4px;
  border-bottom: 1px solid transparent;
  transition: border-color 200ms var(--ease-standard), color 200ms var(--ease-standard);
}
.nav-link:hover { color: var(--text-secondary); }
.nav-link.active { border-bottom-color: var(--text); }
.nav-toggle { display: none; flex-direction: column; gap: 5px; width: 24px; }
.nav-toggle span { display: block; height: 1px; background: var(--text); }

@media (max-width: 860px) {
  .nav-toggle { display: flex; }
  .nav-links {
    position: fixed;
    top: var(--nav-height); left: 0; right: 0; bottom: 0;
    background: var(--bg);
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 28px;
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 250ms var(--ease-standard), transform 250ms var(--ease-standard);
  }
  .nav-links.nav-links--open {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }
  .nav-link { font-size: 14px; }

  /* The homepage's unscrolled nav is styled light-on-transparent to stay
     readable over the dark hero photo behind it (see the .page-home rule
     above) — but the opened mobile menu is its own opaque, light-colored
     panel, not the hero. Without this, opening the menu before scrolling
     (so .nav--scrolled hasn't been added yet) leaves the links in that
     light color against the panel's light background: invisible until
     you scroll down and back up. Same specificity as the rule it's
     overriding, so this only wins because it comes later in the
     cascade — keep it below that rule if this ever moves. */
  .page-home .site-nav .nav-links--open .nav-link { color: var(--text); }
  .page-home .site-nav .nav-links--open .nav-link.active { border-bottom-color: var(--text); }
  .page-home .site-nav .nav-links--open .nav-link:hover { color: var(--text-secondary); }
}

/* 6) FOOTER */
.site-footer {
  background: var(--dark-bg);
  color: var(--dark-text);
  text-align: center;
  padding: 56px 32px;
}
.footer-name { font-family: var(--font-serif); font-weight: 500; font-size: 20px; margin-bottom: 8px; }
.footer-sub { font-size: 13px; color: var(--text-tertiary-on-dark); margin-bottom: 16px; }
.footer-copy { font-size: 11px; color: var(--text-tertiary-on-dark); }
.footer-legal { margin-top: 8px; }
.footer-legal a { font-size: 11px; color: var(--text-tertiary-on-dark); text-decoration: underline; }
.footer-legal a:hover { color: var(--dark-text); }

.footer-newsletter { margin: 20px 0; display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.footer-newsletter input[type="email"] { padding: 8px 12px; border: 1px solid rgba(232,228,221,0.3); background: transparent; color: var(--dark-text); font-family: var(--font); font-size: 13px; min-width: 220px; }
.footer-newsletter button { padding: 8px 16px; color: var(--dark-text); border-color: var(--dark-text); }
.footer-newsletter-note { font-size: 11px; color: var(--text-tertiary-on-dark); max-width: 360px; margin: 0 auto; line-height: 1.5; }
.footer-newsletter-note a { color: var(--text-tertiary-on-dark); text-decoration: underline; }
.footer-newsletter-note a:hover { color: var(--dark-text); }
.footer-newsletter-status { font-size: 12px; margin-top: 8px; min-height: 16px; }
.footer-newsletter-status--ok { color: #A4B5A4; }
.footer-newsletter-status--error { color: #D09897; }

.footer-divider { border-top: 1px solid rgba(232,228,221,0.15); margin: 24px auto 20px; width: 48px; }

/* 7) BUTTONS */
.btn {
  display: inline-block;
  font-family: var(--font);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 16px 32px;
  border: 1px solid var(--text);
  border-radius: 999px;
  transition: transform 200ms var(--ease-standard), box-shadow 200ms var(--ease-standard);
}
/* admin.php (internal CMS tool for Liliane) deliberately opts out of the
   site's two-voice typography (section 0/3): nothing in the tool is "about
   a painting", it's all practical UI, so headings stay in Geist instead of
   inheriting the public site's Cormorant Garamond h1/h2/h3 rule. Buttons
   get soft rounded corners (dropped the old "keep square" rule) as part of
   a friendlier, simpler redesign for a non-technical user. */
.admin-page, .admin-page h1, .admin-page h2, .admin-page h3, .admin-page .sec-title { font-family: var(--font); }
.admin-page .btn { border-radius: 10px; }
.btn:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(44,42,37,0.15); }
.btn--primary { background: var(--text); color: var(--bg); }
.btn--ghost { background: transparent; color: var(--text); }
.section--dark .btn--ghost { color: var(--dark-text); border-color: var(--dark-text); }

/* 8) BADGES */
.badge {
  display: inline-block;
  font-family: var(--font);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 6px 12px;
  border-radius: 2px;
}
.badge--vendu { background: var(--badge-vendu-bg); color: var(--badge-vendu-text); }
.badge--reserve { background: var(--badge-reserve-bg); color: var(--badge-reserve-text); }
.badge--expo { background: var(--badge-expo-bg); color: var(--badge-expo-text); }
.badge--a-vendre { background: var(--badge-a-vendre-bg); color: var(--badge-a-vendre-text); }
a.badge { transition: opacity 200ms var(--ease-standard); }
a.badge:hover { opacity: 0.85; }

.gal-info-prix { font-family: var(--font); font-weight: 600; font-size: 20px; color: var(--dark-text); margin-top: 4px; }

/* ============================================================
   9) GALERIE
   ============================================================ */
.galerie-body { padding-top: var(--nav-height); }
.gallery-layout { display: flex; min-height: calc(100vh - var(--nav-height)); }

.gallery-sidebar {
  width: 220px;
  flex-shrink: 0;
  padding: 40px 24px;
  border-right: 1px solid rgba(44,42,37,0.08);
  position: sticky;
  top: var(--nav-height);
  align-self: flex-start;
  max-height: calc(100vh - var(--nav-height));
  overflow-y: auto;
}
/* A single continuous rail runs alongside every item (Tableaux principaux
   included) instead of each item toggling its own border on/off — a small
   dot glides along it (see .gallery-sidebar-dot, positioned in JS by
   updateSidebarDot() in galerie.js) to show the current série, both on
   click and while scroll-spying through the "Tout" view. The nav's own
   left padding is the rail's gutter, clear of the item text. */
.gallery-sidebar-nav { position: relative; padding-left: 16px; }
.gallery-sidebar-rail {
  position: absolute;
  left: 0; top: 2px; bottom: 2px;
  width: 1px;
  background: rgba(44,42,37,0.12);
}
.gallery-sidebar-dot {
  position: absolute;
  left: -4px; top: 0;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--text);
  /* A page-color ring separates the dot from the rail line underneath it,
     then a thin accent ring around that gives it a bit of warmth/lift
     instead of reading as a flat filled-in circle. */
  box-shadow: 0 0 0 3px var(--bg), 0 0 0 4px var(--accent), 0 2px 6px rgba(44,42,37,0.15);
  opacity: 0;
  transform: scale(0.5);
  transition: top 450ms var(--ease-standard), opacity 250ms var(--ease-standard), transform 350ms var(--ease-standard);
}
.gallery-sidebar-dot.is-visible { opacity: 1; transform: scale(1); }

.gallery-sidebar-list li { margin-bottom: 4px; }
.gallery-sidebar-item {
  display: block;
  width: 100%;
  text-align: left;
  font-family: var(--font);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 8px 0 8px 12px;
  color: var(--text-secondary);
  transition: color 200ms var(--ease-standard);
}
.gallery-sidebar-item:hover { color: var(--text); }
/* Underline (not just a color shift) on the active item — same "currently
   here" signal as .nav-link.active's border-bottom, so the top nav and
   every sidebar built on this class (galerie, à propos) read as one
   consistent grammar for what's clickable/current (Matyas, Aug 2026).
   text-decoration rather than border-bottom because the item is a
   full-width block (the whole row is the tap target) — border-bottom
   would draw a line under empty space past the text; underline hugs the
   text itself either way. */
.gallery-sidebar-item.active { color: var(--text); text-decoration: underline; text-underline-offset: 4px; }
/* Kept larger/bold at all times (it's the flagship série, always meant to
   stand out in the list) — but its own dark color + underline dash used to
   be static too, so it looked "selected" even while browsing Afrique or
   Essais. Those two now follow .active like every other item, so the
   sidebar only ever shows one item as current. */
.gallery-sidebar-item--primary {
  font-family: var(--font);
  font-size: 19px;
  font-weight: 700;
  text-transform: none;
  letter-spacing: normal;
  color: var(--text-secondary);
  padding: 0 0 8px;
}
.gallery-sidebar-item--primary:hover,
.gallery-sidebar-item--primary.active { color: var(--text); text-decoration: none; }
.gallery-sidebar-item--primary.active::after {
  content: '';
  display: block;
  width: 24px;
  height: 1px;
  background: var(--text);
  margin-top: 6px;
}
.gallery-sidebar-item--sub { font-size: 11px; letter-spacing: 0.1em; padding-left: 24px; color: var(--text-tertiary); }
.gallery-sidebar-item--tout {
  border-top: 1px solid rgba(44,42,37,0.08);
  margin-top: 12px;
  padding-top: 12px;
  color: var(--text-tertiary);
}
.gallery-sidebar-subhead {
  font-family: var(--font);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-tertiary);
  padding: 20px 0 4px 12px;
}

/* The "Tout" view's per-série grouping (see galerie.js renderGroupedGrid).
   Each section reuses .gallery-grid unchanged for its own masonry — only
   the header and the divider between sections are new here. */
.gallery-section-header { padding: 40px 40px 0; }
.gallery-section-header .kicker { margin-bottom: 8px; }
.gallery-section-desc { font-family: var(--font); font-style: italic; font-size: 16px; color: var(--text-secondary); max-width: 560px; margin-top: 8px; }
.gallery-section + .gallery-section { border-top: 1px solid rgba(44,42,37,0.08); margin-top: 24px; }
.gallery-section .gallery-grid { padding-top: 24px; }

.gallery-stage { flex: 1; display: flex; flex-direction: column; min-width: 0; }

.gal-featured { padding: 40px 40px 0; }
.gal-featured:empty { display: none; }
.gal-header { margin-bottom: 20px; }
.gal-intro-text { max-width: 640px; margin-bottom: 48px; }
.gal-intro-text p { font-family: var(--font); font-size: 18px; line-height: 1.8; margin-bottom: 16px; }
.gal-intro-text p:last-child { margin-bottom: 0; }

/* No divider line between vedette items (art director: "aérer" the works
   from each other rather than fencing them with a rule), just generous
   vertical air — and no more alternating reverse layout (see
   buildFeaturedItemEl in galerie.js): every item is image-left/text-right,
   consistently, for visual continuity scrolling down. */
.gal-featured-item + .gal-featured-item { margin-top: 72px; padding-top: 72px; }
.gal-featured-kicker { font-family: var(--font); font-size: 11px; text-transform: uppercase; letter-spacing: 0.15em; color: var(--text-tertiary); margin-bottom: 14px; }

.gal-featured-row { display: flex; gap: 48px; align-items: center; margin-bottom: 44px; }

.gal-featured-img-wrap { position: relative; cursor: pointer; flex: 0 1 60%; text-align: center; }
.gal-featured-img-wrap img { max-width: 100%; max-height: 65vh; width: auto; height: auto; display: inline-block; box-shadow: 0 16px 40px rgba(44,42,37,0.10); }
/* Silènes is a portrait-format canvas (110×170cm) — at the shared 65vh
   height cap it prints narrower than the landscape vedettes around it. A
   small bump gives it comparable visual weight (Liliane's request). */
.gal-featured-img-wrap img[alt="Silènes"] { max-height: 72vh; }

.gal-featured-info { flex: 0 1 40%; }
.gal-featured-titre { font-family: var(--font-serif); font-style: italic; font-weight: 500; font-size: 32px; margin-bottom: 10px; }
.gal-featured-meta { font-size: 13px; color: var(--text-secondary); margin-bottom: 16px; }
.gal-featured-desc p { font-family: var(--font-serif); font-size: 17px; line-height: 1.7; margin-bottom: 16px; }
.gal-featured-desc p:last-child { margin-bottom: 0; }
/* A quoted excerpt inside a tableau's description (e.g. Silènes/Charles
   Duits) is marked up as <em> in content.json — the italic sets it apart
   from the surrounding roman description, both already in the serif. */
.gal-featured-desc em { font-style: italic; }

.gal-featured-divider { text-align: center; margin: 44px 0 32px; }
.gal-featured-divider::before { content: ''; display: inline-block; width: 32px; height: 1px; background: rgba(44,42,37,0.2); }
.gal-featured-divider-label { display: block; margin-top: 10px; font-family: var(--font); font-size: 11px; text-transform: uppercase; letter-spacing: 0.15em; color: var(--text-tertiary); }

/* Named sub-groups within a série's plain grid (currently only "afrique":
   Vaches / Textiles, each with its own small intro, then an unlabeled tail
   block for whatever isn't in a named group — see galerie.js renderGrid).
   Reuses the same header vocabulary as the "Tout" view's per-série
   .gallery-section-header (.kicker + a title + a short description) rather
   than inventing a new visual language, just one size down since this is a
   secondary heading nested inside an already-titled série. */
.gal-sub-section + .gal-sub-section { border-top: 1px solid rgba(44,42,37,0.08); margin-top: 24px; }
.gal-sub-header { padding: 32px 40px 0; }
.gal-sub-header .kicker { margin-bottom: 8px; }
.gal-sub-titre { font-family: var(--font); font-style: normal; font-weight: 600; font-size: 24px; }
.gal-sub-intro { font-family: var(--font); font-size: 16px; color: var(--text-secondary); max-width: 560px; margin-top: 8px; }
.gal-sub-section .gallery-grid { padding-top: 24px; }

.gallery-grid {
  columns: 3;
  column-gap: 24px;
  padding: 40px;
  overflow-y: auto;
}
/* When #galGrid holds per-série <section>s (the grouped "Tout" view —
   see galerie.js renderGroupedGrid) or per-groupe .gal-sub-section blocks
   (the "afrique" série's Vaches/Textiles/tail — see renderGrid) instead of
   .gallery-card elements directly, it must not be a multicol container
   itself — each section/block brings its own nested .gallery-grid for its
   own cards. This selector only matches the outer mount point; a nested
   .gallery-grid has .gallery-card children, never .gallery-section or
   .gal-sub-section ones, so it keeps its columns/padding untouched at
   every breakpoint. */
.gallery-grid:has(> .gallery-section), .gallery-grid:has(> .gal-sub-section) { columns: auto; padding: 0; overflow: visible; }
.gallery-card { cursor: pointer; break-inside: avoid; margin-bottom: 24px; }
/* galerie.js sets the real aspect-ratio inline from each œuvre's stored
   imgWidth/imgHeight, so the box is already correctly sized before the
   photo loads (no masonry reflow). The 4/5 default plus the :has() switch
   below is only a fallback for an œuvre published without those fields. */
.gallery-card-img-wrap { position: relative; overflow: hidden; background: var(--bg-alt); aspect-ratio: 4/5; }
.gallery-card-img-wrap:has(img.is-loaded) { aspect-ratio: auto; }
.gallery-card-img-wrap img { width: 100%; height: auto; transition: transform 400ms var(--ease-standard), opacity 300ms var(--ease-standard); }
.gallery-card:hover .gallery-card-img-wrap img { transform: scale(1.04); }
.gallery-card-badge { position: absolute; top: 12px; right: 12px; }
.gallery-card-titre { font-family: var(--font); font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-secondary); margin-top: 12px; }

.gallery-load-error { column-span: all; font-family: var(--font); font-size: 15px; color: var(--text-secondary); display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }

/* Shown in #galGrid while waiting on content.json — see the setTimeout in
   galerie.js's whenReady(). render() overwrites #galGrid's innerHTML the
   moment real data arrives, so this never lingers once loaded. */
.gallery-loading {
  column-span: all;
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font);
  font-size: 15px;
  color: var(--text-secondary);
  padding: 40px;
}
.gallery-loading::before {
  content: '';
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 2px solid rgba(44,42,37,0.18);
  border-top-color: var(--text-secondary);
  animation: lk-spin 800ms linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .gallery-loading::before { animation: none; opacity: 0.7; }
}

/* Only shown once a painting's own photo (not content.json — see
   data-loader.js for that one) has been loading for 2s+ (LK.watchSlowLoad
   in main.js), on whichever of the three wrappers is waiting: a gallery
   card, a vitrine photo, or the lightbox's main image. Most loads never
   see this at all — it exists so a slow connection reads as "still
   loading" instead of "did this break?". */
.is-slow-loading::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  border-radius: 50%;
  border: 2px solid rgba(44,42,37,0.18);
  border-top-color: var(--text-secondary);
  animation: lk-spin 800ms linear infinite;
  pointer-events: none;
  z-index: 2;
}
/* The lightbox sits on a near-black backdrop, where the default (dark-on-
   light) spinner colors above would be nearly invisible. */
.gal-lightbox-img-wrap.is-slow-loading::after {
  border-color: rgba(232,228,221,0.2);
  border-top-color: var(--accent);
}
@keyframes lk-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .is-slow-loading::after { animation: none; opacity: 0.7; }
}

/* Generic content:error fallback (see main.js) — a slim bar pinned to the
   bottom of the viewport so it doesn't fight the fixed top nav's stacking,
   shown on any page other than galerie.html when content.json still
   couldn't be loaded after its own retries. */
.lk-load-error-banner {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 500;
  background: var(--dark-bg); color: var(--dark-text);
  padding: 14px 20px;
  display: flex; align-items: center; justify-content: center; gap: 16px; flex-wrap: wrap;
  font-family: var(--font); font-size: 13px;
}
.lk-load-error-banner button {
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.08em;
  border: 1px solid var(--dark-text); color: var(--dark-text);
  padding: 6px 16px; border-radius: 999px; background: none; cursor: pointer;
  transition: background-color 200ms var(--ease-standard);
}
.lk-load-error-banner button:hover { background: rgba(232,228,221,0.12); }

.gallery-mobile-picker { display: none; }

/* ===== LIGHTBOX / FOCUS ===== */
.gal-lightbox {
  --lightbox-info-width: 320px;
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: none;
  opacity: 0;
  transition: opacity 400ms var(--ease-standard);
}
.gal-lightbox.is-open { display: flex; align-items: center; justify-content: center; opacity: 1; }
.gal-lightbox-backdrop { position: absolute; inset: 0; background: rgba(44,42,37,0.97); cursor: pointer; }

.gal-lightbox-container {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 0;
  width: 100%;
  height: 100%;
  padding: 24px;
}
.gal-lightbox-img-wrap {
  position: relative;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  height: 100%;
  overflow: hidden;
}
.gal-lightbox-img-wrap img {
  position: absolute;
  max-width: 100%;
  max-height: calc(100vh - 48px);
  width: auto;
  height: auto;
  object-fit: contain;
  transition: transform 400ms var(--ease-standard), opacity 400ms var(--ease-standard), transform-origin 100ms linear;
}
/* Clicking the focused painting on desktop "steps closer" to it: the whole
   image scales up in place and gently re-centers on the cursor as it moves
   (see setupClickZoom in galerie.js), rather than a magnifying-glass/
   inspection tool, which felt wrong for looking at a painting. */
#galImg { cursor: zoom-in; }
#galImg.is-zoomed { transform: scale(1.8); cursor: zoom-out; }

.gal-nav-btn {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  z-index: 1001;
  width: 48px;
  height: 48px;
  border-radius: 2px;
  background: rgba(250,248,245,0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color 200ms var(--ease-standard);
}
.gal-nav-btn:hover { background: rgba(250,248,245,0.22); }
.gal-nav-btn svg { stroke: var(--dark-text); }
.gal-nav--prev { left: 20px; }
.gal-nav--next { right: calc(var(--lightbox-info-width) + 44px); }

.gal-close-btn {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 1001;
  width: 40px;
  height: 40px;
  border-radius: 2px;
  background: rgba(250,248,245,0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color 200ms var(--ease-standard);
}
.gal-close-btn:hover { background: rgba(250,248,245,0.22); }
.gal-close-btn svg { stroke: var(--dark-text); }

.gal-img--enter-right { transform: translateX(60px); opacity: 0; }
.gal-img--enter-left { transform: translateX(-60px); opacity: 0; }
.gal-img--center { transform: translateX(0); opacity: 1; }
.gal-img--exit-left { transform: translateX(-60px); opacity: 0; }
.gal-img--exit-right { transform: translateX(60px); opacity: 0; }
.gal-img--fade { transition-duration: 600ms; }

.gal-lightbox-info {
  width: var(--lightbox-info-width);
  flex-shrink: 0;
  padding: 40px 36px;
  color: var(--dark-text);
  align-self: stretch;
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow-y: auto;
  opacity: 1;
  transition: opacity 200ms var(--ease-standard);
}
.gal-lightbox-info.is-fading { opacity: 0; }
.gal-info-kicker { font-size: 11px; text-transform: uppercase; letter-spacing: 0.14em; color: var(--text-secondary-on-dark); margin-bottom: 10px; }
.gal-titre-row { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; flex-wrap: wrap; }
.gal-titre { font-family: var(--font-serif); font-style: italic; font-weight: 500; font-size: 28px; color: var(--dark-text); }
.gal-info-row { display: flex; justify-content: space-between; gap: 16px; padding: 10px 0; border-bottom: 1px solid rgba(232,228,221,0.12); font-size: 13px; }
.gal-info-row span:first-child { color: var(--text-secondary-on-dark); }
.gal-info-row span:last-child { color: var(--accent); text-align: right; }
.gal-compteur { margin-top: 20px; font-size: 12px; letter-spacing: 0.06em; color: var(--text-secondary-on-dark); }
.gal-histoire {
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.7;
  color: var(--accent);
  margin-top: 20px;
}

@media (max-width: 860px) {
  .gallery-layout { flex-direction: column; }
  .gallery-sidebar {
    width: 100%;
    border-right: none;
    border-bottom: 1px solid rgba(44,42,37,0.08);
    padding: 16px 24px;
    position: static;
    max-height: none;
    overflow-y: visible;
  }
  .gallery-sidebar-nav { display: none; }
  /* A hand-built dropdown, not a native <select> — on iOS Safari a
     <select>'s popup is a wheel-picker rendered entirely by the OS, so
     `color-scheme`/`<option>` CSS can't reliably fix its colors (Android
     is more cooperative, but not guaranteed either). Building the list
     ourselves, styled the same way as every other element on the site,
     is the only version of this that's actually guaranteed readable
     regardless of the visitor's OS theme. */
  .gallery-mobile-picker { display: block; position: relative; }
  .gallery-mobile-picker-trigger {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    width: 100%;
    font-family: var(--font); font-size: 14px;
    padding: 12px 14px;
    border: 1px solid rgba(44,42,37,0.2);
    border-radius: 3px;
    background: var(--bg);
    color: var(--text);
  }
  .gallery-mobile-picker-chevron { flex-shrink: 0; transition: transform 250ms var(--ease-standard); }
  .gallery-mobile-picker.is-open .gallery-mobile-picker-chevron { transform: rotate(180deg); }
  .gallery-mobile-picker-list {
    display: none;
    position: absolute; left: 0; right: 0; top: calc(100% + 6px); z-index: 20;
    max-height: 60vh; overflow-y: auto;
    background: var(--bg);
    border: 1px solid rgba(44,42,37,0.15);
    border-radius: 3px;
    box-shadow: 0 12px 32px rgba(44,42,37,0.12);
  }
  .gallery-mobile-picker.is-open .gallery-mobile-picker-list { display: block; }
  .gallery-mobile-picker-item {
    display: block; width: 100%; text-align: left;
    font-family: var(--font); font-size: 14px;
    padding: 12px 14px;
    color: var(--text);
    border-bottom: 1px solid rgba(44,42,37,0.08);
  }
  .gallery-mobile-picker-item:last-child { border-bottom: none; }
  .gallery-mobile-picker-item.active { font-weight: 600; }
  .gallery-mobile-picker-item--primary { font-weight: 700; }
  .gallery-mobile-picker-item--sub { padding-left: 28px; font-size: 13px; color: var(--text-secondary); }
  .gallery-mobile-picker-item--tout { color: var(--text-secondary); }
  .gallery-grid { columns: 2; padding: 24px; }
  .gal-featured { padding: 24px 24px 0; }
  .gal-featured-item + .gal-featured-item { margin-top: 56px; padding-top: 56px; }
  .gal-featured-row { flex-direction: column; gap: 16px; margin-bottom: 32px; }
  .gal-featured-img-wrap { flex: none; }

  .gal-lightbox-container { flex-direction: column; padding: 56px 12px 12px; height: 100vh; overflow-y: auto; }
  .gal-lightbox-img-wrap { flex: none; width: 100%; height: auto; display: flex; align-items: center; justify-content: center; }
  .gal-lightbox-img-wrap img { position: static; max-width: 100%; max-height: 50vh; }
  .gal-lightbox-info { width: 100%; padding: 24px 8px 80px; flex-shrink: 0; }
  .gal-titre { font-size: 22px; }
  .gal-nav-btn { width: 40px; height: 40px; }
  .gal-nav--prev { left: 8px; }
  .gal-nav--next { right: 8px; }
  .gal-close-btn { top: 12px; right: 12px; }
}
@media (max-width: 420px) {
  .gallery-grid { columns: 1; }
}

/* ============================================================
   10) ACCUEIL
   ============================================================ */
.hero {
  position: relative;
  /* Kept short on purpose (was 70vh/60vh mobile): tall enough to still read
     as a real hero, but short enough that "Prochains événements" — the
     section right below it — pokes into view on load instead of needing a
     full scroll to reach, per Liliane's feedback that visitors skimming the
     homepage should see upcoming courses/expositions without effort. */
  height: 50vh;
  min-height: 400px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  overflow: hidden;
  background: var(--dark-bg);
}
.hero-bg { position: absolute; inset: 0; z-index: 0; }
.hero-slide { position: absolute; inset: 0; opacity: 0; animation: heroCrossfade 16s var(--ease-standard) infinite; }
.hero-slide:nth-child(1) { animation-delay: 0s; }
.hero-slide:nth-child(2) { animation-delay: 8s; }
.hero-slide img {
  width: 100%; height: 100%; object-fit: cover;
  filter: blur(13px) saturate(112%) brightness(0.72);
  animation: heroKenBurns 22s ease-out infinite alternate;
  /* ease-out, not ease-in-out: the zoom only starts running once the photo
     becomes visible (see the animation-play-state note below) — that's
     exactly the moment someone is actually watching it. ease-in-out's
     velocity is near-zero right at 0%, so the first couple of seconds of
     motion were imperceptible and the hero read as frozen at first
     glance. ease-out front-loads the movement instead, so it's visibly
     already zooming from the very first frame.
     The animation's clock starts ticking the instant this rule applies —
     at DOM insertion, not once the photo has actually finished loading.
     On a slow-ish first load, several hundred ms can elapse before the
     image paints, so it would appear already partway zoomed instead of
     starting from scale(1.08). Pausing until .is-loaded (added by the
     global <img> load listener in main.js, which covers these
     dynamically-inserted hero images too) keeps the animation frozen at
     its 0% frame while invisible, so it always starts the zoom fresh the
     moment the photo becomes visible. */
  animation-play-state: paused;
  will-change: transform;
}
.hero-slide img.is-loaded { animation-play-state: running; }
.hero-glow {
  position: absolute; inset: -20%; z-index: 1; pointer-events: none;
  background: radial-gradient(circle, rgba(196,184,168,0.45), transparent 60%);
  filter: blur(30px);
  mix-blend-mode: soft-light;
  animation: heroGlowDrift 14s ease-in-out infinite;
}
.hero-scrim {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(44,42,37,0.35), rgba(44,42,37,0.75) 100%);
}
/* flex column: .hero-event and .hero-cta are both inline-level (inline-flex
   / inline-block) so on a wide viewport, with nothing forcing a break
   between them, they'd sit side by side on one line instead of stacking —
   this guarantees the teaser pill always sits above the CTA button,
   regardless of screen width. */
.hero-content { position: relative; z-index: 2; padding: 0 24px; display: flex; flex-direction: column; align-items: center; }
.hero-title { font-family: var(--font-serif); font-size: 68px; font-weight: 400; letter-spacing: 0.01em; margin-bottom: 16px; color: var(--dark-text); text-shadow: 0 2px 20px rgba(0,0,0,0.35); }
.hero-sub { font-family: var(--font); font-size: 13px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-secondary-on-dark); margin-bottom: 40px; }
/* Next-event teaser pill, shown above the CTA (see index.html's whenReady
   script) whenever there's an upcoming exposition/course to point at —
   surfaces its date/title/venue directly in the hero, not just a generic
   "see events" label, so it's readable at a glance without scrolling. Kept
   visually secondary to .hero-cta (smaller, outlined rather than filled) so
   the CTA below still reads as the one actionable button. */
.hero-event {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 28px;
  padding: 10px 20px;
  border: 1px solid rgba(232,228,221,0.35);
  border-radius: 999px;
  font-family: var(--font);
  font-size: 13px;
  color: var(--dark-text);
  background: rgba(44,42,37,0.25);
  backdrop-filter: blur(6px);
  max-width: 90vw;
}
.hero-event:hover { border-color: var(--accent); background: rgba(44,42,37,0.4); }
/* Event titles come from Liliane's own admin tool and can run long (a full
   exhibition name, a venue) — truncated to one line rather than left to wrap
   into a multi-line pill, which would balloon the hero teaser's height and
   read as a text block rather than a compact at-a-glance badge. */
.hero-event-text { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; min-width: 0; }
.hero-cta {
  padding: 22px 52px;
  font-size: 13px;
  letter-spacing: 0.14em;
  border-radius: 999px;
  background: var(--dark-text);
  color: var(--dark-bg);
  border-color: var(--dark-text);
  box-shadow: 0 0 44px rgba(232,228,221,0.4), 0 10px 30px rgba(0,0,0,0.35);
}
.hero-cta:hover {
  transform: translateY(-3px) scale(1.03);
  box-shadow: 0 0 60px rgba(232,228,221,0.55), 0 16px 40px rgba(0,0,0,0.45);
}

.hero .kicker { color: var(--text-secondary-on-dark); margin-bottom: 8px; }

@keyframes heroKenBurns {
  0% { transform: scale(1.08) translate(0, 0); }
  100% { transform: scale(1.18) translate(-1%, -1%); }
}
@keyframes heroCrossfade {
  0%, 45% { opacity: 1; }
  50%, 95% { opacity: 0; }
  100% { opacity: 1; }
}
@keyframes heroGlowDrift {
  0%, 100% { opacity: 0.3; transform: translate(-10%, -10%) scale(1); }
  50% { opacity: 0.5; transform: translate(5%, 8%) scale(1.15); }
}

@media (prefers-reduced-motion: reduce) {
  .hero-slide { animation: none; opacity: 0; }
  .hero-slide:first-child { opacity: 1; }
  .hero-slide img { animation: none; }
  .hero-glow { animation: none; opacity: 0.3; }
}

.series-card { display: block; position: relative; cursor: pointer; aspect-ratio: 4/5; overflow: hidden; border-radius: 3px; background: var(--bg-alt); }
.series-card-img-wrap { position: absolute; inset: 0; }
.series-card-img-wrap img { width: 100%; height: 100%; object-fit: cover; transition: transform 600ms cubic-bezier(0.2, 0.7, 0.3, 1), opacity 300ms var(--ease-standard); }
.series-card:hover .series-card-img-wrap img { transform: scale(1.07); }
.series-card-scrim {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, transparent 40%, rgba(44,42,37,0.85) 100%);
  opacity: 0.55;
  transition: opacity 400ms var(--ease-standard);
}
.series-card:hover .series-card-scrim { opacity: 0.85; }
.series-card-label {
  position: absolute; left: 20px; right: 20px; bottom: 20px; z-index: 2;
  transform: translateY(0);
  transition: transform 400ms var(--ease-standard);
}
.series-card-nom { font-family: var(--font); font-weight: 600; font-size: 20px; color: var(--dark-text); margin-bottom: 4px; }
.series-card-cta {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--dark-text);
  opacity: 1; transition: opacity 300ms var(--ease-standard) 100ms;
}
.series-card--banner { aspect-ratio: 21/9; }

.actu-list { display: flex; flex-direction: column; gap: 0; }
.actu-item {
  display: grid;
  grid-template-columns: 100px 1fr;
  gap: 28px;
  padding: 28px 4px;
  border-bottom: 1px solid rgba(44,42,37,0.08);
  border-left: 2px solid transparent;
  align-items: start;
  transition: background-color 300ms var(--ease-standard), padding-left 300ms var(--ease-standard), border-left-color 300ms var(--ease-standard);
}
.actu-item:first-child { border-top: 1px solid rgba(44,42,37,0.08); }
.actu-item:hover { background-color: var(--bg-alt); padding-left: 12px; border-left-color: var(--accent); }
.actu-date-block { font-family: var(--font); text-align: center; }
.actu-day { font-size: 36px; font-weight: 700; line-height: 1; color: var(--text); }
.actu-month { font-size: 12px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-secondary); margin-top: 4px; }
.actu-year { font-size: 13px; color: var(--text-tertiary); margin-top: 2px; }
.actu-titre { font-family: var(--font); font-weight: 600; font-size: 17px; color: var(--text-secondary); margin-bottom: 6px; }
.actu-lieu { font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-secondary); margin-bottom: 8px; }
.actu-desc { font-size: 14px; line-height: 1.7; color: var(--text); margin-bottom: 10px; }
.actu-ics {
  display: inline-block;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-secondary);
  border-bottom: 1px solid var(--accent);
  padding-bottom: 2px;
  transition: color 200ms var(--ease-standard);
}
.actu-ics:hover { color: var(--text); }
.actu-more { text-align: center; margin-top: 32px; }
.actu-see-all { text-align: center; margin-top: 12px; }
.actu-see-all a { font-size: 13px; color: var(--text-secondary); text-decoration: underline; text-underline-offset: 3px; }
.actu-see-all a:hover { color: var(--text); }

.home-bio-teaser { max-width: 700px; margin: 0 auto; text-align: center; }
/* Dropped the dark card (Matyas's mockup): the portrait floats directly on
   the section's own cream background, citation centered underneath — an
   open, editorial layout instead of a boxed-in one, closer to how the
   "à propos" page itself presents Liliane's bio+citation. */
.home-bio-inner {
  display: flex; flex-direction: column; align-items: center; gap: 24px; margin-top: 32px;
}
.home-bio-portrait {
  width: 150px; height: 150px; border-radius: 50%; object-fit: cover; object-position: top; flex-shrink: 0;
  box-shadow: 0 0 0 1px rgba(44,42,37,0.08), 0 14px 34px rgba(44,42,37,0.14);
}
.home-bio-text { flex: none; }
.home-bio-citation { font-family: var(--font-serif); font-style: italic; font-weight: 400; font-size: 24px; line-height: 1.6; color: var(--text); margin-bottom: 24px; }

@media (max-width: 860px) {
  .actu-item { grid-template-columns: 64px 1fr; gap: 16px; }
  .actu-day { font-size: 26px; }
}

@media (max-width: 860px) {
  .hero { height: 46vh; }
  .hero-title { font-size: 40px; }
  .series-card--banner { aspect-ratio: 4/5; }
}

/* ============================================================
   12) À PROPOS
   ============================================================ */
/* Desktop nav for the page's 5 sections: a sticky left sidebar, shown
   ≥861px (see .apropos-sidebar below) — reuses the galerie sidebar's own
   .gallery-sidebar-item classes so both pages' "sub-nav" share identical
   grammar (Matyas, Aug 2026: "même en one-page, on garde le menu à
   gauche"). Below 861px a sticky rail down the side isn't workable, so
   .apropos-subnav (this horizontal bar) takes over instead — same 5
   anchors, same active-state logic (shared IntersectionObserver in
   apropos.html), just laid out as a top bar. Exactly one of the two is
   visible at a given width — see the two @media blocks further down. */
.apropos-subnav {
  position: sticky;
  top: var(--nav-height);
  z-index: 50;
  background: var(--bg);
  border-bottom: 1px solid rgba(44,42,37,0.08);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 32px;
  padding: 16px 0;
  min-height: var(--subnav-height);
  transition: top 300ms var(--ease-standard);
}
.apropos-subnav a {
  font-family: var(--font);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding-bottom: 4px;
  border-bottom: 1px solid transparent;
  color: var(--text-secondary);
  transition: color 200ms var(--ease-standard), border-color 200ms var(--ease-standard);
}
.apropos-subnav a:hover { color: var(--text); }
.apropos-subnav a.active { color: var(--text); border-bottom-color: var(--text); }

.apropos-layout { display: flex; }
.apropos-sidebar {
  width: 220px;
  flex-shrink: 0;
  padding: 40px 24px;
  border-right: 1px solid rgba(44,42,37,0.08);
  position: sticky;
  top: var(--nav-height);
  align-self: flex-start;
  max-height: calc(100vh - var(--nav-height));
  overflow-y: auto;
}
.apropos-stage { flex: 1; min-width: 0; }

#biographie, #demarche, #expositions, #presse, #presskit {
  scroll-margin-top: var(--nav-height);
}

@media (min-width: 861px) {
  .apropos-subnav { display: none; }
}
@media (max-width: 860px) {
  .apropos-sidebar { display: none; }
  #biographie, #demarche, #expositions, #presse, #presskit {
    scroll-margin-top: calc(var(--nav-height) + var(--subnav-height));
  }
}

.apropos-bio-layout { display: flex; gap: 60px; align-items: flex-start; }
.apropos-portrait { flex: 1; max-width: 380px; }
.apropos-portrait img { width: 100%; aspect-ratio: 3/4; object-fit: cover; }
.apropos-bio-text { flex: 1; }
.apropos-bio-text p { font-family: var(--font); font-size: 18px; line-height: 1.8; margin-bottom: 16px; }

/* Left-aligned to match .apropos-bio-text right above it (was centered with
   its own margin: 0 auto — inconsistent with the rest of the page, and
   looked odd on mobile once the text wrapped to several ragged lines). */
.apropos-demarche { max-width: 700px; font-family: var(--font); font-size: 19px; line-height: 1.8; }

.expo-list { display: flex; flex-direction: column; }
.expo-item { display: flex; gap: 32px; padding: 20px 0; border-bottom: 1px solid rgba(44,42,37,0.08); border-left: 2px solid transparent; transition: background-color 300ms var(--ease-standard), padding-left 300ms var(--ease-standard); }
.expo-item--upcoming { border-left-color: var(--accent); background-color: var(--bg-alt); padding-left: 16px; }
.expo-annee { font-family: var(--font); font-weight: 700; font-size: 20px; width: 80px; flex-shrink: 0; }
.expo-titre { font-weight: 500; margin-bottom: 4px; }
.expo-lieu { font-size: 13px; color: var(--text-secondary); }
.expo-badge-upcoming { display: inline-block; margin-left: 8px; padding: 2px 8px; font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text); background: var(--accent); border-radius: 2px; vertical-align: middle; }

.presse-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }
.presse-item img { width: 100%; aspect-ratio: 3/4; object-fit: cover; cursor: pointer; }

.simple-lightbox {
  position: fixed; inset: 0; background: rgba(26,25,23,0.92);
  display: none; align-items: center; justify-content: center; z-index: 200;
}
.simple-lightbox.is-open { display: flex; }
.simple-lightbox img { max-width: 90vw; max-height: 90vh; object-fit: contain; }
.simple-lightbox-close { position: absolute; top: 24px; right: 32px; color: #fff; font-size: 28px; }

@media (max-width: 860px) {
  .apropos-subnav { overflow-x: auto; gap: 20px; padding: 12px 16px; justify-content: flex-start; }
  .apropos-bio-layout { flex-direction: column; }
  .presse-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ============================================================
   13) COURS
   ============================================================ */
.cours-layout { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: 48px; align-items: center; }
.cours-img { overflow: hidden; }
.cours-img img { width: 100%; display: block; filter: brightness(0.95); }
.cours-grid { display: flex; flex-direction: column; gap: 20px; }
.cours-card { border: 1px solid rgba(44,42,37,0.1); padding: 28px 24px; border-radius: 3px; transition: border-color 300ms var(--ease-standard); }
.cours-card:hover { border-color: rgba(44,42,37,0.22); }
.cours-card-titre { font-family: var(--font); font-weight: 600; text-transform: uppercase; font-size: 20px; margin-bottom: 12px; }
.cours-card-desc { font-size: 14px; line-height: 1.7; color: var(--text); margin-bottom: 16px; }
.cours-card-facts { display: flex; flex-direction: column; gap: 8px; padding-top: 16px; border-top: 1px solid rgba(44,42,37,0.08); }
.cours-card-fact { display: flex; gap: 10px; font-size: 13px; line-height: 1.5; }
.cours-card-fact-label { flex-shrink: 0; width: 52px; text-transform: uppercase; letter-spacing: 0.06em; font-size: 11px; color: var(--text-secondary); padding-top: 2px; }
.cours-card-fact-value { color: var(--text); font-weight: 500; }

.cours-note { margin-top: 32px; padding-top: 24px; border-top: 1px solid rgba(44,42,37,0.1); font-size: 13px; line-height: 1.7; color: var(--text-secondary); max-width: 640px; }

.stage-list { display: flex; flex-direction: column; gap: 20px; }
.stage-item { display: flex; gap: 24px; padding: 20px; border: 1px solid rgba(44,42,37,0.1); align-items: center; }
.stage-date { font-family: var(--font); font-weight: 700; font-size: 18px; width: 140px; flex-shrink: 0; }
.stage-titre { font-weight: 500; margin-bottom: 4px; }
.stage-lieu { font-size: 13px; color: var(--text-secondary); margin-bottom: 6px; }
.stage-prix { margin-left: auto; font-size: 13px; font-weight: 500; }

@media (max-width: 860px) {
  .cours-layout { grid-template-columns: 1fr; gap: 32px; }
  .cours-img { max-height: 300px; }
  .cours-img img { object-fit: cover; height: 300px; }
  .stage-item { flex-wrap: wrap; }
  .stage-prix { margin-left: 0; }
}

/* ============================================================
   14) CONTACT
   ============================================================ */
.contact-layout { display: grid; grid-template-columns: 0.85fr 1.15fr; gap: 72px; }

.contact-info-card { background: var(--bg-alt); padding: 40px 36px; }
.contact-info-row { padding: 18px 0; border-bottom: 1px solid rgba(44,42,37,0.08); }
.contact-info-row:first-child { padding-top: 0; }
.contact-info-row:last-child { border-bottom: none; padding-bottom: 0; }
.contact-info-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-secondary); margin-bottom: 6px; }
.contact-info-value { font-family: var(--font); font-size: 18px; line-height: 1.6; }
.contact-info-value a { border-bottom: 1px solid var(--accent); transition: color 200ms var(--ease-standard); }
.contact-info-value a:hover { color: var(--text-secondary); }

.contact-form { display: flex; flex-direction: column; gap: 20px; }
.contact-form-field label {
  display: block;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-secondary);
  margin-bottom: 8px;
}
.contact-form input, .contact-form textarea {
  width: 100%;
  font-family: var(--font);
  font-size: 14px;
  padding: 14px 16px;
  border: 1px solid rgba(44,42,37,0.18);
  background: var(--bg);
  color: var(--text);
  transition: border-color 200ms var(--ease-standard);
}
.contact-form input:focus, .contact-form textarea:focus {
  outline: none;
  border-color: var(--accent);
}
.contact-form textarea { min-height: 140px; resize: vertical; }
.contact-form .field-error { color: #a94442; font-size: 12px; display: none; margin-top: -12px; }
.contact-form .btn { align-self: flex-start; }
.contact-form .btn:disabled { opacity: 0.6; cursor: default; }
.contact-form-honeypot { position: absolute; left: -9999px; top: -9999px; }
.contact-form-status { font-size: 14px; line-height: 1.6; }
.contact-form-status--success { color: #4a7a4a; }
.contact-form-status--error { color: #a94442; }
.contact-form-status--error a { text-decoration: underline; }

.contact-map { margin-top: 72px; }
.contact-map-wrap { overflow: hidden; border-radius: 4px; box-shadow: 0 12px 32px rgba(44,42,37,0.1); }
.contact-map iframe { width: 100%; height: 360px; border: 0; display: block; }
.contact-map-placeholder {
  height: 360px;
  background: var(--bg-alt);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 24px;
  text-align: center;
}
.contact-map-placeholder p { font-size: 14px; color: var(--text); }
.contact-map-note { max-width: 360px; font-size: 12px; color: var(--text-secondary); }

@media (max-width: 860px) {
  .contact-layout { grid-template-columns: 1fr; gap: 40px; }
  .contact-info-card { padding: 28px 24px; }
}

/* ============================================================
   15) OUTIL DE GESTION
   Redesigned (Aug 2026) to be usable without any technical background:
   bigger touch targets, rounded shapes, a visible hint under every
   category so Liliane can tell what's inside before opening it, a colored
   accent ring on whatever field is focused, and a ✓/⚠ icon on every status
   message so success vs. error is legible at a glance, not just by color.
   ============================================================ */
.outil-tabs { display: flex; gap: 8px; margin-bottom: 32px; flex-wrap: wrap; }
.outil-tab-btn {
  padding: 12px 20px;
  font-size: 13px;
  font-weight: 600;
  border: 1px solid rgba(44,42,37,0.2);
  border-radius: 999px;
  background: var(--bg);
  cursor: pointer;
  transition: background 200ms var(--ease-standard), border-color 200ms var(--ease-standard), transform 200ms var(--ease-standard);
}
.outil-tab-btn:hover { border-color: var(--text); transform: translateY(-1px); }
.outil-tab-btn.active { background: var(--text); color: var(--bg); border-color: var(--text); }
.outil-panel { display: none; }
.outil-panel.active { display: block; }
.outil-panel-title { font-family: var(--font); font-weight: 600; font-size: 21px; margin-bottom: 4px; }
.outil-tab-hint { font-size: 14px; line-height: 1.6; color: var(--text-secondary); margin-bottom: 24px; }
.outil-field { margin-bottom: 20px; }
.outil-field label { display: block; font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-secondary); margin-bottom: 6px; }
.outil-field input, .outil-field select, .outil-field textarea {
  width: 100%;
  font-family: var(--font);
  font-size: 15px;
  padding: 12px 14px;
  border: 1px solid rgba(44,42,37,0.2);
  border-radius: 8px;
  background: var(--bg);
  transition: border-color 150ms var(--ease-standard), box-shadow 150ms var(--ease-standard);
}
.outil-field input:focus, .outil-field select:focus, .outil-field textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(196,184,168,0.35);
}
.outil-field textarea { min-height: 120px; resize: vertical; }
.outil-dropzone {
  border: 2px dashed rgba(44,42,37,0.25);
  border-radius: 10px;
  padding: 32px;
  text-align: center;
  cursor: pointer;
  font-size: 14px;
  color: var(--text-secondary);
  transition: border-color 150ms var(--ease-standard), background 150ms var(--ease-standard);
}
.outil-dropzone:hover { border-color: var(--text); background: rgba(44,42,37,0.03); }
.outil-dropzone.is-dragover { border-color: var(--text); color: var(--text); background: rgba(44,42,37,0.05); }
.outil-preview { max-width: 240px; margin-top: 16px; border-radius: 8px; }
.outil-badge-choices { display: flex; gap: 12px; flex-wrap: wrap; }
.outil-badge-choice { padding: 10px 16px; border: 1px solid rgba(44,42,37,0.2); border-radius: 8px; cursor: pointer; }
.outil-badge-choice.selected { border-color: var(--text); box-shadow: inset 0 0 0 1px var(--text); }
.outil-output {
  background: var(--dark-bg);
  color: var(--dark-text);
  font-family: monospace;
  font-size: 13px;
  white-space: pre-wrap;
  padding: 20px;
  border-radius: 8px;
  margin-top: 24px;
  display: none;
}
.outil-output.is-visible { display: block; }
.outil-recap { margin-top: 16px; font-size: 14px; display: none; }
.outil-recap.is-visible { display: block; }
.outil-reminder { font-size: 12px; color: var(--badge-vendu-bg); margin-top: 12px; }
.outil-status {
  margin-top: 16px; padding: 12px 16px; border-radius: 8px;
  font-size: 14px; font-weight: 600; display: none;
  align-items: center; gap: 8px;
}
.outil-status.is-visible { display: flex; }
.outil-status--ok { background: rgba(90,130,90,0.12); color: #3d5c3d; }
.outil-status--ok::before { content: "✓"; }
.outil-status--error { background: rgba(160,60,60,0.12); color: #8a3a3a; }
.outil-status--error::before { content: "⚠"; }
.outil-search-result { margin-top: 12px; padding: 16px; border: 1px solid rgba(44,42,37,0.15); border-radius: 10px; font-size: 13px; display: none; }
.outil-search-result.is-visible { display: block; }
.outil-suggest {
  margin-top: 4px;
  max-height: 260px;
  overflow-y: auto;
  background: var(--bg);
  border: 1px solid rgba(44,42,37,0.2);
  border-radius: 8px;
  display: none;
}
.outil-suggest.is-visible { display: block; }
.outil-suggest-item { padding: 10px 14px; font-size: 14px; cursor: pointer; }
.outil-suggest-item:hover { background: rgba(44,42,37,0.06); }
.outil-suggest-item + .outil-suggest-item { border-top: 1px solid rgba(44,42,37,0.08); }
.outil-reorder-list { list-style: none; padding: 0; margin: 12px 0; }
.outil-reorder-list li { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; border: 1px solid rgba(44,42,37,0.15); border-radius: 8px; margin-bottom: 6px; }
.outil-reorder-list button { border: none; background: none; cursor: pointer; font-size: 16px; padding: 0 8px; }
.outil-category {
  margin-bottom: 24px;
  border: 1px solid rgba(44,42,37,0.12);
  border-radius: 12px;
  padding: 4px;
  background: var(--bg);
}
/* A darker bar (vs. the plain page background) plus a chevron reads as a
   clickable, expandable menu at a glance — without either cue the title was
   just bold text, indistinguishable from any other heading on the page. */
.outil-category-title {
  font-family: var(--font); font-weight: 600; font-size: 20px;
  margin: 0; padding: 16px 20px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: rgba(44,42,37,0.09);
  border-radius: 9px;
  cursor: pointer;
  transition: background 200ms var(--ease-standard);
}
.outil-category-title:hover { background: rgba(44,42,37,0.14); }
.outil-category-chevron { flex-shrink: 0; transition: transform 250ms var(--ease-standard); }
.outil-category.is-open .outil-category-chevron { transform: rotate(180deg); }
/* Stays visible whether the category is open or closed, so Liliane can see
   what a category is for without having to open it first. */
.outil-category-hint { font-size: 13px; line-height: 1.5; color: var(--text-secondary); margin: 10px 16px 0; }
.outil-category-body { display: none; padding: 20px 16px 16px; }
.outil-category-body.is-open { display: block; }

/* ============================================================
   16) LEGAL / CONFIDENTIALITÉ
   ============================================================ */
.legal-page { padding-top: calc(var(--nav-height) + 56px); }
.legal-content { max-width: 720px; }
.legal-draft-notice {
  font-size: 13px;
  line-height: 1.7;
  color: var(--text-secondary);
  background: var(--bg-alt);
  border-left: 2px solid var(--accent);
  padding: 16px 20px;
  margin-bottom: 40px;
}
.legal-content h3 {
  font-family: var(--font);
  font-weight: 600;
  font-size: 20px;
  margin-top: 40px;
  margin-bottom: 12px;
}
.legal-content h3:first-of-type { margin-top: 0; }
.legal-content p { font-size: 14px; line-height: 1.8; margin-bottom: 12px; }
.legal-content a { border-bottom: 1px solid var(--accent); transition: color 200ms var(--ease-standard); }
.legal-content a:hover { color: var(--text-secondary); }

/* ============================================================
   17) OUTIL — MAP PICKER (choix d'un lieu pour une œuvre)
   ============================================================ */
.outil-map-picker { position: relative; width: 220px; margin-top: 12px; cursor: crosshair; border: 1px solid rgba(44,42,37,0.15); }
.outil-map-marker {
  position: absolute;
  width: 10px; height: 10px;
  margin-left: -5px; margin-top: -5px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--dark-bg);
  pointer-events: none;
}

/* ============================================================
   18) EXPO POPUP — modale d'inscription déclenchée par le QR code des
   flyers d'exposition (voir assets/js/expo-popup.js). Ne s'affiche que
   si l'URL contient ?expo=1 : jamais pour un visiteur organique.
   ============================================================ */
.expo-popup-overlay {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(44,42,37,0.55);
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
  opacity: 0;
  transition: opacity 250ms var(--ease-standard);
}
.expo-popup-overlay.is-visible { opacity: 1; }

.expo-popup {
  --exp-bg: var(--bg);
  --exp-text: var(--text);
  --exp-text-secondary: var(--text-secondary);
  --exp-accent: var(--accent);
  --exp-font: var(--font);
  --exp-font-serif: var(--font-serif);
  --exp-border: rgba(44,42,37,0.14);

  position: relative;
  width: 100%; max-width: 420px;
  max-height: 90vh;
  overflow-y: auto;
  background: var(--exp-bg);
  color: var(--exp-text);
  border-radius: 14px;
  box-shadow: 0 20px 60px rgba(44,42,37,0.25);
  padding: 40px 32px 32px;
  transform: translateY(12px) scale(0.98);
  transition: transform 250ms var(--ease-standard);
}
.expo-popup-overlay.is-visible .expo-popup { transform: translateY(0) scale(1); }

.expo-popup-close {
  position: absolute; top: 10px; right: 10px;
  width: 32px; height: 32px;
  border-radius: 50%;
  border: none; background: transparent;
  font-size: 22px; line-height: 1;
  color: var(--exp-text-secondary);
  cursor: pointer;
  transition: background 200ms var(--ease-standard);
}
.expo-popup-close:hover { background: var(--bg-alt); }

.expo-popup-kicker {
  font-family: var(--exp-font); font-size: 11px; text-transform: uppercase;
  letter-spacing: 0.15em; color: var(--exp-accent); margin-bottom: 10px;
}
.expo-popup-title {
  font-family: var(--exp-font-serif); font-style: italic; font-weight: 500;
  font-size: 26px; line-height: 1.2; margin-bottom: 12px; color: var(--exp-text);
}
.expo-popup-text {
  font-family: var(--exp-font); font-size: 14px; line-height: 1.6;
  color: var(--exp-text-secondary); margin-bottom: 24px;
}

#expoPopupForm { display: flex; flex-direction: column; gap: 12px; }
.expo-popup #expoPrenom, .expo-popup #expoEmail {
  padding: 12px 14px; border: 1px solid var(--exp-border); border-radius: 8px;
  background: transparent; color: var(--exp-text);
  font-family: var(--exp-font); font-size: 14px;
}
.expo-popup #expoPrenom:focus, .expo-popup #expoEmail:focus {
  outline: none; border-color: var(--exp-accent);
}
.expo-popup-consent {
  display: flex; align-items: flex-start; gap: 10px;
  font-family: var(--exp-font); font-size: 12px; line-height: 1.5;
  color: var(--exp-text-secondary); cursor: pointer;
}
.expo-popup-consent input { margin-top: 3px; flex-shrink: 0; }
.expo-popup-consent a { color: var(--exp-text-secondary); text-decoration: underline; }
.expo-popup-submit { margin-top: 4px; width: 100%; text-align: center; cursor: pointer; }
.expo-popup-status { font-size: 12px; margin-top: 4px; min-height: 16px; font-family: var(--exp-font); }
.expo-popup-status--ok { color: #A4B5A4; }
.expo-popup-status--error { color: #D09897; }

.expo-popup-skip {
  display: block; width: 100%; text-align: center; margin-top: 16px;
  background: none; border: none; cursor: pointer;
  font-family: var(--exp-font); font-size: 12px; text-decoration: underline;
  color: var(--exp-text-secondary);
}
.expo-popup-skip:hover { color: var(--exp-text); }

.expo-popup-thanks { text-align: center; }
.expo-popup-thanks-title {
  font-family: var(--exp-font-serif); font-style: italic; font-size: 26px;
  margin-bottom: 12px; color: var(--exp-text);
}
.expo-popup-thanks-text {
  font-family: var(--exp-font); font-size: 14px; color: var(--exp-text-secondary);
  line-height: 1.6; margin-bottom: 20px;
}

body.expo-popup-open { overflow: hidden; }

@media (max-width: 480px) {
  .expo-popup { padding: 32px 22px 24px; }
  .expo-popup-title { font-size: 22px; }
}

/* ============================================================
   19) NEWSLETTER CONFIRM POPUP — modale de remerciement affichée
   après une inscription réussie au formulaire newsletter du footer
   (voir assets/js/main.js). Même langage visuel que la popup expo
   ci-dessus, en plus discret pour un simple accusé de réception.
   ============================================================ */
.nl-confirm-overlay {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(44,42,37,0.55);
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
  opacity: 0;
  transition: opacity 250ms var(--ease-standard);
}
.nl-confirm-overlay.is-visible { opacity: 1; }

.nl-confirm {
  position: relative;
  width: 100%; max-width: 380px;
  max-height: 90vh;
  overflow-y: auto;
  background: var(--bg);
  color: var(--text);
  border-radius: 14px;
  box-shadow: 0 20px 60px rgba(44,42,37,0.25);
  padding: 40px 32px 32px;
  text-align: center;
  transform: translateY(12px) scale(0.98);
  transition: transform 250ms var(--ease-standard);
}
.nl-confirm-overlay.is-visible .nl-confirm { transform: translateY(0) scale(1); }

.nl-confirm-close {
  position: absolute; top: 10px; right: 10px;
  width: 32px; height: 32px;
  border-radius: 50%;
  border: none; background: transparent;
  font-size: 22px; line-height: 1;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background 200ms var(--ease-standard);
}
.nl-confirm-close:hover { background: var(--bg-alt); }

.nl-confirm-title {
  font-family: var(--font-serif); font-style: italic; font-weight: 500;
  font-size: 24px; line-height: 1.2; margin-bottom: 12px; color: var(--text);
}
.nl-confirm-text {
  font-family: var(--font); font-size: 14px; line-height: 1.6;
  color: var(--text-secondary); margin-bottom: 20px;
}
.nl-confirm-cta { width: 100%; text-align: center; cursor: pointer; }

body.nl-confirm-open { overflow: hidden; }

@media (max-width: 480px) {
  .nl-confirm { padding: 32px 22px 24px; }
  .nl-confirm-title { font-size: 21px; }
}
