/* =====================================================================
   Myriam & Brice — Save the Date — V3
   Palette « vieux rose », or, champagne — animations continues
   ===================================================================== */

:root {
  --primary: #8b3555;
  --deep: #5a1f36;
  --rose: #d98aa3;
  --rose-light: #f5cbd6;
  --champagne: #f7e9de;
  --gold: #d4b06a;
  --gold-light: #efd9a4;
  --bg: #fff6f8;
  --bg-2: #fbe7ec;
  --text: #4e2436;
  --text-soft: #8a5a6b;
  --white: #fffafb;

  --surface: rgba(255, 250, 251, 0.72);
  --surface-strong: rgba(255, 250, 251, 0.9);
  --line: rgba(139, 53, 85, 0.14);
  --shadow: 0 30px 70px rgba(110, 40, 65, 0.18);
  --shadow-soft: 0 16px 40px rgba(110, 40, 65, 0.12);
  --shadow-gold: 0 0 0 3px var(--white), 0 0 0 4.5px var(--gold);

  --font-display: "Cormorant Garamond", "Times New Roman", Georgia, serif;
  --font-script: "Great Vibes", "Brush Script MT", cursive;
  --font-body: "Manrope", system-ui, -apple-system, "Segoe UI", sans-serif;

  --container: min(1200px, calc(100vw - 40px));
  --radius: 26px;
  --header-h: 76px;

  --speed: 1;            /* multiplicateur global des animations */
  --petal-opacity: 1;
}

/* Niveaux d'animation (pilotés par le panneau) */
html[data-anim="soft"] { --speed: 1.6; }
html[data-anim="off"] .kenburns,
html[data-anim="off"] .deco,
html[data-anim="off"] .arch,
html[data-anim="off"] .title__word,
html[data-anim="off"] .names,
html[data-anim="off"] .btn--shine::after,
html[data-anim="off"] .aurora i,
html[data-anim="off"] .sparkles i,
html[data-anim="off"] .ribbon__track,
html[data-anim="off"] .swatch i, html[data-anim="off"] .swatch i::before,
html[data-anim="off"] .flourish__heart,
html[data-anim="off"] .hearts i,
html[data-anim="off"] .poster,
html[data-anim="off"] .silk img,
html[data-anim="off"] .hero__scroll i,
html[data-anim="off"] .petal { animation: none !important; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; }
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
[id] { scroll-margin-top: calc(var(--header-h) + 8px); }
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  color: var(--text);
  background: var(--bg);
  overflow-x: hidden;
  min-height: 100svh;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }
:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; border-radius: 6px; }
.container { width: var(--container); margin-inline: auto; position: relative; z-index: 2; }
.script { font-family: var(--font-script); font-weight: 400; }
.ic { width: 1.1em; height: 1.1em; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; flex: none; }
[hidden] { display: none !important; }
section[data-section].is-off, .ribbon.is-off { display: none; }

/* ---------- Préchargement ---------- */
.preloader {
  position: fixed; inset: 0; z-index: 1400; display: grid; place-items: center;
  background: radial-gradient(circle at 50% 30%, #fff, var(--bg-2) 70%);
  transition: opacity .8s ease, visibility .8s ease;
}
.preloader.is-hidden { opacity: 0; visibility: hidden; pointer-events: none; }
.preloader__center { text-align: center; }
.preloader__mark {
  font: italic 700 clamp(3rem, 9vw, 5.4rem) var(--font-display); color: var(--primary);
  animation: breathe 2.2s ease-in-out infinite;
}
.preloader__line { width: min(240px, 60vw); height: 3px; margin: 14px auto 12px; border-radius: 999px; background: rgba(139,53,85,.14); overflow: hidden; }
.preloader__line span { display: block; width: 45%; height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--rose), var(--primary), var(--gold)); animation: loading 1.3s ease-in-out infinite; }
.preloader__text { margin: 0; color: var(--text-soft); font-family: var(--font-display); font-style: italic; font-size: 1.15rem; }
@keyframes loading { from { transform: translateX(-120%); } to { transform: translateX(260%); } }
@keyframes breathe { 0%, 100% { transform: scale(1); opacity: .9; } 50% { transform: scale(1.06); opacity: 1; } }

/* ---------- Couches d'ambiance ---------- */
.aurora { position: fixed; inset: -20%; z-index: 0; pointer-events: none; overflow: hidden; }
.aurora i {
  position: absolute; border-radius: 50%; filter: blur(70px); opacity: .55; mix-blend-mode: multiply;
  animation: aurora calc(38s * var(--speed)) ease-in-out infinite alternate;
}
.aurora i:nth-child(1) { width: 55vw; height: 55vw; left: -10%; top: 5%; background: radial-gradient(circle, rgba(244,180,200,.7), transparent 65%); }
.aurora i:nth-child(2) { width: 50vw; height: 50vw; right: -10%; top: 25%; background: radial-gradient(circle, rgba(239,205,170,.55), transparent 65%); animation-delay: -12s; animation-duration: calc(46s * var(--speed)); }
.aurora i:nth-child(3) { width: 45vw; height: 45vw; left: 25%; bottom: -10%; background: radial-gradient(circle, rgba(214,150,190,.5), transparent 65%); animation-delay: -25s; animation-duration: calc(52s * var(--speed)); }
@keyframes aurora { 0% { transform: translate(0,0) scale(1); } 50% { transform: translate(6vw, -4vh) scale(1.12); } 100% { transform: translate(-4vw, 5vh) scale(.95); } }

.petals { position: fixed; inset: 0; z-index: 60; pointer-events: none; overflow: hidden; }
.petal { position: absolute; top: -8vh; left: 0; width: 20px; height: 14px; opacity: var(--petal-opacity); animation: petal-fall linear infinite; will-change: transform; }
.petal i {
  display: block; width: 100%; height: 100%; border-radius: 85% 15% 80% 20% / 75% 20% 80% 25%;
  background: radial-gradient(circle at 30% 30%, rgba(255,255,255,.7), rgba(255,255,255,0) 45%), linear-gradient(135deg, #f7bfd0, #d8789a 60%, #b05575);
  box-shadow: 0 2px 6px rgba(120,40,70,.18);
  animation: petal-sway ease-in-out infinite alternate;
}
.petal--light i { background: radial-gradient(circle at 30% 30%, rgba(255,255,255,.8), rgba(255,255,255,0) 45%), linear-gradient(135deg, #fde3ea, #f2b8c9 60%, #e08faa); }
.petal--gold i { background: radial-gradient(circle at 30% 30%, rgba(255,255,255,.7), rgba(255,255,255,0) 45%), linear-gradient(135deg, #f7e6bd, #dcbb77 60%, #c39a4e); }
@keyframes petal-fall { 0% { transform: translate3d(0, -8vh, 0) rotate(0deg); } 100% { transform: translate3d(var(--drift, 80px), 112vh, 0) rotate(var(--spin, 520deg)); } }
@keyframes petal-sway { from { transform: rotate(-18deg) scale(var(--s, 1)); } to { transform: rotate(22deg) scale(var(--s, 1)); } }

.sparkles { position: absolute; inset: 0; pointer-events: none; z-index: 1; overflow: hidden; }
.sparkles i {
  position: absolute; width: 6px; height: 6px; border-radius: 50%; opacity: 0;
  background: radial-gradient(circle, #fff 0%, var(--gold-light) 45%, transparent 70%);
  box-shadow: 0 0 10px 2px rgba(239,217,164,.55);
  animation: twinkle calc(var(--d, 4s) * var(--speed)) ease-in-out infinite; animation-delay: var(--delay, 0s);
}
.sparkles i::before { content: ""; position: absolute; inset: -6px; background: linear-gradient(var(--gold-light), transparent) center/2px 100% no-repeat, linear-gradient(90deg, var(--gold-light), transparent) center/100% 2px no-repeat; opacity: .6; }
@keyframes twinkle { 0%, 100% { opacity: 0; transform: scale(.3); } 50% { opacity: 1; transform: scale(1); } }

.cursor-glow { position: fixed; width: 320px; height: 320px; margin: -160px 0 0 -160px; border-radius: 50%; pointer-events: none; z-index: 1; opacity: .38; filter: blur(50px); background: radial-gradient(circle, rgba(240,175,195,.55), transparent 62%); transition: opacity .4s; }
.cursor-glow.is-off { opacity: 0; }

.progress-bar { position: fixed; top: 0; left: 0; height: 3px; width: 0; z-index: 1300; background: linear-gradient(90deg, var(--primary), var(--rose), var(--gold)); box-shadow: 0 2px 10px rgba(139,53,85,.35); }
.preview-badge { position: fixed; left: 50%; bottom: 14px; transform: translateX(-50%); z-index: 1250; padding: 8px 14px; border-radius: 999px; background: var(--deep); color: #fff; font-size: .8rem; letter-spacing: .02em; box-shadow: var(--shadow-soft); }
@media (max-width: 760px) { .preview-badge { bottom: 92px; } }

/* ---------- Décor floral (bords fondus) ---------- */
.deco { position: absolute; pointer-events: none; z-index: 1; user-select: none; will-change: transform; transform: translate3d(0, var(--py, 0px), 0); animation: deco-sway calc(11s * var(--speed)) ease-in-out infinite alternate; }
.deco--tl { top: -30px; left: -30px; width: clamp(180px, 30vw, 460px); }
.deco--tr { top: -30px; right: -30px; width: clamp(170px, 26vw, 400px); animation-delay: -4s; }
.deco--bl { bottom: -30px; left: -30px; width: clamp(160px, 24vw, 360px); animation-delay: -7s; }
.deco--br { bottom: -30px; right: -30px; width: clamp(180px, 28vw, 440px); animation-delay: -2s; }
.deco--hearts { top: 7%; right: 23%; width: clamp(70px, 8vw, 120px); z-index: 3; animation: deco-float calc(7s * var(--speed)) ease-in-out infinite alternate; }
.deco--side-r { right: -10px; top: 14%; width: clamp(110px, 14vw, 190px); }
.deco--silk-bl { left: -10px; bottom: -10px; width: clamp(160px, 24vw, 330px); animation-delay: -5s; }
.deco--rose-a { left: 3%; bottom: 8%; width: clamp(80px, 9vw, 150px); animation: deco-float calc(9s * var(--speed)) ease-in-out infinite alternate; }
.deco--rose-b { right: 4%; bottom: 10%; width: clamp(80px, 9vw, 140px); animation: deco-float calc(8s * var(--speed)) ease-in-out infinite alternate-reverse; }
.deco--right { left: auto; right: 3%; }
.deco--soft { opacity: .75; }
.deco--dim { opacity: .38; mix-blend-mode: screen; }
@keyframes deco-sway { from { transform: translate3d(0, var(--py, 0px), 0) rotate(-1.2deg) scale(1); } to { transform: translate3d(0, calc(var(--py, 0px) - 10px), 0) rotate(1.4deg) scale(1.03); } }
@keyframes deco-float { from { transform: translate3d(0, var(--py, 0px), 0) rotate(-4deg); } to { transform: translate3d(6px, calc(var(--py, 0px) - 14px), 0) rotate(5deg); } }

.silk { position: absolute; left: 0; right: 0; bottom: -2px; z-index: 2; pointer-events: none; line-height: 0; }
.silk img { width: 100%; height: clamp(90px, 16vw, 220px); object-fit: cover; object-position: center top; animation: silk-flow calc(16s * var(--speed)) ease-in-out infinite alternate; transform-origin: center bottom; }
@keyframes silk-flow { from { transform: scaleX(1) translateX(0); } to { transform: scaleX(1.05) translateX(-1.5%); } }

/* ---------- En-tête ---------- */
.site-header {
  position: sticky; top: 0; z-index: 900;
  background: rgba(255, 246, 248, 0.6);
  backdrop-filter: blur(18px) saturate(1.3); -webkit-backdrop-filter: blur(18px) saturate(1.3);
  border-bottom: 1px solid rgba(139,53,85,.06);
  transition: background .35s ease, box-shadow .35s ease;
}
.site-header.is-scrolled { background: rgba(255, 246, 248, 0.88); box-shadow: 0 10px 30px rgba(110,40,65,.08); }
.header__inner { display: grid; grid-template-columns: auto 1fr auto auto; align-items: center; gap: 18px; min-height: var(--header-h); }
.brand__mark { font: italic 700 clamp(1.7rem, 3vw, 2.2rem) var(--font-display); color: var(--primary); letter-spacing: .01em; white-space: nowrap; }
.main-nav { display: flex; justify-content: center; gap: clamp(14px, 2vw, 28px); flex-wrap: wrap; }
.main-nav a, .footer__nav a { position: relative; font-size: .92rem; font-weight: 500; color: var(--text); padding: 4px 0; }
.main-nav a::after, .footer__nav a::after { content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 1.5px; background: linear-gradient(90deg, var(--primary), var(--gold)); transform: scaleX(0); transform-origin: center; transition: transform .3s ease; }
.main-nav a:hover::after, .main-nav a.is-active::after, .footer__nav a:hover::after { transform: scaleX(1); }
.main-nav a.is-active { color: var(--primary); }
.header__actions { display: flex; gap: 10px; align-items: center; }
.chip { display: inline-flex; align-items: center; gap: 8px; border-radius: 999px; padding: 10px 16px; border: 1px solid transparent; font-weight: 600; font-size: .9rem; cursor: pointer; transition: transform .25s ease, box-shadow .25s ease; }
.chip:hover { transform: translateY(-2px); }
.chip--outline { border-color: var(--line); background: rgba(255,255,255,.7); color: var(--primary); }
.chip--filled { background: linear-gradient(135deg, var(--primary), #b25a7c); color: #fff; box-shadow: var(--shadow-soft); }
.chip--filled .ic { fill: currentColor; stroke: none; }
.menu-toggle { display: none; width: 44px; height: 44px; border: 0; background: transparent; padding: 9px; cursor: pointer; border-radius: 12px; }
.menu-toggle span { display: block; width: 24px; height: 2px; margin: 5px auto; border-radius: 99px; background: var(--primary); transition: transform .3s ease, opacity .3s ease; }
.menu-toggle.is-open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.menu-toggle.is-open span:nth-child(2) { opacity: 0; }
.menu-toggle.is-open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

.mobile-menu { position: fixed; inset: 0; z-index: 890; background: rgba(90,31,54,.35); backdrop-filter: blur(6px); opacity: 0; visibility: hidden; transition: opacity .35s ease, visibility .35s ease; }
.mobile-menu.is-open { opacity: 1; visibility: visible; }
.mobile-menu__panel { position: absolute; top: calc(var(--header-h) + 8px); left: 12px; right: 12px; padding: 22px 20px 20px; border-radius: 26px; background: linear-gradient(180deg, #fffafb, #fdeef2); box-shadow: var(--shadow); transform: translateY(-14px) scale(.98); transition: transform .35s cubic-bezier(.2,.8,.2,1); border: 1px solid rgba(212,176,106,.35); }
.mobile-menu.is-open .mobile-menu__panel { transform: none; }
.mobile-menu__mark { text-align: center; font: italic 700 2.2rem var(--font-display); color: var(--primary); margin-bottom: 8px; }
.mobile-menu nav { display: grid; gap: 4px; margin-bottom: 14px; }
.mobile-menu nav a { display: block; padding: 12px 14px; border-radius: 14px; font-family: var(--font-display); font-size: 1.35rem; font-weight: 600; color: var(--deep); transition: background .25s; }
.mobile-menu nav a:hover { background: rgba(139,53,85,.08); }
.mobile-menu nav a.is-off { display: none; }
.mobile-menu .btn { width: 100%; }

/* ---------- Boutons ---------- */
.btn { position: relative; overflow: hidden; border: 0; cursor: pointer; border-radius: 999px; padding: 15px 24px; display: inline-flex; align-items: center; justify-content: center; gap: 10px; font-weight: 600; font-size: .98rem; transition: transform .28s cubic-bezier(.2,.8,.2,1), box-shadow .28s ease, background .28s ease; }
.btn:hover { transform: translateY(-3px); }
.btn:active { transform: translateY(-1px) scale(.99); }
.btn--primary { background: linear-gradient(135deg, var(--deep) 0%, var(--primary) 55%, #b25a7c 100%); color: #fff; box-shadow: 0 16px 34px rgba(110,40,65,.28), inset 0 1px 0 rgba(255,255,255,.25); }
.btn--primary .ic { fill: currentColor; stroke: none; }
.btn--ghost { background: rgba(255,255,255,.78); color: var(--primary); border: 1px solid rgba(139,53,85,.14); box-shadow: var(--shadow-soft); }
.btn--light { background: #fff; color: var(--primary); box-shadow: 0 16px 34px rgba(0,0,0,.18); }
.btn--ghost-light { background: rgba(255,255,255,.12); color: #fff; border: 1px solid rgba(255,255,255,.35); backdrop-filter: blur(6px); }
.btn--ghost-light:hover { background: rgba(255,255,255,.2); }
.btn--block { width: 100%; }
.btn--shine::after { content: ""; position: absolute; top: -60%; bottom: -60%; left: -40%; width: 40%; background: linear-gradient(105deg, transparent 20%, rgba(255,255,255,.55) 50%, transparent 80%); transform: skewX(-20deg) translateX(-100%); animation: shine calc(4.5s * var(--speed)) ease-in-out infinite; }
@keyframes shine { 0%, 60% { transform: skewX(-20deg) translateX(-140%); } 100% { transform: skewX(-20deg) translateX(520%); } }
.round-btn { width: 50px; height: 50px; border-radius: 50%; border: 1px solid rgba(139,53,85,.14); background: rgba(255,255,255,.85); color: var(--primary); cursor: pointer; display: inline-grid; place-items: center; box-shadow: var(--shadow-soft); transition: transform .25s ease, background .25s ease; }
.round-btn:hover { transform: scale(1.06); background: #fff; }
.round-btn .ic { width: 22px; height: 22px; }

/* ---------- Accueil ---------- */
.hero { position: relative; overflow: clip; isolation: isolate; padding: clamp(24px, 4vw, 54px) 0 clamp(120px, 16vw, 200px); background: linear-gradient(180deg, #fff9fa 0%, #fbe7ec 100%); }
.hero__bg { position: absolute; inset: -6%; z-index: 0; background-size: cover; background-position: center 30%; opacity: var(--bg-opacity, .55); filter: blur(var(--bg-blur, 6px)) saturate(1.1); transform: scale(1.04); animation: bg-zoom calc(30s * var(--speed)) ease-in-out infinite alternate; }
.hero__veil { position: absolute; inset: 0; z-index: 0; background: radial-gradient(ellipse at 50% 35%, rgba(255,255,255,.72), rgba(255,246,248,.5) 45%, rgba(251,231,236,.92) 100%); }
@keyframes bg-zoom { from { transform: scale(1.04) translate(0,0); } to { transform: scale(1.12) translate(-1.5%, 1%); } }
.hero__grid { min-height: calc(100svh - var(--header-h) - 60px); display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.25fr) minmax(0, .8fr); gap: clamp(18px, 3vw, 44px); align-items: center; }
.hero__text { text-align: center; position: relative; z-index: 3; padding: 10px 0; }

.eyebrow { text-shadow: 0 0 12px rgba(255,246,248,.95), 0 0 24px rgba(255,246,248,.9); margin: 0 0 6px; font-family: var(--font-script); font-size: clamp(1.5rem, 2.4vw, 2rem); color: var(--rose); animation: names-glow calc(6s * var(--speed)) ease-in-out infinite; }
.title { margin: 0; line-height: .86; font-family: var(--font-display); font-weight: 700; color: var(--primary); display: grid; justify-items: center; }
.title__word { font-size: clamp(3.9rem, 9vw, 8rem); letter-spacing: -.01em; background: linear-gradient(100deg, var(--deep) 0%, var(--primary) 30%, #c0688a 48%, var(--gold) 58%, var(--primary) 72%, var(--deep) 100%); background-size: 260% 100%; -webkit-background-clip: text; background-clip: text; color: transparent; animation: shimmer calc(7s * var(--speed)) ease-in-out infinite; }
.title__word--bottom { animation-delay: -1.5s; }
.title__script { font-family: var(--font-script); font-size: clamp(2.6rem, 5.4vw, 4.6rem); color: var(--rose); line-height: .9; margin: .1em 0 0 -.9em; transform: rotate(-6deg); text-shadow: 0 6px 20px rgba(217,138,163,.35); animation: names-glow calc(5s * var(--speed)) ease-in-out infinite; }
@keyframes shimmer { 0% { background-position: 100% 0; } 100% { background-position: -100% 0; } }
.names { margin: 10px 0 0; font-family: var(--font-script); font-size: clamp(2.6rem, 5.6vw, 4.4rem); line-height: 1.05; color: var(--primary); text-shadow: 0 8px 26px rgba(139,53,85,.18); animation: names-glow calc(5s * var(--speed)) ease-in-out infinite; }
.names em { font-style: normal; color: var(--gold); font-size: .78em; }
@keyframes names-glow { 0%, 100% { filter: drop-shadow(0 0 0 rgba(212,176,106,0)); } 50% { filter: drop-shadow(0 0 12px rgba(212,176,106,.55)); } }

.hero__meta { display: flex; justify-content: center; flex-wrap: wrap; gap: 10px; margin-top: 16px; }
.pill { display: inline-flex; align-items: center; gap: 9px; padding: 10px 16px; border-radius: 999px; background: rgba(255,255,255,.78); border: 1px solid rgba(212,176,106,.45); box-shadow: 0 8px 22px rgba(110,40,65,.1); color: var(--deep); font-size: .88rem; letter-spacing: .05em; text-transform: uppercase; }
.pill .ic { color: var(--primary); }
.hero__quote { margin: 18px auto 0; max-width: 520px; font-family: var(--font-display); font-style: italic; font-size: clamp(1.2rem, 2vw, 1.45rem); color: var(--text-soft); line-height: 1.45; }
.hero__actions { display: flex; justify-content: center; flex-wrap: wrap; gap: 12px; margin-top: 24px; }
.hero__scroll { display: inline-flex; flex-direction: column; align-items: center; gap: 8px; margin-top: 30px; color: var(--text-soft); font-size: .78rem; letter-spacing: .12em; text-transform: uppercase; }
.hero__scroll i { width: 1px; height: 38px; background: linear-gradient(var(--primary), transparent); animation: scroll-hint calc(1.8s * var(--speed)) ease-in-out infinite; transform-origin: top; }
@keyframes scroll-hint { 0% { transform: scaleY(0); opacity: 0; } 40% { transform: scaleY(1); opacity: 1; } 100% { transform: scaleY(1) translateY(10px); opacity: 0; } }

/* Cadres en arche */
.arch { margin: 0; position: relative; z-index: 2; animation: arch-float calc(7s * var(--speed)) ease-in-out infinite alternate; }
.arch--main { justify-self: end; width: min(100%, 420px); }
.arch--side { justify-self: start; width: min(100%, 330px); animation-delay: -3.2s; margin-top: clamp(20px, 8vw, 90px); }
.arch__frame { position: relative; overflow: hidden; border-radius: 999px 999px 26px 26px; aspect-ratio: 3 / 4.1; background: var(--bg-2); box-shadow: var(--shadow-gold), var(--shadow); }
.arch__frame::after { content: ""; position: absolute; inset: 10px; border-radius: 999px 999px 18px 18px; border: 1px solid rgba(239,217,164,.85); pointer-events: none; box-shadow: inset 0 0 40px rgba(255,255,255,.1); }
.arch__frame::before { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none; background: linear-gradient(180deg, rgba(255,255,255,.08), transparent 30%, transparent 70%, rgba(90,31,54,.18)); }
.arch__frame img { width: 100%; height: 100%; object-fit: cover; object-position: var(--pos, center); }
.arch__caption { margin-top: 14px; text-align: center; font-family: var(--font-script); font-size: clamp(1.5rem, 2.2vw, 1.9rem); line-height: 1.1; color: var(--primary); }
.arch__quote { margin-top: 14px; text-align: center; font-family: var(--font-script); font-size: clamp(1.5rem, 2.2vw, 1.9rem); line-height: 1.15; color: var(--primary); max-width: 300px; margin-inline: auto; }
@keyframes arch-float { from { transform: translate3d(0, 0, 0) rotate(-.6deg); } to { transform: translate3d(0, -14px, 0) rotate(.6deg); } }
.kenburns { animation: kenburns calc(22s * var(--speed)) ease-in-out infinite alternate; transform-origin: 50% 40%; will-change: transform; }
.kenburns--alt { animation-name: kenburns-alt; animation-duration: calc(26s * var(--speed)); }
@keyframes kenburns { from { transform: scale(1) translate(0, 0); } to { transform: scale(1.12) translate(-2%, 2%); } }
@keyframes kenburns-alt { from { transform: scale(1.1) translate(2%, -1%); } to { transform: scale(1) translate(0, 0); } }

/* ---------- Ruban défilant ---------- */
.ribbon { position: relative; z-index: 3; overflow: hidden; background: linear-gradient(90deg, var(--deep), var(--primary) 40%, #a24d70 60%, var(--deep)); color: #fbe4ec; border-top: 1px solid rgba(239,217,164,.5); border-bottom: 1px solid rgba(239,217,164,.5); box-shadow: 0 12px 30px rgba(90,31,54,.2); }
.ribbon__track { display: flex; width: max-content; animation: ribbon calc(38s * var(--speed)) linear infinite; }
.ribbon__track:hover { animation-play-state: paused; }
.ribbon__item { display: inline-flex; align-items: center; gap: 22px; padding: 12px 22px; font-family: var(--font-display); font-size: 1.2rem; letter-spacing: .06em; white-space: nowrap; }
.ribbon__item i { color: var(--gold-light); font-style: normal; font-size: 1rem; animation: heart-pulse calc(1.6s * var(--speed)) ease-in-out infinite; }
@keyframes ribbon { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes heart-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.25); } }

/* ---------- Sections ---------- */
.section { position: relative; padding: clamp(80px, 10vw, 120px) 0; overflow: clip; isolation: isolate; }
.section-bg { position: absolute; inset: -8%; z-index: 0; background-size: cover; background-position: center; opacity: var(--bg-opacity, .12); filter: blur(var(--bg-blur, 12px)) saturate(1.15); pointer-events: none; animation: bg-zoom calc(40s * var(--speed)) ease-in-out infinite alternate; }
.section-title { position: relative; z-index: 1; text-align: center; margin: 0 auto clamp(34px, 5vw, 52px); max-width: 780px; }
.section-title h2, .closing h2 { margin: 0; font-family: var(--font-script); font-weight: 400; font-size: clamp(2.9rem, 6.4vw, 4.8rem); line-height: 1.05; color: var(--primary); text-shadow: 0 10px 30px rgba(139,53,85,.14); }
.section-title p { margin: 8px auto 0; font-family: var(--font-display); font-size: clamp(1.15rem, 1.6vw, 1.35rem); color: var(--text-soft); max-width: 620px; }
.section-title--light h2, .section-title--light p { color: #fff; text-shadow: 0 6px 24px rgba(0,0,0,.25); }
.section-title--left { text-align: left; }
.section-title--left p { margin-inline: 0; }
.flourish { width: 220px; margin: 6px auto 4px; }
.flourish--left { margin-inline: 0; }
.flourish svg { width: 100%; height: 26px; overflow: visible; }
.flourish__line { fill: none; stroke: var(--gold); stroke-width: 1.4; stroke-linecap: round; stroke-dasharray: 120; stroke-dashoffset: 120; transition: stroke-dashoffset 1.6s ease .2s; }
.reveal.is-visible .flourish__line { stroke-dashoffset: 0; }
.flourish__heart { fill: var(--primary); transform-origin: 110px 12px; animation: heart-pulse calc(2s * var(--speed)) ease-in-out infinite; }
.section-note { text-align: center; margin: 26px 0 0; font-family: var(--font-script); font-size: clamp(1.6rem, 2.4vw, 2rem); color: var(--text-soft); position: relative; z-index: 2; text-shadow: 0 0 12px rgba(255,246,248,.95), 0 0 24px rgba(255,246,248,.9); }

/* Cartes univers */
.universe-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(18px, 2.6vw, 30px); }
.ucard { position: relative; padding: 12px; border-radius: 20px; background: linear-gradient(160deg, rgba(255,255,255,.85), rgba(255,240,244,.7)); border: 1px solid rgba(212,176,106,.35); box-shadow: var(--shadow-soft); transition: transform .5s cubic-bezier(.2,.8,.2,1), box-shadow .5s ease; transform-style: preserve-3d; }
.ucard:hover { transform: translateY(-8px) rotateX(2deg); box-shadow: var(--shadow); }
.ucard__media { position: relative; overflow: hidden; border-radius: 14px; aspect-ratio: 3 / 3.7; box-shadow: inset 0 0 0 1px rgba(239,217,164,.9); }
.ucard__media::after { content: ""; position: absolute; inset: 8px; border: 1px solid rgba(239,217,164,.75); border-radius: 9px; pointer-events: none; z-index: 2; }
.ucard__media::before { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none; background: linear-gradient(180deg, transparent 60%, rgba(90,31,54,.22)); }
.ucard__media img { width: 100%; height: 100%; object-fit: cover; object-position: var(--pos, center); }
.ucard__caption { padding: 16px 6px 6px; text-align: center; font-family: var(--font-display); font-weight: 600; font-size: 1.3rem; color: var(--deep); }
.ucard__heart { text-align: center; color: var(--primary); font-size: 1.1rem; line-height: 1; padding-bottom: 6px; animation: heart-pulse calc(2.4s * var(--speed)) ease-in-out infinite; }
.ucard:nth-child(2) { margin-top: clamp(0px, 3vw, 34px); }
.ucard:nth-child(2) .kenburns { animation-name: kenburns-alt; }

/* Souvenirs (polaroïds) */
.memories__wrap { position: relative; }
.memories__viewport { overflow-x: auto; overflow-y: hidden; scrollbar-width: none; -ms-overflow-style: none; padding: 26px 0 30px; cursor: grab; -webkit-overflow-scrolling: touch; }
.memories__viewport::-webkit-scrollbar { display: none; }
.memories__viewport.is-dragging { cursor: grabbing; scroll-behavior: auto; }
.memories__track { display: flex; gap: clamp(18px, 3vw, 36px); width: max-content; padding: 0 12px; }
.polaroid { flex: none; width: clamp(200px, 22vw, 270px); padding: 12px 12px 14px; background: #fffdfd; border-radius: 8px; box-shadow: 0 18px 40px rgba(90,31,54,.18), 0 2px 0 rgba(255,255,255,.7) inset; transform: rotate(var(--r, 0deg)); transition: transform .45s cubic-bezier(.2,.8,.2,1), box-shadow .45s; cursor: zoom-in; border: 1px solid rgba(212,176,106,.3); }
.polaroid:hover { transform: rotate(0deg) translateY(-8px) scale(1.03); box-shadow: 0 30px 60px rgba(90,31,54,.26); z-index: 2; }
.polaroid__img { overflow: hidden; aspect-ratio: 3 / 3.6; border-radius: 3px; background: var(--bg-2); }
.polaroid__img img { width: 100%; height: 100%; object-fit: cover; }
.polaroid__caption { margin-top: 12px; text-align: center; font-family: var(--font-script); font-size: 1.5rem; line-height: 1.1; color: var(--primary); }
.polaroid__caption i { color: var(--rose); font-style: normal; }
.memories__btn { position: absolute; top: 50%; transform: translateY(-50%); z-index: 3; }
.memories__btn--prev { left: -14px; }
.memories__btn--next { right: -14px; }

/* Histoire (timeline) */
.timeline { list-style: none; margin: 0 auto; padding: 0; max-width: 760px; position: relative; }
.timeline::before { content: ""; position: absolute; left: 22px; top: 0; bottom: 0; width: 1px; background: linear-gradient(var(--gold), var(--rose), var(--gold)); }
.timeline li { position: relative; padding: 0 0 30px 64px; }
.timeline li::before { content: "♥"; position: absolute; left: 10px; top: 2px; width: 26px; height: 26px; border-radius: 50%; background: #fff; border: 1px solid var(--gold); display: grid; place-items: center; color: var(--primary); font-size: .8rem; box-shadow: var(--shadow-soft); }
.timeline time { display: block; font-size: .82rem; letter-spacing: .1em; text-transform: uppercase; color: var(--text-soft); }
.timeline h3 { margin: 4px 0 6px; font-family: var(--font-display); font-size: 1.6rem; color: var(--deep); }
.timeline p { margin: 0; color: var(--text-soft); }

/* Compte à rebours */
.countdown { position: relative; padding: clamp(80px, 10vw, 130px) 0; overflow: clip; isolation: isolate; color: #fff; background: linear-gradient(135deg, #4a1729, var(--primary) 55%, #a24d70); }
.countdown__bg { position: absolute; inset: -6%; z-index: 0; background-size: cover; background-position: center 30%; opacity: var(--bg-opacity, .35); filter: blur(var(--bg-blur, 4px)); animation: bg-zoom calc(34s * var(--speed)) ease-in-out infinite alternate; mix-blend-mode: luminosity; }
.countdown__veil { position: absolute; inset: 0; z-index: 0; background: linear-gradient(180deg, rgba(74,23,41,.55), rgba(139,53,85,.35) 50%, rgba(74,23,41,.6)); }
.countdown__inner { text-align: center; }
.countdown__grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(12px, 2vw, 22px); max-width: 860px; margin: 0 auto; }
.tile { position: relative; padding: clamp(18px, 3vw, 30px) 10px; border-radius: 22px; background: rgba(255,255,255,.1); border: 1px solid rgba(239,217,164,.55); backdrop-filter: blur(8px); box-shadow: 0 20px 50px rgba(0,0,0,.18), inset 0 1px 0 rgba(255,255,255,.3); overflow: hidden; }
.tile::before { content: ""; position: absolute; inset: 6px; border-radius: 16px; border: 1px solid rgba(239,217,164,.35); pointer-events: none; }
.tile__num { font-family: var(--font-display); font-weight: 600; font-size: clamp(2.4rem, 6vw, 4.4rem); line-height: 1; color: #fff; text-shadow: 0 6px 20px rgba(0,0,0,.25); font-variant-numeric: tabular-nums; }
.tile__num.is-flip { animation: flip .5s cubic-bezier(.2,.8,.2,1); }
@keyframes flip { 0% { transform: translateY(-40%) rotateX(60deg); opacity: 0; } 100% { transform: none; opacity: 1; } }
.tile__label { margin-top: 8px; font-size: .78rem; letter-spacing: .18em; text-transform: uppercase; color: var(--gold-light); }
.countdown__actions { display: flex; justify-content: center; flex-wrap: wrap; gap: 12px; margin-top: 30px; }
.countdown.is-done .countdown__grid { display: none; }

/* Thème */
.theme__grid { display: grid; grid-template-columns: 1.1fr .9fr; gap: clamp(28px, 5vw, 70px); align-items: center; }
.palette { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 22px 14px; margin-top: 24px; max-width: 520px; }
.swatch { display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; color: var(--text-soft); font-size: .9rem; font-weight: 500; }
.swatch i { position: relative; width: clamp(64px, 7vw, 82px); aspect-ratio: 1; border-radius: 50%; display: block; animation: swatch-bob calc(5s * var(--speed)) ease-in-out infinite alternate; animation-delay: var(--delay, 0s); filter: drop-shadow(0 12px 18px rgba(90,31,54,.2)); }
.swatch i::before { content: ""; position: absolute; inset: 0; border-radius: 50%; background: conic-gradient(from 0deg, var(--gold), #fff6f8, var(--gold), #fff6f8, var(--gold)); animation: spin calc(14s * var(--speed)) linear infinite; }
.swatch i::after { content: ""; position: absolute; inset: 3px; border: 4px solid #fff; border-radius: 50%; background: var(--c); box-shadow: inset 0 -8px 16px rgba(0,0,0,.12), inset 0 6px 10px rgba(255,255,255,.35); }
@keyframes swatch-bob { from { transform: translateY(0); } to { transform: translateY(-7px); } }
@keyframes spin { to { transform: rotate(360deg); } }
.theme__note { margin: 22px 0 0; font-size: clamp(1.5rem, 2.2vw, 1.9rem); color: var(--primary); text-shadow: 0 0 14px rgba(255,246,248,.95), 0 0 28px rgba(255,246,248,.9); }
.theme .deco--silk-bl { opacity: .55; left: -8%; bottom: -14%; }
.swatch span { text-shadow: 0 0 10px rgba(255,246,248,.95), 0 0 20px rgba(255,246,248,.9); }
.theme__poster { perspective: 1200px; }
.poster { margin: 0; position: relative; width: min(100%, 400px); margin-inline: auto; animation: arch-float calc(8s * var(--speed)) ease-in-out infinite alternate; }
.poster__inner { position: relative; border-radius: 18px; overflow: hidden; box-shadow: var(--shadow-gold), var(--shadow); transform-style: preserve-3d; transition: transform .35s ease; will-change: transform; background: var(--bg-2); }
.poster__inner::after { content: ""; position: absolute; inset: 0; background: linear-gradient(115deg, transparent 30%, rgba(255,255,255,.28) 48%, transparent 60%); background-size: 240% 100%; animation: poster-glint calc(9s * var(--speed)) ease-in-out infinite; pointer-events: none; }
.poster__inner img { width: 100%; display: block; }
@keyframes poster-glint { 0%, 55% { background-position: 120% 0; } 100% { background-position: -80% 0; } }

/* Infos pratiques */
.infos-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(16px, 2vw, 24px); }
.info { position: relative; padding: 26px 22px 24px; border-radius: 20px; background: rgba(255,255,255,.72); border: 1px solid rgba(212,176,106,.35); box-shadow: var(--shadow-soft); backdrop-filter: blur(8px); transition: transform .4s cubic-bezier(.2,.8,.2,1), box-shadow .4s; display: flex; flex-direction: column; gap: 8px; }
.info:hover { transform: translateY(-6px); box-shadow: var(--shadow); }
.info__icon { width: 52px; height: 52px; border-radius: 50%; display: grid; place-items: center; color: var(--primary); background: linear-gradient(145deg, #fff, var(--bg-2)); box-shadow: 0 0 0 1px rgba(212,176,106,.6), 0 10px 20px rgba(110,40,65,.12); margin-bottom: 4px; }
.info__icon .ic { width: 24px; height: 24px; }
.info h3 { margin: 0; font-family: var(--font-display); font-size: 1.45rem; color: var(--deep); }
.info p { margin: 0; color: var(--text-soft); font-size: .95rem; flex: 1; }
.info a { align-self: flex-start; margin-top: 6px; color: var(--primary); font-weight: 600; font-size: .9rem; display: inline-flex; align-items: center; gap: 6px; border-bottom: 1px solid rgba(139,53,85,.3); padding-bottom: 2px; }

/* Galerie */
.gallery-grid { columns: 3; column-gap: 18px; }
.gitem { break-inside: avoid; margin: 0 0 18px; display: block; width: 100%; padding: 6px; border: 0; background: rgba(255,255,255,.8); border-radius: 16px; box-shadow: 0 0 0 1px rgba(212,176,106,.45), var(--shadow-soft); cursor: zoom-in; overflow: hidden; transition: transform .45s cubic-bezier(.2,.8,.2,1), box-shadow .45s; }
.gitem:hover { transform: translateY(-6px); box-shadow: 0 0 0 1px var(--gold), var(--shadow); }
.gitem__img { overflow: hidden; border-radius: 11px; }
.gitem img { width: 100%; height: auto; transition: transform .8s ease; }
.gitem:hover img { transform: scale(1.06); }

/* Clôture + RSVP */
.closing { position: relative; overflow: clip; isolation: isolate; color: #fff; padding: clamp(80px, 10vw, 130px) 0; }
.closing__media { position: absolute; inset: -4%; z-index: 0; background-size: cover; background-position: var(--pos, center); animation: bg-zoom calc(36s * var(--speed)) ease-in-out infinite alternate; }
.closing__veil { position: absolute; inset: 0; z-index: 0; background: linear-gradient(100deg, rgba(60,14,32,.82) 0%, rgba(110,40,65,.55) 55%, rgba(60,14,32,.5) 100%); }
.hearts { position: absolute; inset: 0; z-index: 1; pointer-events: none; overflow: hidden; }
.hearts i { position: absolute; bottom: -8%; left: var(--x, 50%); font-style: normal; color: rgba(255,214,226,.7); font-size: var(--fs, 18px); animation: heart-rise calc(var(--d, 12s) * var(--speed)) linear infinite; animation-delay: var(--delay, 0s); text-shadow: 0 0 12px rgba(255,180,205,.6); }
@keyframes heart-rise { 0% { transform: translateY(0) scale(.6) rotate(0); opacity: 0; } 10% { opacity: 1; } 100% { transform: translateY(-115vh) scale(1.3) rotate(25deg); opacity: 0; } }
.closing__grid { display: grid; grid-template-columns: 1.05fr .95fr; gap: clamp(28px, 5vw, 70px); align-items: center; }
.closing__tag { margin: 0 0 8px; font-size: clamp(1.9rem, 3vw, 2.6rem); color: var(--rose-light); }
.closing h2 { color: #fff; font-family: var(--font-display); font-weight: 600; font-size: clamp(2.2rem, 4.2vw, 3.4rem); line-height: 1.1; text-shadow: 0 8px 26px rgba(0,0,0,.3); }
.closing__desc { color: rgba(255,240,245,.88); font-size: 1.05rem; max-width: 520px; }
.closing__facts { list-style: none; padding: 0; margin: 22px 0 26px; display: grid; gap: 10px; max-width: 460px; }
.closing__facts li { display: flex; justify-content: space-between; gap: 14px; padding: 10px 0; border-bottom: 1px solid rgba(255,255,255,.18); }
.closing__facts span { color: var(--gold-light); font-size: .8rem; letter-spacing: .14em; text-transform: uppercase; }
.rsvp { position: relative; z-index: 2; }
.rsvp__card { padding: clamp(24px, 3.4vw, 36px); border-radius: 26px; background: linear-gradient(180deg, rgba(255,250,251,.96), rgba(253,238,242,.96)); color: var(--text); box-shadow: var(--shadow-gold), var(--shadow); display: grid; gap: 14px; }
.rsvp__card h3, .rsvp__success h3 { margin: 0; text-align: center; font-family: var(--font-script); font-weight: 400; font-size: clamp(2.2rem, 3.2vw, 2.8rem); color: var(--primary); }
.rsvp__intro { margin: -6px 0 0; text-align: center; color: var(--text-soft); font-size: .95rem; }
.field { display: grid; gap: 6px; font-size: .84rem; font-weight: 600; color: var(--deep); }
.field input, .field select, .field textarea { width: 100%; font: inherit; font-weight: 500; color: var(--text); padding: 12px 14px; border-radius: 14px; border: 1px solid rgba(139,53,85,.18); background: #fff; transition: border-color .25s, box-shadow .25s; }
.field input:focus, .field select:focus, .field textarea:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 4px rgba(139,53,85,.12); }
.field textarea { resize: vertical; min-height: 84px; }
.choice { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.choice label { position: relative; display: flex; align-items: center; gap: 8px; padding: 12px 14px; border-radius: 14px; border: 1px solid rgba(139,53,85,.18); background: #fff; cursor: pointer; font-weight: 500; transition: border-color .25s, background .25s; }
.choice input { position: absolute; opacity: 0; }
.choice i { width: 16px; height: 16px; border-radius: 50%; border: 2px solid rgba(139,53,85,.35); display: inline-block; flex: none; transition: .25s; }
.choice input:checked + i { border-color: var(--primary); background: radial-gradient(circle, var(--primary) 45%, transparent 50%); }
.choice input:checked ~ * { color: var(--primary); }
.choice label:has(input:checked) { border-color: var(--primary); background: rgba(139,53,85,.06); }
.rsvp__deadline { margin: 0; display: flex; align-items: center; gap: 8px; justify-content: center; color: var(--text-soft); font-size: .86rem; }
.rsvp__hint { margin: -4px 0 0; text-align: center; color: var(--text-soft); font-size: .8rem; min-height: 1em; }
.rsvp__success { padding: clamp(28px, 4vw, 44px); border-radius: 26px; background: linear-gradient(180deg, rgba(255,250,251,.96), rgba(253,238,242,.96)); color: var(--text); box-shadow: var(--shadow-gold), var(--shadow); text-align: center; display: grid; gap: 12px; justify-items: center; animation: pop .5s cubic-bezier(.2,.8,.2,1); }
.rsvp__success-heart { font-size: 3.6rem; color: var(--primary); line-height: 1; animation: heart-pulse 1.4s ease-in-out infinite; }
.rsvp__success p { margin: 0; color: var(--text-soft); }
@keyframes pop { from { transform: scale(.9); opacity: 0; } to { transform: none; opacity: 1; } }

/* Pied de page */
.site-footer { position: relative; z-index: 2; background: linear-gradient(180deg, #fffafb, #fbe7ec); border-top: 1px solid rgba(212,176,106,.4); padding: 34px 0 30px; }
.footer__inner { display: grid; grid-template-columns: 1fr auto auto; gap: 18px 28px; align-items: center; }
.footer__brand { display: flex; gap: 14px; align-items: center; }
.footer__brand p { margin: 0; color: var(--text-soft); font-size: .9rem; }
.footer__brand b { font-family: var(--font-display); font-size: 1.25rem; color: var(--deep); }
.footer__nav { display: flex; gap: 16px; flex-wrap: wrap; justify-content: center; }
.footer__nav a.is-off { display: none; }
.footer__socials { display: flex; gap: 10px; }
.footer__socials a { width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center; color: var(--primary); background: #fff; box-shadow: 0 0 0 1px rgba(212,176,106,.5), var(--shadow-soft); transition: transform .25s; }
.footer__socials a:hover { transform: translateY(-3px); }
.footer__socials a svg { width: 18px; height: 18px; }
.footer__note { grid-column: 1 / -1; margin: 6px 0 0; text-align: center; color: var(--text-soft); font-size: .9rem; display: flex; justify-content: center; align-items: baseline; gap: 14px; flex-wrap: wrap; }
.footer__amour { font-size: 1.45rem; color: var(--primary); }

/* Barre mobile */
.dock { position: fixed; left: 50%; bottom: max(12px, env(safe-area-inset-bottom)); transform: translateX(-50%); z-index: 850; display: none; width: min(94vw, 420px); padding: 8px; gap: 4px; grid-template-columns: repeat(4, 1fr); background: rgba(255,250,251,.88); backdrop-filter: blur(18px); border-radius: 24px; box-shadow: var(--shadow), 0 0 0 1px rgba(212,176,106,.45); }
.dock a, .dock button { border: 0; background: transparent; color: var(--primary); font-size: .7rem; font-weight: 600; text-align: center; padding: 8px 4px 6px; border-radius: 16px; display: grid; justify-items: center; gap: 3px; cursor: pointer; }
.dock .ic { width: 22px; height: 22px; }
.dock .dock__rsvp { background: linear-gradient(135deg, var(--deep), var(--primary)); color: #fff !important; }
.dock .dock__rsvp .ic { fill: currentColor; stroke: none; }

.music-toggle { position: fixed; right: 16px; bottom: 16px; z-index: 860; width: 48px; height: 48px; border-radius: 50%; border: 0; background: #fff; color: var(--primary); box-shadow: var(--shadow-gold), var(--shadow-soft); cursor: pointer; display: grid; place-items: center; }
.music-toggle[aria-pressed="true"] { animation: breathe 1.4s ease-in-out infinite; }
@media (max-width: 760px) { .music-toggle { bottom: 92px; } }

/* Visionneuse */
.lightbox { width: min(96vw, 1100px); max-width: none; padding: 0; border: 0; border-radius: 22px; background: transparent; overflow: visible; }
.lightbox::backdrop { background: rgba(48, 12, 27, 0.86); backdrop-filter: blur(10px); }
.lightbox__figure { margin: 0; display: grid; justify-items: center; gap: 12px; }
.lightbox img { max-width: 100%; max-height: 82svh; object-fit: contain; border-radius: 16px; box-shadow: 0 0 0 4px rgba(255,255,255,.9), 0 0 0 5.5px var(--gold), 0 40px 90px rgba(0,0,0,.5); animation: pop .4s cubic-bezier(.2,.8,.2,1); }
.lightbox figcaption { color: #fff; font-size: 2rem; text-shadow: 0 4px 14px rgba(0,0,0,.4); min-height: 1.2em; }
.lightbox__close { position: fixed; top: 16px; right: 16px; }
.lightbox__nav { position: fixed; top: 50%; transform: translateY(-50%); }
.lightbox__nav--prev { left: 16px; }
.lightbox__nav--next { right: 16px; }
.lightbox__counter { position: fixed; bottom: 16px; left: 50%; transform: translateX(-50%); color: rgba(255,255,255,.75); font-size: .85rem; letter-spacing: .1em; }

/* Toast */
.toast { position: fixed; left: 50%; bottom: 24px; transform: translate(-50%, 20px); z-index: 1350; padding: 12px 18px; border-radius: 999px; background: var(--deep); color: #fff; font-size: .92rem; box-shadow: var(--shadow); opacity: 0; visibility: hidden; transition: .35s ease; max-width: 92vw; text-align: center; }
.toast.is-visible { opacity: 1; visibility: visible; transform: translate(-50%, 0); }
@media (max-width: 760px) { .toast { bottom: 96px; } }

/* Apparition au défilement */
.reveal { opacity: 0; transform: translateY(28px); transition: opacity .9s ease, transform .9s cubic-bezier(.2,.8,.2,1); transition-delay: var(--delay, 0ms); }
.reveal.is-visible { opacity: 1; transform: none; }
.reveal-item { opacity: 0; transform: translateY(22px) scale(.98); transition: opacity .8s ease, transform .8s cubic-bezier(.2,.8,.2,1); transition-delay: var(--delay, 0ms); }
.reveal-item.is-visible { opacity: 1; transform: none; }

/* ---------- Responsive ---------- */
@media (max-width: 1180px) {
  .hero__grid { grid-template-columns: minmax(0, .85fr) minmax(0, 1.3fr) minmax(0, .75fr); }
  .infos-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 1024px) {
  .header__inner { grid-template-columns: auto 1fr auto; }
  .header__actions { justify-self: end; }
  .main-nav { display: none; }
  .header__actions .chip--outline { display: none; }
  .menu-toggle { display: block; }
  .hero { padding-bottom: clamp(110px, 16vw, 170px); }
  .hero__grid { min-height: 0; grid-template-columns: 1fr; grid-template-areas: "text" "main" "side"; gap: 26px; padding-top: 8px; }
  .hero__text { grid-area: text; }
  .arch--main { grid-area: main; justify-self: center; width: min(78vw, 400px); }
  .arch--side { grid-area: side; justify-self: center; width: min(64vw, 300px); margin-top: 0; }
  .theme__grid, .closing__grid { grid-template-columns: 1fr; }
  .poster { width: min(100%, 360px); }
  .universe-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ucard:nth-child(2) { margin-top: 0; }
  .gallery-grid { columns: 2; }
  .deco--hearts { top: 6%; right: 6%; }
  .memories__btn--prev { left: 0; }
  .memories__btn--next { right: 0; }
}
@media (max-width: 760px) {
  :root { --container: min(100vw - 28px, 100%); --header-h: 64px; }
  body { padding-bottom: 84px; }
  .header__actions { gap: 6px; }
  .header__actions .chip--filled { padding: 8px 12px; font-size: .78rem; }
  .header__inner { grid-template-columns: auto 1fr auto; }
  .header__actions { justify-self: end; }
  .hero { padding-top: 18px; }
  .hero__grid { grid-template-areas: "text" "main"; }
  .arch--side { display: none; }
  .hero__text { padding: 6px 0 0; }
  .title { line-height: .84; }
  .hero__meta { gap: 8px; }
  .pill { padding: 9px 13px; font-size: .78rem; }
  .hero__actions .btn { width: 100%; }
  .hero__scroll { margin-top: 20px; }
  .arch--main { width: min(82vw, 360px); }
  .deco--tl { width: 42vw; top: -14px; left: -18px; }
  .deco--tr { width: 38vw; top: -12px; right: -18px; }
  .deco--bl, .deco--br { width: 42vw; }
  .deco--hearts { width: 64px; top: 4%; right: 8%; }
  .deco--side-r, .deco--silk-bl { width: 36vw; }
  .ribbon__item { font-size: 1.05rem; padding: 10px 16px; }
  .universe-grid { grid-template-columns: 1fr; gap: 20px; }
  .ucard { max-width: 420px; margin-inline: auto; width: 100%; }
  .polaroid { width: min(64vw, 260px); }
  .memories__btn { display: none; }
  .countdown__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .palette { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px 8px; }
  .infos-grid { grid-template-columns: 1fr; }
  .gallery-grid { columns: 2; column-gap: 12px; }
  .gitem { margin-bottom: 12px; padding: 4px; }
  .choice { grid-template-columns: 1fr; }
  .footer__inner { grid-template-columns: 1fr; justify-items: center; text-align: center; }
  .footer__brand { flex-direction: column; text-align: center; }
  .dock { display: grid; }
  .cursor-glow { display: none; }
  .lightbox__nav { top: auto; bottom: 60px; transform: none; }
  .lightbox figcaption { font-size: 1.6rem; }
}
@media (max-width: 400px) {
  .title__word { font-size: clamp(3.4rem, 19vw, 4.6rem); }
  .names { font-size: clamp(2.2rem, 13vw, 3rem); }
}

/* =====================================================================
   V4 — « Le chemin » : paysage continu, photos fondues, parallaxe
   ===================================================================== */
html, body { overflow-x: clip; }
body { background: linear-gradient(180deg, var(--bg) 0%, #fbeaf0 22%, #f6dbe5 48%, #fbeaf0 74%, #fff3f6 100%); }
main { position: relative; }

/* Sentier doré qui relie les étapes */
.trail { position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; overflow: visible; }
.trail__base { fill: none; stroke: rgba(212,176,106,.42); stroke-width: 2.2; stroke-dasharray: 2 13; stroke-linecap: round; }
.trail__lit { fill: none; stroke: var(--gold); stroke-width: 3; stroke-linecap: round; stroke-dasharray: 2 13; filter: drop-shadow(0 0 7px rgba(212,176,106,.85)); }
.trail__glow { fill: none; stroke: rgba(255,255,255,.55); stroke-width: 9; stroke-linecap: round; filter: blur(6px); }
.trail__node { fill: #fff; stroke: var(--gold); stroke-width: 2; filter: drop-shadow(0 4px 10px rgba(139,53,85,.25)); transition: fill .5s; }
.trail__node.is-lit { fill: var(--gold-light); }
.trail__heart { fill: var(--primary); transform-box: fill-box; transform-origin: center; animation: heart-pulse calc(2.4s * var(--speed)) ease-in-out infinite; }
.trail__walker { fill: none; stroke: #fff; stroke-width: 1.5; filter: drop-shadow(0 0 8px rgba(212,176,106,.9)); }
html[data-path="off"] .trail { display: none; }

/* Sections : plus de blocs, tout se chevauche et se fond */
.section { padding: clamp(64px, 9vw, 110px) 0; overflow: visible; isolation: auto; }
.section + .section { margin-top: clamp(-48px, -5vw, -24px); }
.section-bg { display: none; }
.scene { position: absolute; left: 0; right: 0; top: -12%; bottom: -14%; z-index: 0; pointer-events: none; overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 16%, #000 84%, transparent); mask-image: linear-gradient(180deg, transparent, #000 16%, #000 84%, transparent); }
.scene__layer { position: absolute; left: 50%; width: max(100%, 1100px); height: auto; top: var(--top, auto); opacity: var(--op, 1); transform: translate3d(-50%, var(--py, 0px), 0); will-change: transform; }
.scene__layer--bottom { bottom: 0; }
.scene__sun { position: absolute; right: 8%; top: 4%; width: clamp(180px, 26vw, 380px); transform: translate3d(0, var(--py, 0px), 0); animation: sun-breathe calc(9s * var(--speed)) ease-in-out infinite alternate; }
@keyframes sun-breathe { from { opacity: .75; scale: 1; } to { opacity: 1; scale: 1.08; } }
html[data-landscape="off"] .scene { display: none; }
html[data-anim="off"] .scene__sun, html[data-anim="off"] .trail__heart { animation: none !important; }

/* Accueil : fondu vers le paysage */
.hero { background: transparent; padding-bottom: clamp(90px, 12vw, 160px); }
.hero__bg, .hero__veil { -webkit-mask-image: linear-gradient(180deg, #000 55%, transparent 100%); mask-image: linear-gradient(180deg, #000 55%, transparent 100%); }
.silk--hero img { -webkit-mask-image: linear-gradient(180deg, #000 30%, transparent 100%); mask-image: linear-gradient(180deg, #000 30%, transparent 100%); opacity: .9; }
.hero .deco--bl, .hero .deco--br { -webkit-mask-image: linear-gradient(180deg, #000 45%, transparent 100%); mask-image: linear-gradient(180deg, #000 45%, transparent 100%); }
.pill--link { text-decoration: none; color: inherit; transition: transform .25s ease, box-shadow .25s ease; }
.pill--link:hover { transform: translateY(-2px); box-shadow: var(--shadow-soft); }
.pill--link i { font-style: normal; color: var(--gold); font-size: .8rem; margin-left: -2px; }

/* Ruban : léger, incliné comme une soie posée */
.ribbon { transform: rotate(-1.1deg) scale(1.03); margin: -22px 0 -6px; border-radius: 6px; box-shadow: 0 18px 40px rgba(90,31,54,.18); background: linear-gradient(90deg, rgba(90,31,54,.94), rgba(139,53,85,.94) 40%, rgba(162,77,112,.94) 60%, rgba(90,31,54,.94)); }

/* Photos fondues */
.feather { -webkit-mask-image: radial-gradient(ellipse 66% 64% at 50% 50%, #000 50%, rgba(0,0,0,.55) 66%, transparent 84%); mask-image: radial-gradient(ellipse 66% 64% at 50% 50%, #000 50%, rgba(0,0,0,.55) 66%, transparent 84%); }
.feather--arch { border-radius: 48% 48% 26px 26px / 34% 34% 26px 26px; -webkit-mask-image: linear-gradient(180deg, #000 68%, transparent 100%); mask-image: linear-gradient(180deg, #000 68%, transparent 100%); }
.feather--soft { border-radius: 30px; -webkit-mask-image: radial-gradient(ellipse 82% 82% at 50% 50%, #000 60%, rgba(0,0,0,.7) 78%, transparent 100%); mask-image: radial-gradient(ellipse 82% 82% at 50% 50%, #000 60%, rgba(0,0,0,.7) 78%, transparent 100%); }

/* Notre univers : étapes le long du chemin */
.stops { display: grid; gap: clamp(36px, 7vw, 120px); margin-top: clamp(10px, 3vw, 30px); }
.stop { display: grid; grid-template-columns: 1.05fr .95fr; align-items: center; gap: clamp(20px, 4vw, 64px); }
.stop--flip .stop__media { order: 2; }
.stop--flip .stop__text { text-align: right; }
.stop--flip .stop__num { margin-left: auto; }
.stop__media { position: relative; cursor: zoom-in; border: 0; padding: 0; background: none; display: block; width: 100%; }
.stop__media img { width: 100%; aspect-ratio: 4 / 4.3; object-fit: cover; object-position: var(--pos, center); display: block; transition: transform 1s ease; }
.stop__media:hover img { transform: scale(1.03); }
.stop__num { display: block; width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center; font-family: var(--font-display); font-weight: 600; color: var(--primary); background: #fff; box-shadow: 0 0 0 2px var(--gold), 0 10px 24px rgba(139,53,85,.18); margin-bottom: 14px; }
.stop__text h3 { margin: 0 0 10px; font-family: var(--font-script); font-weight: 400; font-size: clamp(2.2rem, 3.6vw, 3.2rem); color: var(--primary); line-height: 1.1; text-shadow: 0 0 18px rgba(255,246,248,.9); }
.stop__text p { margin: 0; font-family: var(--font-display); font-size: clamp(1.1rem, 1.5vw, 1.3rem); color: var(--text); max-width: 46ch; text-shadow: 0 0 14px rgba(255,246,248,.95); }
.stop--flip .stop__text p { margin-left: auto; }

/* Nos souvenirs : mur parallaxe (photos + vidéos) */
.wall { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); grid-auto-rows: clamp(64px, 8vw, 118px); grid-auto-flow: dense; gap: clamp(10px, 1.6vw, 22px); margin-top: 10px; }
.wall__item { position: relative; overflow: hidden; border-radius: 26px; cursor: zoom-in; border: 0; padding: 0; background: var(--bg-2); text-align: left; transform: translate3d(0, var(--py, 0px), 0); will-change: transform;
  -webkit-mask-image: radial-gradient(ellipse 84% 84% at 50% 50%, #000 58%, rgba(0,0,0,.7) 78%, transparent 100%); mask-image: radial-gradient(ellipse 84% 84% at 50% 50%, #000 58%, rgba(0,0,0,.7) 78%, transparent 100%); }
.wall__item--s { grid-column: span 2; grid-row: span 2; }
.wall__item--m { grid-column: span 2; grid-row: span 3; }
.wall__item--l { grid-column: span 3; grid-row: span 4; }
.wall__item img, .wall__item video { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 1s ease; }
.wall__item:hover img, .wall__item:hover video { transform: scale(1.06); }
.wall__cap { position: absolute; left: 0; right: 0; bottom: 0; padding: 30px 18px 16px; font-family: var(--font-script); font-size: clamp(1.3rem, 1.8vw, 1.7rem); color: #fff; text-shadow: 0 2px 14px rgba(60,14,32,.7); background: linear-gradient(transparent, rgba(60,14,32,.45)); pointer-events: none; }
.wall__play { position: absolute; top: 12px; right: 14px; width: 34px; height: 34px; border-radius: 50%; background: rgba(255,255,255,.85); color: var(--primary); display: grid; place-items: center; pointer-events: none; box-shadow: 0 6px 16px rgba(60,14,32,.3); }
.wall__play .ic { width: 16px; height: 16px; fill: currentColor; stroke: none; }

/* Le grand jour : crépuscule fondu dans le paysage */
.countdown { background: none; color: #fff; }
.dusk { position: relative; text-align: center; padding: clamp(40px, 6vw, 80px) clamp(14px, 4vw, 60px); }
.dusk::before { content: ""; position: absolute; inset: -30% -16%; z-index: -1; pointer-events: none; background: radial-gradient(ellipse closest-side at 50% 48%, rgba(74,23,41,.96) 0%, rgba(90,31,54,.9) 40%, rgba(139,53,85,.55) 72%, rgba(139,53,85,0) 100%); }
.countdown .section-title { margin-bottom: clamp(26px, 4vw, 40px); }
.countdown__grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(10px, 2vw, 22px); max-width: 840px; margin: 0 auto; }
.tile { position: relative; padding: clamp(16px, 3vw, 28px) 8px; border-radius: 22px; background: rgba(255,255,255,.08); border: 1px solid rgba(239,217,164,.55); backdrop-filter: blur(6px); box-shadow: 0 20px 50px rgba(0,0,0,.18), inset 0 1px 0 rgba(255,255,255,.25); }
.tile b { display: block; font-family: var(--font-display); font-weight: 600; font-size: clamp(2.3rem, 6vw, 4.4rem); line-height: 1; color: #fff; text-shadow: 0 6px 20px rgba(0,0,0,.25); font-variant-numeric: tabular-nums; }
.tile b.is-flip { animation: flip .5s cubic-bezier(.2,.8,.2,1); }
.tile span { display: block; margin-top: 8px; font-size: .76rem; letter-spacing: .18em; text-transform: uppercase; color: var(--gold-light); }
.countdown__actions { margin-top: 28px; }
.countdown.is-done .countdown__grid { display: none; }

/* Thème */
.theme .deco--rose-b { right: 2%; bottom: 14%; opacity: .8; }

/* Infos : cartes de verre légères */
.info { background: rgba(255,255,255,.5); border: 1px solid rgba(255,255,255,.75); backdrop-filter: blur(8px); box-shadow: 0 10px 30px rgba(139,53,85,.06); }

/* Galerie : mosaïque adaptative en parallaxe */
.mosaic { position: relative; min-height: 200px; }
.mosaic__item { position: absolute; display: block; padding: 0; border: 0; background: var(--bg-2); cursor: zoom-in; overflow: hidden; border-radius: 22px; transform: translate3d(0, var(--py, 0px), 0); will-change: transform;
  -webkit-mask-image: radial-gradient(ellipse 86% 86% at 50% 50%, #000 62%, rgba(0,0,0,.72) 82%, transparent 100%); mask-image: radial-gradient(ellipse 86% 86% at 50% 50%, #000 62%, rgba(0,0,0,.72) 82%, transparent 100%); }
.mosaic__item img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 1s ease; }
.mosaic__item:hover img { transform: scale(1.05); }
.mosaic.is-ready .mosaic__item { transition: left .5s ease, top .5s ease, width .5s ease, height .5s ease; }

/* Clôture : fondue en haut et en bas */
.closing { margin-top: clamp(-40px, -4vw, -20px); -webkit-mask-image: linear-gradient(180deg, transparent, #000 110px, #000 calc(100% - 90px), transparent); mask-image: linear-gradient(180deg, transparent, #000 110px, #000 calc(100% - 90px), transparent); padding-top: clamp(120px, 14vw, 180px); padding-bottom: clamp(120px, 14vw, 170px); }
.closing__actions { display: flex; flex-wrap: wrap; gap: 10px; }

/* After mariage */
.after { padding-top: 10px; padding-bottom: clamp(60px, 8vw, 100px); }
.after__card { position: relative; text-align: center; max-width: 640px; margin: 0 auto; padding: clamp(30px, 4vw, 46px) clamp(20px, 4vw, 40px); border-radius: 32px; background: rgba(255,255,255,.55); border: 1px solid rgba(212,176,106,.5); backdrop-filter: blur(10px); box-shadow: var(--shadow-soft); }
.after__hearts { display: block; width: 84px; margin: -78px auto 10px; animation: deco-float calc(7s * var(--speed)) ease-in-out infinite alternate; }
.badge { display: inline-block; padding: 5px 14px; border-radius: 999px; background: linear-gradient(135deg, var(--gold), #e8cd8f); color: #fff; font-size: .7rem; font-weight: 700; letter-spacing: .2em; text-transform: uppercase; box-shadow: 0 6px 16px rgba(212,176,106,.4); }
.after__card h2 { margin: 12px 0 8px; font-family: var(--font-script); font-weight: 400; font-size: clamp(2.4rem, 4vw, 3.4rem); color: var(--primary); }
.after__card p { margin: 0 auto 18px; max-width: 48ch; font-family: var(--font-display); font-size: 1.15rem; color: var(--text); }

/* Feuille « Ajouter au calendrier » */
.sheet { border: 0; padding: 0; background: transparent; width: 100vw; max-width: 100vw; height: 100vh; max-height: 100vh; margin: 0; }
.sheet[open] { display: flex; align-items: flex-end; justify-content: center; }
.sheet::backdrop { background: rgba(60,14,32,.45); backdrop-filter: blur(4px); }
.sheet__panel { width: min(100%, 470px); background: #fff; color: var(--text); border-radius: 28px 28px 0 0; padding: 12px 22px calc(22px + env(safe-area-inset-bottom)); box-shadow: 0 -20px 60px rgba(60,14,32,.35); animation: sheet-up .4s cubic-bezier(.2,.8,.2,1); }
.sheet__grip { width: 44px; height: 5px; border-radius: 999px; background: #ecd9df; margin: 0 auto 14px; }
.sheet__panel h3 { margin: 0; font-family: var(--font-display); font-size: 1.6rem; color: var(--deep); text-align: center; }
.sheet__sub { margin: 4px 0 14px; text-align: center; color: var(--text-soft); font-size: .92rem; }
.sheet__list { display: grid; gap: 8px; margin-bottom: 12px; }
.sheet__list a, .sheet__list button { display: flex; align-items: center; gap: 12px; padding: 11px 14px; border-radius: 14px; border: 1px solid var(--line); background: #fff; color: var(--text); font: inherit; font-weight: 600; text-decoration: none; cursor: pointer; transition: background .2s, transform .2s; }
.sheet__list a:hover, .sheet__list button:hover { background: #fdf2f5; transform: translateX(3px); }
.sheet__list .ico { width: 36px; height: 36px; border-radius: 10px; display: grid; place-items: center; color: #fff; font-weight: 700; font-size: .78rem; flex: none; }
.sheet__list small { margin-left: auto; color: var(--text-soft); font-weight: 500; }
@keyframes sheet-up { from { transform: translateY(40px); opacity: 0; } to { transform: none; opacity: 1; } }
@media (min-width: 761px) { .sheet[open] { align-items: center; } .sheet__panel { border-radius: 28px; animation-name: pop; } }
@keyframes pop { from { transform: scale(.96); opacity: 0; } to { transform: none; opacity: 1; } }

/* Visionneuse : vidéo */
.lightbox__figure video { max-width: min(92vw, 1100px); max-height: 76vh; border-radius: 12px; background: #000; box-shadow: 0 30px 80px rgba(0,0,0,.5); }

/* Responsive V4 */
@media (max-width: 1024px) {
  .wall { grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-rows: clamp(70px, 10vw, 110px); }
  .wall__item--l { grid-column: span 4; grid-row: span 3; }
}
@media (max-width: 760px) {
  .section { padding: clamp(48px, 8vw, 70px) 0; }
  .section + .section { margin-top: -16px; }
  .scene { top: -6%; bottom: -8%; }
  .scene__layer { width: 180%; }
  .stops { gap: 44px; }
  .stop { grid-template-columns: 1fr; gap: 16px; }
  .stop--flip .stop__media { order: 0; }
  .stop__text, .stop--flip .stop__text { text-align: center; }
  .stop__num, .stop--flip .stop__num { margin-inline: auto; }
  .stop__text p, .stop--flip .stop__text p { margin-inline: auto; }
  .stop__media { max-width: 86%; margin: 0 auto; }
  .stop__media img { aspect-ratio: 4 / 4.6; }
  .wall { grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-rows: 64px; gap: 10px; }
  .wall__item { border-radius: 18px; }
  .wall__item--s { grid-column: span 2; grid-row: span 2; }
  .wall__item--m { grid-column: span 2; grid-row: span 3; }
  .wall__item--l { grid-column: span 4; grid-row: span 3; }
  .wall__cap { font-size: 1.15rem; padding: 22px 12px 10px; }
  .dusk { padding: 34px 6px; }
  .dusk::before { inset: -10% -14%; }
  .countdown__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
  .tile { padding: 14px 4px; border-radius: 16px; }
  .tile b { font-size: 1.7rem; }
  .tile span { font-size: .58rem; letter-spacing: .1em; }
  .mosaic__item { border-radius: 16px; }
  .closing { padding-top: 110px; }
  .after__hearts { margin-top: -50px; width: 70px; }
  .ribbon { transform: rotate(-1.6deg) scale(1.04); margin: -14px 0 -4px; }
}
/* parallaxe compatible avec l'apparition (reveal) */
.stop__media.is-visible, .wall__item.is-visible { transform: translate3d(0, var(--py, 0px), 0); }

/* =====================================================================
   V5 — décor partout, escalier, fondus organiques, textes animés
   ===================================================================== */
.scene { display: none !important; }
.deco--far { opacity: .55; filter: saturate(.9); }
.deco--side-l { left: -10px; top: 18%; width: clamp(110px, 14vw, 190px); }
.deco--big { width: clamp(220px, 34vw, 520px); }

/* Accueil : légendes lisibles, départ du chemin */
.arch__caption, .arch__quote { display: inline-block; margin-top: 12px; padding: 6px 16px; border-radius: 999px; background: rgba(255,250,251,.72); backdrop-filter: blur(6px); box-shadow: 0 6px 18px rgba(139,53,85,.12), 0 0 0 1px rgba(212,176,106,.35); text-shadow: none; }
.hero__scroll { position: relative; z-index: 3; }
.hero__scroll i { display: none; }
.hero__scroll-dot { display: block !important; width: 12px; height: 12px; border-radius: 50%; background: var(--gold); box-shadow: 0 0 0 6px rgba(212,176,106,.25), 0 0 18px rgba(212,176,106,.9); animation: dot-pulse calc(1.8s * var(--speed)) ease-in-out infinite; }
@keyframes dot-pulse { 0%,100% { transform: scale(1); box-shadow: 0 0 0 6px rgba(212,176,106,.25), 0 0 18px rgba(212,176,106,.9); } 50% { transform: scale(1.25); box-shadow: 0 0 0 12px rgba(212,176,106,.12), 0 0 26px rgba(212,176,106,1); } }

/* Chemin : flux lumineux animé, marcheur qui pulse */
.trail__flow { fill: none; stroke: rgba(255,255,255,.9); stroke-width: 3; stroke-linecap: round; stroke-dasharray: 14 220; animation: trail-flow calc(3.2s * var(--speed)) linear infinite; filter: drop-shadow(0 0 6px rgba(255,255,255,.9)); }
@keyframes trail-flow { to { stroke-dashoffset: -234; } }
.trail__walker { animation: walker-pulse calc(1.6s * var(--speed)) ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
@keyframes walker-pulse { 0%,100% { r: 6; } 50% { r: 9; } }
.trail__halo { fill: rgba(212,176,106,.22); animation: halo-pulse calc(2.2s * var(--speed)) ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
@keyframes halo-pulse { 0%,100% { transform: scale(1); opacity: .7; } 50% { transform: scale(1.7); opacity: .15; } }
html[data-anim="off"] .trail__flow, html[data-anim="off"] .trail__walker, html[data-anim="off"] .trail__halo, html[data-anim="off"] .hero__scroll-dot { animation: none !important; }

/* Fondus organiques (masques alpha) */
.omask { -webkit-mask-size: 100% 100%; mask-size: 100% 100%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; }
.omask--1 { -webkit-mask-image: url("../assets/deco/mask-blob-1.png"); mask-image: url("../assets/deco/mask-blob-1.png"); }
.omask--2 { -webkit-mask-image: url("../assets/deco/mask-blob-2.png"); mask-image: url("../assets/deco/mask-blob-2.png"); }
.omask--3 { -webkit-mask-image: url("../assets/deco/mask-blob-3.png"); mask-image: url("../assets/deco/mask-blob-3.png"); }
.omask--4 { -webkit-mask-image: url("../assets/deco/mask-blob-4.png"); mask-image: url("../assets/deco/mask-blob-4.png"); }
.omask--arch { -webkit-mask-image: url("../assets/deco/mask-arch.png"); mask-image: url("../assets/deco/mask-arch.png"); }
.omask--wide { -webkit-mask-image: url("../assets/deco/mask-wide.png"); mask-image: url("../assets/deco/mask-wide.png"); }

/* Escalier : photo d'un côté, décor de l'autre */
.stops, .stair { display: grid; gap: clamp(30px, 6vw, 90px); margin-top: clamp(10px, 3vw, 30px); }
.stop, .step { display: grid; grid-template-columns: 1.05fr .95fr; align-items: center; gap: clamp(16px, 3vw, 48px); position: relative; }
.stop--flip .stop__media, .step--flip .step__media { order: 2; }
.stop__media, .step__media { position: relative; cursor: zoom-in; border: 0; padding: 0; background: none; display: block; width: 100%; }
.stop__media img { width: 100%; aspect-ratio: 4 / 4.4; object-fit: cover; object-position: var(--pos, center); display: block; transition: transform 1s ease; }
.step__media img, .step__media video { width: 100%; aspect-ratio: 4 / 3.6; object-fit: cover; display: block; transition: transform 1s ease; }
.step__media video { pointer-events: none; }
.stop__media:hover img, .step__media:hover img, .step__media:hover video { transform: scale(1.03); }
/* décor qui déborde sur la photo (côté intérieur) */
.stop__media .over, .step__media .over { position: absolute; pointer-events: none; width: clamp(110px, 16vw, 230px); filter: drop-shadow(0 12px 22px rgba(90,31,54,.25)); animation: deco-float calc(8s * var(--speed)) ease-in-out infinite alternate; }
.over--tl { left: -8%; top: -8%; }
.over--br { right: -8%; bottom: -6%; animation-delay: -3s; }
.over--tr { right: -8%; top: -6%; animation-delay: -5s; }
.over--bl { left: -8%; bottom: -8%; animation-delay: -2s; }
.over--sm { width: clamp(70px, 9vw, 130px); }
/* colonne décor + texte */
.stop__side, .step__side { position: relative; min-height: 260px; display: grid; align-content: center; }
.stop__text { position: relative; z-index: 2; }
.stop--flip .stop__text { text-align: right; }
.stop--flip .stop__num { margin-left: auto; }
.stop--flip .stop__text p { margin-left: auto; }
.cluster { position: absolute; inset: -12% -6%; pointer-events: none; z-index: 1; }
.cluster img { position: absolute; will-change: transform; transform: translate3d(0, var(--py, 0px), 0); }
.cluster .c1 { right: 0; top: 0; width: 62%; opacity: .9; animation: deco-sway calc(12s * var(--speed)) ease-in-out infinite alternate; }
.cluster .c2 { left: 4%; bottom: 0; width: 46%; opacity: .95; animation: deco-float calc(9s * var(--speed)) ease-in-out infinite alternate-reverse; }
.cluster .c3 { right: 18%; bottom: 8%; width: 20%; animation: deco-float calc(7s * var(--speed)) ease-in-out infinite alternate; }
.cluster .c4 { left: 10%; top: 6%; width: 32%; opacity: .55; filter: blur(1px); animation: deco-sway calc(14s * var(--speed)) ease-in-out infinite alternate-reverse; }
.stop--flip .cluster .c1, .step--flip .cluster .c1 { right: auto; left: 0; }
.stop--flip .cluster .c2, .step--flip .cluster .c2 { left: auto; right: 4%; }
.stop--flip .cluster .c3, .step--flip .cluster .c3 { right: auto; left: 18%; }
.stop--flip .cluster .c4, .step--flip .cluster .c4 { left: auto; right: 10%; }
.stop__text h3, .step__cap { position: relative; z-index: 2; }
.step__side { justify-items: center; text-align: center; }
.step__cap { margin: 0; font-family: var(--font-script); font-size: clamp(2rem, 3.4vw, 3rem); color: var(--primary); text-shadow: 0 0 18px rgba(255,246,248,.95), 0 0 30px rgba(255,246,248,.9); }
.step__cap small { display: block; font-family: var(--font-display); font-size: 1.05rem; color: var(--text-soft); margin-top: 4px; }
.step__play { position: absolute; top: 14px; right: 16px; width: 40px; height: 40px; border-radius: 50%; background: rgba(255,255,255,.85); color: var(--primary); display: grid; place-items: center; pointer-events: none; box-shadow: 0 6px 16px rgba(60,14,32,.3); }
.step__play .ic { width: 18px; height: 18px; fill: currentColor; stroke: none; }
.wall, .wall__item { display: none; }

/* Le grand jour : bandeau vieux rose profond, bords fondus, décor qui déborde */
.countdown { color: #fff; padding: clamp(110px, 14vw, 190px) 0; }
.countdown__band { position: absolute; inset: 0; z-index: 0; overflow: hidden; background: linear-gradient(135deg, #4a1729, var(--primary) 55%, #a24d70);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 90px, #000 calc(100% - 90px), transparent); mask-image: linear-gradient(180deg, transparent, #000 90px, #000 calc(100% - 90px), transparent); }
.countdown__bg { position: absolute; inset: -6%; background-size: cover; background-position: center 30%; opacity: var(--bg-opacity, .3); filter: blur(var(--bg-blur, 10px)); mix-blend-mode: luminosity; animation: bg-zoom calc(34s * var(--speed)) ease-in-out infinite alternate; }
.countdown__veil { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(74,23,41,.55), rgba(139,53,85,.35) 50%, rgba(74,23,41,.6)); }
.countdown .sparkles { z-index: 1; }
.countdown .deco--tl { top: 3%; left: -20px; width: clamp(150px, 24vw, 380px); opacity: .95; }
.countdown .deco--br { bottom: 2%; right: -20px; width: clamp(150px, 24vw, 380px); opacity: .95; }
.countdown .deco--hearts { top: 10%; right: 18%; width: clamp(60px, 7vw, 100px); }
.countdown__inner { position: relative; text-align: center; }
.dusk::before { display: none; }
.countdown__grid { max-width: 860px; }
.tile { background: rgba(255,255,255,.1); }

/* Infos */
.info { background: rgba(255,255,255,.62); }

/* Galerie : mosaïque centrée, propre */
.gallery-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-rows: clamp(120px, 14vw, 210px); grid-auto-flow: dense; gap: clamp(12px, 1.6vw, 20px); max-width: 1100px; margin: 0 auto; }
.gitem { position: relative; display: block; padding: 0; border: 0; background: var(--bg-2); cursor: zoom-in; overflow: hidden; border-radius: 22px; margin: 0; box-shadow: 0 16px 36px rgba(90,31,54,.16); transition: transform .5s ease, box-shadow .5s ease; }
.gitem::after { content: ""; position: absolute; inset: 0; border-radius: inherit; box-shadow: inset 0 0 0 1px rgba(212,176,106,.55), inset 0 0 40px rgba(255,246,248,.35); pointer-events: none; }
.gitem:hover { transform: translateY(-6px); box-shadow: 0 26px 50px rgba(90,31,54,.24); }
.gitem--wide { grid-column: span 2; }
.gitem--tall { grid-row: span 2; }
.gitem--big { grid-column: span 2; grid-row: span 2; }
.gitem__img { width: 100%; height: 100%; }
.gitem img { width: 100%; height: 100%; object-fit: cover; object-position: center 30%; display: block; transition: transform .9s ease; }
.gitem:hover img { transform: scale(1.06); }
.mosaic, .mosaic__item { display: none; }

/* ---------- Animations de texte pilotées par le défilement ---------- */
[data-fx] { --p: 0; }
[data-fx="fade"] { opacity: var(--p); transform: translateY(calc((1 - var(--p)) * 22px)); }
/* SECURITE : les lettres ne sont masquees QUE si le script a effectivement pris la
   main (classe fx-live posee par prepTextFx). Sans cela un titre pouvait rester
   definitivement invisible ou coupe en plein mot des que le script n'avait pas la
   main au bon moment (saut par une ancre du menu, Safari, chargement lent). Par
   defaut le texte est donc LISIBLE, jamais transparent. */
html.fx-live [data-fx="write"] .ch { opacity: 0; transition: opacity .12s linear; }
html.fx-live [data-fx="write"] .ch.on { opacity: 1; }
[data-fx="write"] .ch { opacity: 1; }
[data-fx="write"] .caret { display: inline-block; width: 2px; height: .9em; margin-left: 2px; vertical-align: -.1em; background: var(--gold); animation: caret 1s steps(2) infinite; }
[data-fx="write"].is-done .caret { opacity: 0; }
@keyframes caret { 50% { opacity: 0; } }
[data-fx="spread"] { opacity: var(--p); letter-spacing: calc((1 - var(--p)) * .28em); filter: blur(calc((1 - var(--p)) * 6px)); }
[data-fx="flip"] .w { display: inline-block; transform-origin: 50% 100%; transform: rotateX(calc((1 - var(--p)) * -90deg)) translateY(calc((1 - var(--p)) * 10px)); opacity: var(--p); transition: transform .1s linear, opacity .1s linear; }
[data-fx="curtain"] { -webkit-mask-image: linear-gradient(90deg, #000 calc(var(--p) * 100%), transparent calc(var(--p) * 100% + 12%)); mask-image: linear-gradient(90deg, #000 calc(var(--p) * 100%), transparent calc(var(--p) * 100% + 12%)); }
[data-fx="slide-l"] { opacity: var(--p); transform: translateX(calc((1 - var(--p)) * -50px)); }
[data-fx="slide-r"] { opacity: var(--p); transform: translateX(calc((1 - var(--p)) * 50px)); }
[data-fx="scale"] { opacity: var(--p); transform: scale(calc(.9 + var(--p) * .1)); }
html[data-textfx="off"] [data-fx] { --p: 1 !important; }
html[data-textfx="off"] [data-fx="write"] .ch { opacity: 1; }
html[data-textfx="off"] [data-fx="write"] .caret { display: none; }
.info[data-fx], .stop__text[data-fx], .step__cap[data-fx], .tile[data-fx], .swatch[data-fx] { transition: none; }

/* Responsive V5 */
@media (max-width: 1024px) {
  .gallery-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 760px) {
  .stops, .stair { gap: 40px; }
  .stop, .step { grid-template-columns: 1fr; gap: 10px; }
  .stop--flip .stop__media, .step--flip .step__media { order: 0; }
  .stop__media, .step__media { max-width: 88%; margin: 0 auto; }
  .stop__side, .step__side { min-height: 0; padding: 10px 6px 0; }
  .stop__text, .stop--flip .stop__text { text-align: center; }
  .stop__num, .stop--flip .stop__num { margin-inline: auto; }
  .stop__text p, .stop--flip .stop__text p { margin-inline: auto; }
  .cluster { inset: -30% -10% -10%; }
  .cluster .c1 { width: 52%; top: auto; bottom: 0; }
  .cluster .c2 { width: 38%; top: 0; bottom: auto; }
  .cluster .c4 { display: none; }
  .over--tl, .over--tr, .over--bl, .over--br { width: 30%; }
  .countdown { padding: 90px 0; }
  .countdown .deco--tl, .countdown .deco--br { width: 42vw; }
  .countdown__band { -webkit-mask-image: linear-gradient(180deg, transparent, #000 60px, #000 calc(100% - 60px), transparent); mask-image: linear-gradient(180deg, transparent, #000 60px, #000 calc(100% - 60px), transparent); }
  .gallery-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: 120px; gap: 10px; }
  .gitem { border-radius: 16px; }
  .arch__caption { font-size: 1.15rem; padding: 5px 12px; }
}
/* lisibilité des textes posés sur le décor */
.stop__text, .step__cap { position: relative; z-index: 2; }
.stop__text::before, .step__cap::before { content: ""; position: absolute; inset: -28px -44px; z-index: -1; border-radius: 50%; background: radial-gradient(ellipse at 50% 50%, rgba(255,246,248,.95) 0%, rgba(255,246,248,.72) 45%, rgba(255,246,248,0) 78%); filter: blur(4px); pointer-events: none; }
.step__cap { padding: 10px 18px; }
.stop__media .over { width: clamp(90px, 13vw, 190px); }
.over--tl { left: -12%; top: -10%; } .over--tr { right: -12%; top: -8%; } .over--br { right: -10%; bottom: -8%; } .over--bl { left: -10%; bottom: -10%; }
@media (max-width: 760px) { .stop__text::before, .step__cap::before { inset: -14px -20px; } .stop__media .over, .step__media .over { width: 24%; } .over--sm { width: 15% !important; } }

/* =====================================================================
   V6 — une seule image : environnements fondus, vagues, médaillons
   ===================================================================== */
.cluster, .stop__side, .step__side, .stops, .stair, .wall, .mosaic, .gallery-grid, .dusk { display: none; }
.section { padding: clamp(90px, 11vw, 150px) 0; }
.section + .section { margin-top: clamp(-150px, -11vw, -70px); }
.env { position: absolute; left: 0; right: 0; top: -6%; bottom: -6%; z-index: 0; pointer-events: none; background-size: cover; background-position: center;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 24%, #000 76%, transparent 100%); mask-image: linear-gradient(180deg, transparent 0, #000 24%, #000 76%, transparent 100%); }
.env::after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(255,246,248,.35), rgba(255,246,248,.08) 30%, rgba(255,246,248,.08) 70%, rgba(255,246,248,.35)); }
.hero__veil { opacity: .55; }
.hero__bg { -webkit-mask-image: linear-gradient(180deg, #000 70%, transparent 100%); mask-image: linear-gradient(180deg, #000 70%, transparent 100%); }
.hero .deco--petals { left: 34%; top: 2%; width: clamp(160px, 26vw, 420px); opacity: .55; }
.hero .deco--bl { bottom: 4%; left: -30px; width: clamp(200px, 26vw, 420px); }
.hero .deco--br { bottom: 2%; right: -40px; width: clamp(200px, 26vw, 420px); }

/* décors de sections */
.deco--garland-l { left: -1%; top: 6%; width: clamp(80px, 9vw, 160px); }
.deco--garland-r { right: -1%; top: 32%; width: clamp(80px, 9vw, 160px); }
.deco--low { top: auto; bottom: 8%; }
.deco--seam { left: -4%; width: 108%; top: -6vw; opacity: .95; z-index: 2; }
.deco--seam-top { top: -5vw; }
.deco--hearts-r { right: 7%; top: 7%; width: clamp(56px, 6.5vw, 100px); }
.garland-title { display: block; width: min(64%, 520px); margin: -14px auto 24px; position: relative; z-index: 2; }
.deco--rings { left: 3%; bottom: 40%; width: clamp(120px, 16vw, 260px); }
.deco--lantern { right: 3%; top: 8%; width: clamp(120px, 15vw, 240px); }
.deco--silk-top { top: -4vw; left: -3%; width: 106%; opacity: .95; z-index: 2; }
.deco--bouquet { right: -3%; bottom: 2%; width: clamp(160px, 22vw, 340px); }
.deco--petals-l { left: -2%; top: 8%; width: clamp(150px, 20vw, 300px); opacity: .7; }
.deco--lantern-l { left: 2%; bottom: 6%; width: clamp(110px, 14vw, 220px); }
.deco--envelope { right: 3%; top: 10%; width: clamp(110px, 14vw, 220px); transform: rotate(-8deg); }
.calligraphy { display: block; width: min(56%, 420px); margin: -8px auto 26px; position: relative; z-index: 2; }
.deco--rose-l { left: 2%; top: 12%; width: clamp(110px, 14vw, 220px); }
.deco--arch { left: 50%; top: 2%; width: clamp(320px, 52vw, 780px); transform: translateX(-50%); opacity: .5; }
.deco--envelope-form { position: absolute; right: 6%; top: -30px; width: clamp(90px, 10vw, 150px); z-index: 3; transform: rotate(10deg); animation: deco-float calc(7s * var(--speed)) ease-in-out infinite alternate; }

/* la vague */
.wave { display: grid; gap: clamp(36px, 6vw, 100px); margin-top: clamp(10px, 3vw, 30px); }
.wave__row { display: grid; grid-template-columns: 1.05fr .95fr; align-items: center; gap: clamp(24px, 4vw, 70px); position: relative; }
.wave__row--flip .wave__media { order: 2; }
.wave__media { position: relative; border: 0; padding: 0; background: none; display: block; width: 100%; cursor: zoom-in; text-align: left; }
.wave__media > img.omask { width: 100%; aspect-ratio: 4 / 4.3; object-fit: cover; object-position: var(--pos, center); display: block; transition: transform 1s ease; }
.wave__media:hover > img.omask { transform: scale(1.03); }
.medallion { position: relative; width: min(88%, 460px); aspect-ratio: 1; margin: 0 auto; overflow: hidden; border-radius: 50%;
  -webkit-mask-image: radial-gradient(circle at 50% 50%, #000 56%, rgba(0,0,0,.55) 74%, transparent 100%); mask-image: radial-gradient(circle at 50% 50%, #000 56%, rgba(0,0,0,.55) 74%, transparent 100%); }
.medallion video, .medallion img { width: 100%; height: 100%; object-fit: cover; display: block; opacity: .94; }
.medallion__ring { position: absolute; inset: 6%; border-radius: 50%; box-shadow: 0 0 0 1.5px rgba(212,176,106,.55), 0 0 40px rgba(212,176,106,.35) inset; pointer-events: none; }
.wave__over { position: absolute; pointer-events: none; z-index: 2; filter: drop-shadow(0 10px 20px rgba(90,31,54,.25)); animation: deco-float calc(8s * var(--speed)) ease-in-out infinite alternate; }
.wave__over--tl { left: -6%; top: -4%; width: 34%; }
.wave__over--br { right: -6%; bottom: -3%; width: 30%; animation-delay: -3s; }
.wave__over--tr { right: -5%; top: -4%; width: 34%; animation-delay: -5s; }
.wave__over--bl { left: -6%; bottom: -3%; width: 30%; animation-delay: -2s; }
.wave__side { position: relative; padding: 20px 8px; }
.wave__row--flip .wave__side { text-align: right; }
.wave__bg { position: absolute; pointer-events: none; z-index: 0; opacity: .8; }
.wave__bg--a { right: -6%; bottom: -14%; width: 48%; animation: deco-sway calc(12s * var(--speed)) ease-in-out infinite alternate; }
.wave__bg--b { left: -6%; top: -18%; width: 40%; animation: deco-float calc(9s * var(--speed)) ease-in-out infinite alternate-reverse; }
.wave__row--flip .wave__bg--a { right: auto; left: -6%; }
.wave__row--flip .wave__bg--b { left: auto; right: -6%; }
.wave__text { position: relative; z-index: 2; }
.wave__text::before { content: ""; position: absolute; inset: -26px -40px; z-index: -1; border-radius: 50%; background: radial-gradient(ellipse at 50% 50%, rgba(255,246,248,.9) 0%, rgba(255,246,248,.6) 45%, rgba(255,246,248,0) 78%); filter: blur(5px); }
.wave__text h3 { margin: 0 0 10px; font-family: var(--font-script); font-weight: 400; font-size: clamp(2.2rem, 3.8vw, 3.4rem); color: var(--primary); line-height: 1.1; }
.wave__text p { margin: 0; font-family: var(--font-display); font-size: clamp(1.1rem, 1.5vw, 1.32rem); color: var(--text); max-width: 44ch; }
.wave__row--flip .wave__text p { margin-left: auto; }
.wave--dense { gap: clamp(28px, 5vw, 70px); }
.wave--dense .wave__row { grid-template-columns: 1fr 1fr; }
.wave--dense .wave__media > img.omask { aspect-ratio: 4 / 3.8; }
.wave--dense .medallion { width: min(80%, 380px); }
.wave__cap { margin: 0; font-family: var(--font-script); font-size: clamp(2rem, 3.4vw, 3rem); color: var(--primary); }

/* Le grand jour */
.countdown { color: #fff; padding: clamp(120px, 14vw, 200px) 0 clamp(200px, 22vw, 320px); }
.countdown__band { display: none; }
.env--band { top: -4%; bottom: 30%; -webkit-mask-image: linear-gradient(180deg, transparent, #000 14%, #000 72%, transparent 100%); mask-image: linear-gradient(180deg, transparent, #000 14%, #000 72%, transparent 100%); }
.env--band::after { background: linear-gradient(180deg, rgba(74,23,41,.35), rgba(74,23,41,.25) 50%, rgba(74,23,41,.4)); }
.env--after { top: 52%; bottom: -10%; -webkit-mask-image: linear-gradient(180deg, transparent, #000 40%, #000 75%, transparent 100%); mask-image: linear-gradient(180deg, transparent, #000 40%, #000 75%, transparent 100%); }
.env--after::after { background: none; }
.countdown .deco--tl, .countdown .deco--br, .countdown .deco--hearts { display: none; }
.countdown__inner { position: relative; text-align: center; }
.countdown__grid { max-width: 860px; }

/* Infos : ligne dorée, pas de cartes */
.infoline { position: relative; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px; padding-top: 30px; }
.infoline::before { content: ""; position: absolute; left: 8%; right: 8%; top: 58px; height: 2px; background: linear-gradient(90deg, transparent, var(--gold) 20%, var(--gold) 80%, transparent); opacity: .8; }
.infoline .info { background: none; border: 0; box-shadow: none; backdrop-filter: none; text-align: center; padding: 0 10px; }
.infoline .info__icon { margin: 0 auto 16px; width: 58px; height: 58px; border-radius: 50%; background: #fff; display: grid; place-items: center; box-shadow: 0 0 0 3px var(--gold-light), 0 12px 26px rgba(139,53,85,.2); }
.infoline .info h3, .infoline .info p, .infoline .info a { text-shadow: 0 0 12px rgba(255,246,248,.95), 0 0 24px rgba(255,246,248,.9); }
.infos-grid { display: none; }

/* Galerie : rivière de photos fondues */
.river { display: grid; gap: clamp(24px, 4vw, 60px); margin-top: 10px; }
.river__row { display: grid; grid-template-columns: 1.25fr .75fr; align-items: center; gap: clamp(14px, 3vw, 40px); }
.river__row--flip .river__big { order: 2; }
.river__big, .river__small button { position: relative; border: 0; padding: 0; background: none; cursor: zoom-in; display: block; width: 100%; }
.river__big img { width: 100%; aspect-ratio: 4 / 3.1; object-fit: cover; object-position: center 35%; display: block; transition: transform 1s ease; }
.river__small { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.river__small img { width: 100%; aspect-ratio: 1 / 1.15; object-fit: cover; object-position: center 25%; display: block; transition: transform 1s ease; }
.river__row--flip .river__small { grid-template-columns: 1fr 1fr; }
.river button:hover img { transform: scale(1.04); }
.river__over { position: absolute; pointer-events: none; z-index: 2; width: 32%; filter: drop-shadow(0 10px 18px rgba(90,31,54,.25)); animation: deco-float calc(8s * var(--speed)) ease-in-out infinite alternate; }

/* Clôture */
.closing { background: none; }
.closing .env { top: 0; bottom: 0; -webkit-mask-image: linear-gradient(180deg, transparent, #000 18%, #000 84%, transparent); mask-image: linear-gradient(180deg, transparent, #000 18%, #000 84%, transparent); }
.closing .env::after { background: linear-gradient(90deg, rgba(74,23,41,.6), rgba(74,23,41,.3) 55%, rgba(74,23,41,.15)); }
.closing__media { -webkit-mask-image: radial-gradient(ellipse 48% 70% at 22% 50%, #000 40%, rgba(0,0,0,.6) 65%, transparent 100%); mask-image: radial-gradient(ellipse 48% 70% at 22% 50%, #000 40%, rgba(0,0,0,.6) 65%, transparent 100%); opacity: .9; }
.closing__veil { background: linear-gradient(90deg, rgba(74,23,41,.55), rgba(74,23,41,.25) 50%, rgba(74,23,41,.1)); }
.closing__grid { position: relative; }
.closing__text { position: relative; }
.medallion--closing { position: absolute; right: -6%; top: -60px; width: clamp(130px, 15vw, 220px); opacity: .9; z-index: 1; }
.closing__text > * { position: relative; z-index: 2; }

/* After */
.after { padding-top: clamp(80px, 10vw, 140px); color: #fff; }
.after .env { top: -6%; bottom: 0; -webkit-mask-image: linear-gradient(180deg, transparent, #000 30%, #000 100%); mask-image: linear-gradient(180deg, transparent, #000 30%, #000 100%); }
.after .env::after { background: linear-gradient(180deg, rgba(74,23,41,.2), rgba(40,10,24,.55)); }
.after__card { background: rgba(255,246,248,.08); border: 1px solid rgba(212,176,106,.45); backdrop-filter: blur(6px); color: #fff; }
.after__card h2 { color: #fff; }
.after__card p { color: rgba(255,246,248,.9); }
.after__badge { display: block; font-size: 1.6rem; color: var(--gold-light); margin-top: 4px; }
.after__card .btn--ghost { border-color: rgba(255,255,255,.5); color: #fff; background: rgba(255,255,255,.08); }
.site-footer { background: linear-gradient(180deg, rgba(40,10,24,.98), #2a0a18); color: #fff; }
.site-footer a, .site-footer .footer__nav a { color: rgba(255,246,248,.85); }

/* Responsive V6 */
@media (max-width: 1024px) {
  .infoline { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .infoline::before { display: none; }
}
@media (max-width: 760px) {
  .section { padding: clamp(60px, 9vw, 90px) 0; }
  .section + .section { margin-top: -60px; }
  .env { top: -3%; bottom: -3%; }
  .wave, .wave--dense { gap: 36px; }
  .wave__row, .wave--dense .wave__row { grid-template-columns: 1fr; gap: 6px; }
  .wave__row--flip .wave__media { order: 0; }
  .wave__media { max-width: 86%; margin: 0 auto; }
  .medallion, .wave--dense .medallion { width: min(78%, 320px); }
  .wave__side, .wave__row--flip .wave__side { text-align: center; padding: 10px 6px 0; }
  .wave__text p, .wave__row--flip .wave__text p { margin-inline: auto; }
  .wave__bg--a { width: 40%; bottom: auto; top: -30%; }
  .wave__bg--b { display: none; }
  .wave__over--tl, .wave__over--tr, .wave__over--bl, .wave__over--br { width: 26%; }
  .deco--garland-l, .deco--garland-r, .deco--lantern, .deco--lantern-l, .deco--envelope, .deco--rose-l { width: 22vw; }
  .deco--rings { width: 30vw; bottom: 46%; }
  .deco--bouquet { width: 44vw; }
  .countdown { padding: 100px 0 200px; }
  .env--band { bottom: 26%; }
  .env--after { top: 56%; }
  .river__row, .river__row--flip .river__row { grid-template-columns: 1fr; }
  .river__row--flip .river__big { order: 0; }
  .river__small, .river__row--flip .river__small { grid-template-columns: 1fr 1fr; }
  .river__big { max-width: 92%; margin: 0 auto; }
  .medallion--closing { position: static; width: 46%; margin: 0 auto 10px; }
  .deco--envelope-form { display: none; }
  .deco--arch { width: 110vw; }
  .calligraphy { width: 70%; }
}

/* V6 : lisibilité et corrections */
.river__row, .river__small { position: relative; }
.river__over { width: 26%; opacity: .9; }
.section-title h2, .section-title p, .section-title--left h2, .section-title--left p, .theme__note, .swatch span, .wave__cap { text-shadow: 0 0 12px rgba(255,246,248,.95), 0 0 26px rgba(255,246,248,.9), 0 0 40px rgba(255,246,248,.7); }
.section-title--light h2, .section-title--light p { text-shadow: 0 6px 24px rgba(40,10,24,.6), 0 0 30px rgba(40,10,24,.4); }
.infos .env::after { background: linear-gradient(180deg, rgba(255,246,248,.55), rgba(255,246,248,.4) 40%, rgba(255,246,248,.45) 70%, rgba(255,246,248,.6)); }
.theme .env::after { background: linear-gradient(90deg, rgba(255,246,248,.55), rgba(255,246,248,.25) 55%, rgba(255,246,248,.1)); }
.gallery .env::after { background: linear-gradient(180deg, rgba(255,246,248,.35), rgba(255,246,248,.2) 40%, rgba(255,246,248,.35)); }
.universe .env::after { background: linear-gradient(180deg, rgba(255,246,248,.4), rgba(255,246,248,.12) 30%, rgba(255,246,248,.12) 70%, rgba(255,246,248,.4)); }
.wave__bg { opacity: .75; }
.wave__bg--a { width: 40%; }
.wave__bg--b { width: 26%; }
.hero .eyebrow { color: var(--primary); }
.infoline { padding: 34px 20px 24px; border-radius: 40px; background: radial-gradient(ellipse at 50% 55%, rgba(255,246,248,.9) 0%, rgba(255,246,248,.72) 50%, rgba(255,246,248,0) 95%); }
.infoline::before { top: 62px; }
.theme .env::after { background: linear-gradient(90deg, rgba(255,246,248,.72), rgba(255,246,248,.45) 50%, rgba(255,246,248,.15)); }
.palette { position: relative; z-index: 2; }
.river__over { width: 20%; }
.river__small { overflow: visible; }
@media (max-width: 760px) { .infoline { padding: 24px 8px 16px; gap: 18px 10px; } .infoline .info { padding: 0 2px; } .infoline .info p { font-size: .88rem; } .infoline .info h3 { font-size: 1.05rem; } }

/* ---------- Mobile : compacité, performance, pas de débordement ---------- */
main, .hero, .section, .closing { overflow-x: clip; }
@media (max-width: 760px) {
  .section { padding: 44px 0; }
  .section + .section { margin-top: -34px; }
  .section-title { margin-bottom: 14px; }
  .section-title h2 { font-size: 2.3rem; }
  .wave, .wave--dense { gap: 22px; margin-top: 4px; }
  .wave__row, .wave--dense .wave__row { gap: 2px; }
  .wave__media { max-width: 74%; }
  .medallion, .wave--dense .medallion { width: min(60%, 250px); }
  .wave__side, .wave__row--flip .wave__side { padding: 2px 6px 0; }
  .wave__text h3 { font-size: 1.9rem; margin-bottom: 4px; }
  .wave__text p { font-size: 1rem; }
  .wave__cap { font-size: 1.8rem; }
  .wave__bg--a { width: 34%; top: -22%; }
  .section-note { margin-top: 12px; font-size: 1.35rem; }
  .garland-title { width: 60%; margin: -8px auto 12px; }
  .countdown { padding: 70px 0 160px; }
  .env--band { bottom: 22%; }
  .theme__grid { gap: 14px; }
  .theme__poster { max-width: 72%; margin: 0 auto; }
  .calligraphy { width: 60%; margin: -4px auto 14px; }
  .river { gap: 16px; }
  .river__big { max-width: 100%; }
  .river__small { gap: 8px; }
  .river__over { width: 22%; }
  .closing { padding-top: 90px; padding-bottom: 90px; }
  .closing__grid { gap: 22px; }
  .after { padding-top: 60px; }
  .after__card { padding: 22px 16px 26px; }
  .deco--bouquet { width: 38vw; bottom: 0; }
  .deco--petals-l { display: none; }
  .deco--arch { width: 120vw; opacity: .35; }
  .medallion video, .medallion img { opacity: 1; }
  .env::after { background: linear-gradient(180deg, rgba(255,246,248,.3), rgba(255,246,248,.15) 30%, rgba(255,246,248,.15) 70%, rgba(255,246,248,.3)); }
  .after .env::after { background: linear-gradient(180deg, rgba(74,23,41,.2), rgba(40,10,24,.6)); }
  .closing .env::after { background: linear-gradient(180deg, rgba(74,23,41,.55), rgba(74,23,41,.35)); }
  .theme .env::after { background: linear-gradient(180deg, rgba(255,246,248,.6), rgba(255,246,248,.35)); }
  .infos .env::after { background: rgba(255,246,248,.5); }
}

/* =====================================================================
   V7 — fluidité + vidéos fondues + photos partout, galerie retirée
   ===================================================================== */
/* --- performance : plus de flous, d'ombres portées ni de backdrop sur les éléments animés --- */
.aurora, .cursor-glow { display: none !important; }
.deco { filter: none !important; will-change: auto; }
.trail__glow, .trail__flow { display: none; }
.trail__lit, .trail__walker, .trail__halo, .trail__node { filter: none !important; }
.trail__lit { stroke-width: 3.5; }
.site-header { backdrop-filter: none; -webkit-backdrop-filter: none; background: rgba(255,246,248,.92); }
.tile, .info, .after__card, .arch__caption, .arch__quote, .btn--ghost-light, .mobile-menu { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; }
.wave__text::before { filter: none; }
.petals i { filter: none !important; box-shadow: none !important; }
.hero__bg { filter: none !important; }
.env::after { will-change: auto; }
.wave__media, .wave__bg, .river__big, .wall__item, .mosaic__item, .stop__media, .scene__layer, .cluster img { will-change: auto; }
.section-title h2, .section-title p, .section-title--left h2, .section-title--left p, .theme__note, .swatch span, .wave__cap { text-shadow: 0 0 14px rgba(255,246,248,.95), 0 0 28px rgba(255,246,248,.85); }
.stop__text::before, .step__cap::before { filter: none; }
.medallion__ring, .wave__over, .wave__bg, .river, .gallery { display: none !important; }

/* --- accueil --- */
.arch__caption:empty { display: none; }
.hero__scroll::before, .hero__scroll::after { display: none; }
.arch__quote { display: inline-block; margin-top: 12px; padding: 6px 16px; border-radius: 999px; background: rgba(255,250,251,.72); box-shadow: 0 0 0 1px rgba(212,176,106,.35); text-shadow: none; }

/* --- vague : photo principale + petite photo + texte --- */
.wave { gap: clamp(30px, 5vw, 80px); }
.wave__row { grid-template-columns: 1.1fr .9fr; gap: clamp(24px, 4vw, 64px); }
.wave__media { position: relative; cursor: default; padding: 4% 0 6%; }
.wm { display: block; border: 0; padding: 0; background: none; cursor: zoom-in; }
.wm--main { width: 100%; position: relative; z-index: 1; }
.wm--main img { width: 100%; aspect-ratio: 4 / 4.2; object-fit: cover; object-position: var(--pos, center 22%); display: block; }
.wm--main.wm--wide img { aspect-ratio: 4 / 3.3; }
.wm--second { position: absolute; width: 44%; right: -8%; bottom: -6%; z-index: 2; }
.wave__row--flip .wm--second { right: auto; left: -8%; }
.wm--second img { width: 100%; aspect-ratio: 1 / 1.1; object-fit: cover; object-position: var(--pos, center 20%); display: block; }
.wm--video video { width: 100%; aspect-ratio: 4 / 3.2; object-fit: cover; object-position: var(--pos, center); display: block; opacity: .92; }
.wm--main:hover img, .wm--second:hover img { transform: none; }
.wave__side { padding: 10px 6px; }
.wave__text::before { inset: -22px -34px; background: radial-gradient(ellipse at 50% 50%, rgba(255,246,248,.92) 0%, rgba(255,246,248,.65) 45%, rgba(255,246,248,0) 78%); }
.wave__text h3 { font-size: clamp(2.2rem, 3.8vw, 3.4rem); }
.wave__text p { font-size: clamp(1.08rem, 1.45vw, 1.28rem); max-width: 42ch; }

/* --- thème : photo fondue --- */
.theme__photo { position: absolute; left: 40%; top: -6%; width: clamp(200px, 26vw, 380px); z-index: 0; opacity: .9; pointer-events: none; }
.theme__photo img { width: 100%; aspect-ratio: 4 / 4.6; object-fit: cover; object-position: center 20%; display: block; }
.theme__grid { position: relative; }

/* --- infos : photos de part et d'autre --- */
.infos__wrap { display: grid; grid-template-columns: 1fr minmax(0, 3.2fr) 1fr; gap: 20px; align-items: center; }
.infos__photo img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; object-position: center 25%; display: block; }
.infos__photo { cursor: zoom-in; }

/* --- clôture : vidéo fondue au lieu du cercle --- */
.medallion { border-radius: 0; width: min(100%, 520px); aspect-ratio: 4 / 3.2; -webkit-mask-image: url("../assets/deco/mask-wide.png"); mask-image: url("../assets/deco/mask-wide.png"); -webkit-mask-size: 100% 100%; mask-size: 100% 100%; }
.medallion--closing { position: absolute; right: -8%; top: -80px; width: clamp(200px, 22vw, 320px); opacity: .85; }
.closing__media { -webkit-mask-image: url("../assets/deco/mask-blob-2.png"); mask-image: url("../assets/deco/mask-blob-2.png"); -webkit-mask-size: 70% 110%; mask-size: 70% 110%; -webkit-mask-position: -10% 50%; mask-position: -10% 50%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; opacity: .95; }

/* --- sections plus courtes --- */
.section { padding: clamp(70px, 9vw, 120px) 0; }
.section + .section { margin-top: clamp(-120px, -9vw, -60px); }
.countdown { padding: clamp(100px, 12vw, 170px) 0 clamp(170px, 18vw, 260px); }

@media (max-width: 1024px) {
  .infos__wrap { grid-template-columns: 1fr; }
  .infos__photo { display: none; }
}
@media (max-width: 760px) {
  .wave__row { gap: 0; }
  .wave__media { max-width: 82%; padding: 2% 0 10%; }
  .wm--second { width: 46%; right: -12%; bottom: -8%; }
  .wave__row--flip .wm--second { left: -12%; }
  .wm--main img { aspect-ratio: 4 / 4; }
  .theme__photo { display: none; }
  .medallion--closing { position: static; width: 84%; margin: 0 auto 6px; }
  .section { padding: 40px 0; }
  .section + .section { margin-top: -30px; }
  .countdown { padding: 70px 0 150px; }
}
.medallion--closing { right: auto; left: -8%; top: -130px; width: clamp(220px, 24vw, 340px); opacity: .7; }
.deco--envelope-form { right: -26px; top: -46px; width: clamp(80px, 8vw, 120px); }
@media (max-width: 760px) { .medallion--closing { position: static; width: 84%; margin: 0 auto 6px; opacity: .9; } }
@media (max-width: 760px) {
  .wave__row, .wave--dense .wave__row { grid-template-columns: 1fr; }
  .wave__row--flip .wave__media { order: 0; }
  .wave__side, .wave__row--flip .wave__side { text-align: center; }
  .wave__text p, .wave__row--flip .wave__text p { margin-inline: auto; }
}

/* =====================================================================
   V7.1 — masques en dégradés CSS (fonctionnent aussi en ouvrant index.html
   directement depuis l'ordinateur, sans serveur)
   ===================================================================== */
.omask, .closing__media, .medallion { -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-size: 100% 100%; mask-size: 100% 100%; -webkit-mask-composite: source-over; mask-composite: add; }
.omask--1 { -webkit-mask-image: radial-gradient(ellipse 50% 44% at 47% 40%, #000 52%, transparent 100%), radial-gradient(ellipse 44% 38% at 60% 64%, #000 50%, transparent 100%), radial-gradient(ellipse 36% 32% at 36% 68%, #000 48%, transparent 100%);
  mask-image: radial-gradient(ellipse 50% 44% at 47% 40%, #000 52%, transparent 100%), radial-gradient(ellipse 44% 38% at 60% 64%, #000 50%, transparent 100%), radial-gradient(ellipse 36% 32% at 36% 68%, #000 48%, transparent 100%); }
.omask--2 { -webkit-mask-image: radial-gradient(ellipse 48% 42% at 52% 38%, #000 52%, transparent 100%), radial-gradient(ellipse 46% 36% at 42% 66%, #000 50%, transparent 100%), radial-gradient(ellipse 34% 30% at 66% 70%, #000 48%, transparent 100%);
  mask-image: radial-gradient(ellipse 48% 42% at 52% 38%, #000 52%, transparent 100%), radial-gradient(ellipse 46% 36% at 42% 66%, #000 50%, transparent 100%), radial-gradient(ellipse 34% 30% at 66% 70%, #000 48%, transparent 100%); }
.omask--3 { -webkit-mask-image: radial-gradient(ellipse 54% 40% at 50% 44%, #000 54%, transparent 100%), radial-gradient(ellipse 40% 40% at 38% 62%, #000 50%, transparent 100%), radial-gradient(ellipse 40% 36% at 64% 60%, #000 50%, transparent 100%);
  mask-image: radial-gradient(ellipse 54% 40% at 50% 44%, #000 54%, transparent 100%), radial-gradient(ellipse 40% 40% at 38% 62%, #000 50%, transparent 100%), radial-gradient(ellipse 40% 36% at 64% 60%, #000 50%, transparent 100%); }
.omask--4 { -webkit-mask-image: radial-gradient(ellipse 46% 46% at 44% 42%, #000 52%, transparent 100%), radial-gradient(ellipse 44% 40% at 62% 56%, #000 52%, transparent 100%), radial-gradient(ellipse 34% 32% at 50% 74%, #000 46%, transparent 100%);
  mask-image: radial-gradient(ellipse 46% 46% at 44% 42%, #000 52%, transparent 100%), radial-gradient(ellipse 44% 40% at 62% 56%, #000 52%, transparent 100%), radial-gradient(ellipse 34% 32% at 50% 74%, #000 46%, transparent 100%); }
.omask--arch { border-radius: 0; -webkit-mask-image: radial-gradient(ellipse 48% 34% at 50% 30%, #000 60%, transparent 100%), linear-gradient(180deg, transparent 0, #000 22%, #000 62%, transparent 100%), radial-gradient(ellipse 44% 40% at 50% 56%, #000 55%, transparent 100%);
  mask-image: radial-gradient(ellipse 48% 34% at 50% 30%, #000 60%, transparent 100%), linear-gradient(180deg, transparent 0, #000 22%, #000 62%, transparent 100%), radial-gradient(ellipse 44% 40% at 50% 56%, #000 55%, transparent 100%); -webkit-mask-composite: source-in; mask-composite: intersect; }
.omask--wide { -webkit-mask-image: radial-gradient(ellipse 54% 50% at 42% 50%, #000 52%, transparent 100%), radial-gradient(ellipse 50% 46% at 62% 48%, #000 52%, transparent 100%), radial-gradient(ellipse 40% 36% at 52% 66%, #000 48%, transparent 100%);
  mask-image: radial-gradient(ellipse 54% 50% at 42% 50%, #000 52%, transparent 100%), radial-gradient(ellipse 50% 46% at 62% 48%, #000 52%, transparent 100%), radial-gradient(ellipse 40% 36% at 52% 66%, #000 48%, transparent 100%); }
.medallion { -webkit-mask-image: radial-gradient(ellipse 52% 50% at 44% 50%, #000 50%, transparent 100%), radial-gradient(ellipse 48% 44% at 62% 46%, #000 50%, transparent 100%); mask-image: radial-gradient(ellipse 52% 50% at 44% 50%, #000 50%, transparent 100%), radial-gradient(ellipse 48% 44% at 62% 46%, #000 50%, transparent 100%); }
.closing__media { -webkit-mask-image: radial-gradient(ellipse 40% 60% at 18% 48%, #000 45%, transparent 100%), radial-gradient(ellipse 30% 44% at 36% 62%, #000 45%, transparent 100%); mask-image: radial-gradient(ellipse 40% 60% at 18% 48%, #000 45%, transparent 100%), radial-gradient(ellipse 30% 44% at 36% 62%, #000 45%, transparent 100%); -webkit-mask-size: 100% 100%; mask-size: 100% 100%; -webkit-mask-position: 0 0; mask-position: 0 0; }

/* =====================================================================
   V8 — plus court, fondus sur les 4 côtés, halos de texte doux, chemin visible
   ===================================================================== */
/* --- masques : chaque ellipse s'éteint avant le bord de l'image --- */
.omask--1 { -webkit-mask-image: radial-gradient(ellipse 40% 36% at 48% 40%, #000 45%, transparent 100%), radial-gradient(ellipse 36% 32% at 58% 62%, #000 45%, transparent 100%), radial-gradient(ellipse 32% 28% at 40% 66%, #000 40%, transparent 100%);
  mask-image: radial-gradient(ellipse 40% 36% at 48% 40%, #000 45%, transparent 100%), radial-gradient(ellipse 36% 32% at 58% 62%, #000 45%, transparent 100%), radial-gradient(ellipse 32% 28% at 40% 66%, #000 40%, transparent 100%); }
.omask--2 { -webkit-mask-image: radial-gradient(ellipse 40% 34% at 52% 38%, #000 45%, transparent 100%), radial-gradient(ellipse 38% 32% at 44% 62%, #000 45%, transparent 100%), radial-gradient(ellipse 30% 26% at 62% 66%, #000 40%, transparent 100%);
  mask-image: radial-gradient(ellipse 40% 34% at 52% 38%, #000 45%, transparent 100%), radial-gradient(ellipse 38% 32% at 44% 62%, #000 45%, transparent 100%), radial-gradient(ellipse 30% 26% at 62% 66%, #000 40%, transparent 100%); }
.omask--3 { -webkit-mask-image: radial-gradient(ellipse 42% 34% at 50% 42%, #000 46%, transparent 100%), radial-gradient(ellipse 34% 32% at 40% 60%, #000 42%, transparent 100%), radial-gradient(ellipse 34% 30% at 60% 60%, #000 42%, transparent 100%);
  mask-image: radial-gradient(ellipse 42% 34% at 50% 42%, #000 46%, transparent 100%), radial-gradient(ellipse 34% 32% at 40% 60%, #000 42%, transparent 100%), radial-gradient(ellipse 34% 30% at 60% 60%, #000 42%, transparent 100%); }
.omask--4 { -webkit-mask-image: radial-gradient(ellipse 38% 38% at 46% 42%, #000 45%, transparent 100%), radial-gradient(ellipse 36% 32% at 58% 54%, #000 45%, transparent 100%), radial-gradient(ellipse 30% 26% at 50% 70%, #000 40%, transparent 100%);
  mask-image: radial-gradient(ellipse 38% 38% at 46% 42%, #000 45%, transparent 100%), radial-gradient(ellipse 36% 32% at 58% 54%, #000 45%, transparent 100%), radial-gradient(ellipse 30% 26% at 50% 70%, #000 40%, transparent 100%); }
.omask--arch { -webkit-mask-image: radial-gradient(ellipse 40% 30% at 50% 34%, #000 50%, transparent 100%), radial-gradient(ellipse 40% 34% at 50% 58%, #000 48%, transparent 100%); mask-image: radial-gradient(ellipse 40% 30% at 50% 34%, #000 50%, transparent 100%), radial-gradient(ellipse 40% 34% at 50% 58%, #000 48%, transparent 100%); -webkit-mask-composite: source-over; mask-composite: add; }
.omask--wide { -webkit-mask-image: radial-gradient(ellipse 40% 40% at 42% 50%, #000 44%, transparent 100%), radial-gradient(ellipse 38% 38% at 60% 48%, #000 44%, transparent 100%), radial-gradient(ellipse 30% 28% at 52% 64%, #000 40%, transparent 100%);
  mask-image: radial-gradient(ellipse 40% 40% at 42% 50%, #000 44%, transparent 100%), radial-gradient(ellipse 38% 38% at 60% 48%, #000 44%, transparent 100%), radial-gradient(ellipse 30% 28% at 52% 64%, #000 40%, transparent 100%); }
.wm--main img, .wm--main.wm--wide img { aspect-ratio: 4 / 3.7; }
.wm--video video { aspect-ratio: 4 / 3.4; }
.wm--second img { aspect-ratio: 1 / 1; }

/* --- halo de texte : large, doux, centré, sans forme visible --- */
.wave__text { padding: 8px 10px; }
.wave__text::before { inset: -34% -26%; border-radius: 50%; background: radial-gradient(ellipse at 50% 50%, rgba(255,246,248,.72) 0%, rgba(255,246,248,.5) 30%, rgba(255,246,248,.22) 52%, rgba(255,246,248,0) 72%); transition: opacity .5s; }
.wave__text.is-lit::before { background: radial-gradient(ellipse at 50% 50%, rgba(255,250,236,.85) 0%, rgba(255,246,248,.55) 30%, rgba(250,236,200,.22) 52%, rgba(255,246,248,0) 72%); }
.wave__text h3 { text-shadow: 0 0 16px rgba(255,246,248,1), 0 0 30px rgba(255,246,248,.9); }
.wave__text p { color: var(--deep); text-shadow: 0 0 10px rgba(255,246,248,1), 0 0 20px rgba(255,246,248,.9); }
.section-note { color: var(--deep); font-size: clamp(1.5rem, 2.2vw, 1.9rem); }
.section-title p { color: var(--deep); }

/* --- chemin au-dessus des environnements, sous le contenu --- */
.trail { z-index: 1; }
.trail__base { stroke: rgba(212,176,106,.55); }
.trail__node { stroke-width: 2.5; }

/* --- accueil : un seul départ, lisible --- */
.hero__scroll-dot { display: none !important; }
.hero__scroll { margin-top: 14px; }
.hero__scroll span { color: var(--primary); font-weight: 700; letter-spacing: .32em; font-size: .78rem; opacity: 1; text-shadow: 0 0 12px rgba(255,246,248,1); animation: hint-pulse calc(2.4s * var(--speed)) ease-in-out infinite; }
@keyframes hint-pulse { 0%,100% { opacity: .7; transform: translateY(0); } 50% { opacity: 1; transform: translateY(4px); } }

/* --- grand jour : lanterne devant le ruban, rubans plus discrets --- */
.countdown .deco--lantern { z-index: 3; }
.deco--silk-top, .deco--seam { opacity: .7; }

/* --- plus court --- */
.hero { padding-bottom: clamp(56px, 7vw, 100px); }
.section { padding: clamp(44px, 6.5vw, 84px) 0; }
.section + .section { margin-top: clamp(-90px, -7vw, -40px); }
.section-title { margin-bottom: clamp(18px, 3vw, 30px); }
.wave { gap: clamp(16px, 3.5vw, 48px); margin-top: 0; }
.wave__media { padding: 2% 0 4%; }
.countdown { padding: clamp(80px, 10vw, 130px) 0 clamp(120px, 14vw, 190px); }
.env--band { bottom: 26%; }
.env--after { top: 56%; }
.theme { padding-top: clamp(40px, 6vw, 70px); }
.infos { padding-bottom: clamp(50px, 7vw, 90px); }

/* --- clôture : photo bien visible, pas de vidéo, pas d'after --- */
.closing { padding-top: clamp(80px, 9vw, 120px); padding-bottom: clamp(70px, 8vw, 110px); -webkit-mask-image: linear-gradient(180deg, transparent, #000 90px, #000 100%); mask-image: linear-gradient(180deg, transparent, #000 90px, #000 100%); }
.closing__media { opacity: 1; -webkit-mask-image: radial-gradient(ellipse 34% 46% at 24% 46%, #000 48%, transparent 100%), radial-gradient(ellipse 26% 36% at 38% 60%, #000 40%, transparent 100%); mask-image: radial-gradient(ellipse 34% 46% at 24% 46%, #000 48%, transparent 100%), radial-gradient(ellipse 26% 36% at 38% 60%, #000 40%, transparent 100%); }
.closing .env::after { background: linear-gradient(90deg, rgba(74,23,41,.15), rgba(74,23,41,.35) 55%, rgba(74,23,41,.5)); }
.closing__veil { background: linear-gradient(90deg, rgba(74,23,41,.25), rgba(74,23,41,.35) 50%, rgba(74,23,41,.45)); }
.closing__text { padding-top: clamp(200px, 26vw, 360px); }
.closing__tag, .closing__text h2, .closing__desc { text-shadow: 0 2px 14px rgba(40,10,24,.7); }
.after { display: none !important; }
.site-footer { margin-top: -2px; }

@media (max-width: 760px) {
  .section { padding: 34px 0; }
  .section + .section { margin-top: -26px; }
  .wave, .wave--dense { gap: 14px; }
  .wave__media { max-width: 80%; padding: 0 0 8%; }
  .wm--main img, .wm--main.wm--wide img { aspect-ratio: 4 / 3.8; }
  .wave__text::before { inset: -24% -18%; }
  .countdown { padding: 60px 0 120px; }
  .closing__text { padding-top: 220px; }
  .closing__media { -webkit-mask-image: radial-gradient(ellipse 44% 30% at 50% 22%, #000 45%, transparent 100%); mask-image: radial-gradient(ellipse 44% 30% at 50% 22%, #000 45%, transparent 100%); }
}
.closing__media { left: -6%; right: 44%; top: 4%; bottom: 8%; background-size: cover; background-position: center 18% !important; -webkit-mask-image: radial-gradient(ellipse 40% 42% at 50% 42%, #000 46%, transparent 100%), radial-gradient(ellipse 30% 30% at 46% 66%, #000 40%, transparent 100%); mask-image: radial-gradient(ellipse 40% 42% at 50% 42%, #000 46%, transparent 100%), radial-gradient(ellipse 30% 30% at 46% 66%, #000 40%, transparent 100%); }
.closing__text { padding-top: clamp(260px, 30vw, 420px); }
@media (max-width: 760px) { .closing__media { left: 0; right: 0; top: 0; bottom: auto; height: 420px; background-position: center 15% !important; -webkit-mask-image: radial-gradient(ellipse 42% 40% at 50% 42%, #000 45%, transparent 100%); mask-image: radial-gradient(ellipse 42% 40% at 50% 42%, #000 42%, transparent 100%); } .closing__text { padding-top: 300px; } }
.closing { -webkit-mask-image: none; mask-image: none; }
.closing .env { top: -6%; -webkit-mask-image: linear-gradient(180deg, transparent, #000 22%, #000 100%); mask-image: linear-gradient(180deg, transparent, #000 22%, #000 100%); }

/* =====================================================================
   V9 — chemin lumineux sans ligne parasite, voiles allégés, cœurs, masque cœur
   ===================================================================== */
.omask--heart { -webkit-mask-image: url("data:image/svg+xml;utf8,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22%3E%3Cdefs%3E%3Cfilter id=%22b%22 x=%22-20%25%22 y=%22-20%25%22 width=%22140%25%22 height=%22140%25%22%3E%3CfeGaussianBlur stdDeviation=%223.2%22/%3E%3C/filter%3E%3C/defs%3E%3Cpath filter=%22url(%23b)%22 fill=%22%23000%22 d=%22M50 88 C20 66 8 52 8 34 C8 22 17 13 28 13 C37 13 45 19 50 27 C55 19 63 13 72 13 C83 13 92 22 92 34 C92 52 80 66 50 88 Z%22/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml;utf8,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22%3E%3Cdefs%3E%3Cfilter id=%22b%22 x=%22-20%25%22 y=%22-20%25%22 width=%22140%25%22 height=%22140%25%22%3E%3CfeGaussianBlur stdDeviation=%223.2%22/%3E%3C/filter%3E%3C/defs%3E%3Cpath filter=%22url(%23b)%22 fill=%22%23000%22 d=%22M50 88 C20 66 8 52 8 34 C8 22 17 13 28 13 C37 13 45 19 50 27 C55 19 63 13 72 13 C83 13 92 22 92 34 C92 52 80 66 50 88 Z%22/%3E%3C/svg%3E"); -webkit-mask-size: 100% 100%; mask-size: 100% 100%; }

/* chemin : rien avant le passage, fil d'or qui se dessine, cœur qui avance */
.trail__base, .trail__glow, .trail__flow { display: none !important; }
.trail__lit { stroke: url(#trailGrad); stroke-width: 4; stroke-linecap: round; stroke-dasharray: none; }
.trail__pearls { fill: none; stroke: rgba(212,176,106,.9); stroke-width: 6; stroke-linecap: round; stroke-dasharray: 0 22; }
.trail__nodeg .trail__node { display: none; }
.trail__nodeheart { fill: rgba(212,176,106,.35); transform-box: fill-box; transform-origin: center; transition: fill .6s, transform .6s; }
.trail__nodeheart.is-lit { fill: #e9c46a; transform: scale(1.35); }
.trail__walker, .trail__halo { display: none; }
.trail__comet { fill: url(#cometGrad); }
.trail__cometheart { fill: #f6dd9a; transform-box: fill-box; transform-origin: center; animation: heart-pulse calc(1.4s * var(--speed)) ease-in-out infinite; }
html[data-anim="off"] .trail__cometheart { animation: none; }
/* le texte brille à l'arrivée du chemin */
.wave__text.is-lit h3 { background: linear-gradient(100deg, var(--primary) 0 38%, #f1d38f 50%, var(--primary) 62% 100%); background-size: 260% 100%; -webkit-background-clip: text; background-clip: text; color: transparent; animation: text-shine 1.8s ease-out both; text-shadow: none; }
.wave__text.is-lit h3 .ch.on { text-shadow: 0 0 18px rgba(241,211,143,.9); }
@keyframes text-shine { 0% { background-position: 120% 0; } 100% { background-position: -80% 0; } }
.wave__text.is-lit::before { background: radial-gradient(ellipse at 50% 50%, rgba(255,250,236,.92) 0%, rgba(255,246,248,.6) 30%, rgba(246,221,154,.3) 52%, rgba(255,246,248,0) 72%); }

/* voiles beaucoup plus légers : vos environnements restent nets */
.env::after { background: linear-gradient(180deg, rgba(255,246,248,.16), rgba(255,246,248,.04) 30%, rgba(255,246,248,.04) 70%, rgba(255,246,248,.16)); }
.universe .env::after { background: linear-gradient(180deg, rgba(255,246,248,.2), rgba(255,246,248,.05) 30%, rgba(255,246,248,.05) 70%, rgba(255,246,248,.18)); }
.theme .env::after { background: linear-gradient(90deg, rgba(255,246,248,.45), rgba(255,246,248,.2) 50%, rgba(255,246,248,.05)); }
.infos .env::after { background: linear-gradient(180deg, rgba(255,246,248,.35), rgba(255,246,248,.25) 40%, rgba(255,246,248,.3) 70%, rgba(255,246,248,.4)); }
.hero__veil { opacity: .3; }
.hero__bg { opacity: 1 !important; }

/* accueil : lisibilité + décor plus présent + animation d'entrée et de sortie */
.hero__quote { display: inline-block; padding: 8px 18px; border-radius: 999px; background: rgba(255,250,251,.72); box-shadow: 0 0 0 1px rgba(212,176,106,.35); color: var(--deep); text-shadow: none; }
.hero__scroll { display: inline-flex; flex-direction: column; align-items: center; gap: 4px; padding: 10px 22px 8px; border-radius: 999px; background: rgba(255,250,251,.78); box-shadow: 0 0 0 1px rgba(212,176,106,.5), 0 10px 26px rgba(139,53,85,.15); text-decoration: none; }
.hero__scroll span { animation: none; opacity: 1; letter-spacing: .26em; font-size: .78rem; }
.hero__chev { width: 22px; height: 22px; fill: none; stroke: var(--gold); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; animation: chev-bounce calc(1.6s * var(--speed)) ease-in-out infinite; }
@keyframes chev-bounce { 0%,100% { transform: translateY(0); opacity: .7; } 50% { transform: translateY(5px); opacity: 1; } }
.hero .deco--tl, .hero .deco--tr { width: clamp(220px, 30vw, 520px); }
.hero__text > * { opacity: 0; transform: translateY(24px); animation: hero-in .9s cubic-bezier(.2,.8,.2,1) forwards; }
.hero__text > *:nth-child(1) { animation-delay: .15s; } .hero__text > *:nth-child(2) { animation-delay: .35s; } .hero__text > *:nth-child(3) { animation-delay: .6s; } .hero__text > *:nth-child(4) { animation-delay: .8s; } .hero__text > *:nth-child(5) { animation-delay: 1s; } .hero__text > *:nth-child(6) { animation-delay: 1.15s; } .hero__text > *:nth-child(7) { animation-delay: 1.3s; }
@keyframes hero-in { to { opacity: 1; transform: none; } }
html[data-anim="off"] .hero__text > * { animation: none; opacity: 1; transform: none; }
.hero__text { transform: translate3d(0, var(--hy, 0px), 0); opacity: var(--ho, 1); }
.arch { transform: translate3d(0, var(--ay, 0px), 0); }

/* cœurs qui montent, sur tout le site */
.hearts--global { position: fixed; inset: 0; z-index: 2; }
.hearts--global i { color: rgba(217,138,163,.55); }
html[data-petals="off"] .hearts--global { display: none; }

/* grand jour : sous-titre lisible */
.section-title--light p { color: #fff; opacity: .95; text-shadow: 0 2px 14px rgba(40,10,24,.8); }

@media (max-width: 760px) {
  .hero .deco--tl, .hero .deco--tr { width: 46vw; }
  .hero__scroll { padding: 8px 16px 6px; }
}

/* V9.1 — perles réelles, sillon de cœurs et pétales derrière la comète */
.trail__pearls { display: block !important; }
.trail__pearl { fill: rgba(212,176,106,0); transition: fill .35s ease; }
.trail__pearl.is-on { fill: rgba(233,196,106,.9); }
.trail__spark { transform-box: fill-box; transform-origin: center; animation: spark-drift 2.6s ease-out forwards; pointer-events: none; }
.trail__spark--heart { fill: #e9a0b6; }
.trail__spark--petal { fill: rgba(245,203,214,.9); }
@keyframes spark-drift { 0% { opacity: 0; transform: translate(0, 0) rotate(0) scale(.5); } 12% { opacity: 1; } 100% { opacity: 0; transform: translate(var(--dx), var(--dy)) rotate(var(--rot)) scale(1.1); } }

/* V9.2 — chemin dessiné dans un calque fixe de la taille de l'écran (fluide, pas de flash blanc) */
.trail { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 1; overflow: hidden; }

/* V9.3 — le chemin s'arrête sur le formulaire et l'illumine ; sillon plus dense */
.rsvp { transition: box-shadow .8s ease; }
.rsvp.is-lit { box-shadow: 0 0 0 2px rgba(233,196,106,.9), 0 0 70px rgba(233,196,106,.6), 0 30px 80px rgba(60,14,32,.35); animation: rsvp-hit 1.1s ease-out; }
@keyframes rsvp-hit { 0% { transform: scale(1); } 35% { transform: scale(1.025); } 100% { transform: scale(1); } }
.rsvp.is-lit .rsvp__head h3, .rsvp.is-lit form > h3, .rsvp.is-lit h3:first-of-type { background: linear-gradient(100deg, var(--primary) 0 38%, #f1d38f 50%, var(--primary) 62% 100%); background-size: 260% 100%; -webkit-background-clip: text; background-clip: text; color: transparent; animation: text-shine 1.8s ease-out both; }
#trailComet.is-done .trail__comet { animation: comet-glow 1.6s ease-in-out infinite alternate; }
@keyframes comet-glow { from { r: 22; opacity: .8; } to { r: 34; opacity: 1; } }
.trail__spark--heart { fill: #e48fa8; }
.trail__spark--petal { fill: rgba(246,196,210,.95); }
/* V9.4 — stabilité de la mise en page (pas de décalage au chargement des images) + impact sur le formulaire */
.garland-title, .calligraphy { aspect-ratio: 3 / 1; height: auto; }
.wm--main img, .wm--second img, .infos__photo img, .theme__photo img { background: transparent; }
.rsvp { position: relative; }
.rsvp.is-lit::after { content: ""; position: absolute; left: 50%; top: -6px; width: 30px; height: 30px; margin-left: -15px; border-radius: 50%; border: 3px solid rgba(233,196,106,.95); animation: hit-ripple 1.4s ease-out 2; pointer-events: none; }
@keyframes hit-ripple { 0% { transform: scale(.3); opacity: 1; } 100% { transform: scale(6); opacity: 0; } }

/* ==========================================================================
   V10 — LOT 1 : le decor ne doit plus recouvrir la carte RSVP
   Constat mesure : la comete du chemin debordait de 56px dans la carte et
   recouvrait le titre de 32px ; 20 petales flottaient par-dessus le formulaire.
   Cause : .closing porte isolation:isolate, donc aucun z-index pose a
   l'interieur ne peut battre #petals (z-60, enfant de body). On retire cette
   isolation (les .section du site l'ont deja fait ligne 555) pour que la carte
   participe au contexte racine, puis on la place juste au-dessus des petales.
   ========================================================================== */
.closing { isolation: auto; }
/* .closing__grid porte position:relative + z-index:2 : il cree donc son PROPRE
   contexte d'empilement, dans lequel un z-index:61 pose sur .rsvp restait
   prisonnier (verifie par un marqueur opaque insere dans #petals). C'est le
   conteneur qui doit remonter au-dessus de la couche de petales (z-60). */
.closing .closing__grid { z-index: 61; }
.rsvp { z-index: 2; }

/* Le titre "Confirmer ma presence" doit rester lisible quand le chemin arrive.
   L'effet d'origine rendait le texte transparent (background-clip:text) : on
   garde l'anneau dore de la carte, on rend le titre a sa couleur pleine. */
.rsvp.is-lit .rsvp__head h3, .rsvp.is-lit form > h3, .rsvp.is-lit h3:first-of-type {
  background: none; -webkit-background-clip: border-box; background-clip: border-box;
  color: var(--primary); animation: none;
}

/* L'onde d'arrivee part du bord haut de la carte, plus de son milieu. */
.rsvp.is-lit::after { top: -20px; }

/* Repli de copie manuelle du RSVP (aucun canal configure / presse-papiers indisponible) */
.rsvp__manual { display: grid; gap: 10px; margin-top: 4px; padding-top: 14px; border-top: 1px solid rgba(212,176,106,.45); }
.rsvp__manual-title { margin: 0; font-size: .9rem; font-weight: 600; color: var(--deep); text-align: center; }
.rsvp__manual-text { width: 100%; box-sizing: border-box; padding: 12px 14px; border-radius: 16px; border: 1px solid rgba(212,176,106,.55); background: #fff; color: var(--text); font: inherit; font-size: .9rem; line-height: 1.5; resize: vertical; }

/* ==========================================================================
   V10 — LOT 2 : lisibilite
   Constat mesure (8 auditeurs, contraste au pixel) : les 6 noms de couleur
   etaient entre 1,17:1 et 2,7:1 pour un seuil exige de 4,5:1.
   Trois causes cumulees :
   1. js/app.js:58 recalcule --text-soft en #917782, qui plafonne a 4,07:1
      MEME SUR DU BLANC PUR : ce gris ne peut donc jamais etre conforme.
      On ne touche PAS --text-soft (18 consommateurs dans la feuille, risque
      de regression sur tout le site) : on donne sa couleur au seul libelle.
   2. css/site.css:1302 annule le voile mobile de la ligne 1081 et tombe a
      5 % d'opacite a droite, exactement sous "Prune" et "Rose the".
   3. Une planche de couleurs posee sur une photo de champ de roses ne permet
      de juger aucune teinte : elle a besoin d'un fond neutre.
   ========================================================================== */

/* La palette recoit sa propre surface neutre : les teintes redeviennent
   jugeables et les noms cessent de concourir avec la photo. */
.palette {
  background: rgba(255, 250, 251, .93);
  border: 1px solid rgba(212, 176, 106, .45);
  border-radius: 24px;
  padding: 22px 18px 18px;
  box-shadow: 0 18px 40px rgba(90, 31, 54, .12);
  max-width: 560px;
}

/* Le nom de la couleur passe en prune profond (#5a1f36 = 11,7:1 sur ce fond)
   et perd son halo, devenu inutile sur une surface opaque. */
.palette .swatch span {
  color: var(--deep);
  font-weight: 600;
  font-size: .95rem;
  text-shadow: none;
}

/* Voile de la section theme : on retablit une protection reelle et uniforme,
   au lieu du degrade horizontal qui laissait 5 % a droite. */
.theme .env::after {
  background: linear-gradient(180deg, rgba(255, 246, 248, .58), rgba(255, 246, 248, .42) 45%, rgba(255, 246, 248, .55));
}

/* ==========================================================================
   V10 — LOT 3 : « Save the Date » et « Myriam & Brice » s'ECRIVENT
   Le hero n'avait aucun attribut data-fx (index.html:104-111) : il etait donc
   exclu du systeme d'ecriture, et ce systeme est de toute facon pilote par le
   defilement, donc incapable d'ecrire a l'arrivee sur le site.
   Ici : animation au chargement, lettre par lettre, avec petales et bulles.
   SECURITE : .hw seul n'a AUCUNE opacite forcee. Les lettres ne sont invisibles
   que pendant l'ecriture (.is-writing). Si l'animation ne part pas, le titre
   reste lisible au lieu de disparaitre.
   ========================================================================== */
.hw { display: inline-block; will-change: auto; }
.is-writing .hw {
  opacity: 0;
  animation: hero-write .52s cubic-bezier(.2, .8, .2, 1) forwards;
  animation-delay: calc(var(--i, 0) * 68ms + 260ms);
}
@keyframes hero-write {
  from { opacity: 0; transform: translateY(.3em) scale(.9) rotate(-4deg); filter: blur(3px); }
  to   { opacity: 1; transform: none; filter: none; }
}

/* Couche des particules d'ecriture : posee dans le hero, retiree a la fin. */
.hero__ink { position: absolute; inset: 0; pointer-events: none; overflow: visible; z-index: 4; }
.hero__ink .ink {
  position: absolute; width: var(--s); height: var(--s); margin: calc(var(--s) / -2) 0 0 calc(var(--s) / -2);
  opacity: 0; animation: ink-float var(--d) cubic-bezier(.25, .7, .35, 1) forwards;
}
.hero__ink .ink--petal { border-radius: 60% 40% 55% 45%; background: linear-gradient(140deg, rgba(246, 196, 210, .95), rgba(217, 138, 163, .85)); }
.hero__ink .ink--bubble { border-radius: 50%; background: radial-gradient(circle at 32% 30%, rgba(255, 255, 255, .95), rgba(247, 233, 222, .45) 55%, rgba(212, 176, 106, .18)); box-shadow: 0 0 6px rgba(255, 255, 255, .5); }
@keyframes ink-float {
  0%   { opacity: 0; transform: translate(0, 0) scale(.3) rotate(0deg); }
  22%  { opacity: 1; }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(1) rotate(var(--rot)); }
}

/* Animations coupees (reglage du panneau, ou « reduire les animations » du
   telephone) : les lettres apparaissent d'un coup, entieres, sans particules. */
html[data-anim="off"] .is-writing .hw { animation: none; opacity: 1; }
html[data-anim="off"] .hero__ink { display: none; }
@media (prefers-reduced-motion: reduce) {
  .is-writing .hw { animation: none; opacity: 1; }
  .hero__ink { display: none; }
}

/* « Save » et « Date » sont peints par un degrade decoupe sur le texte
   (.title__word : background-clip:text + color:transparent). Une fois le mot
   decoupe en lettres, chaque lettre est une boite a part : elle heritait du
   color:transparent SANS heriter du degrade, donc le mot disparaissait.
   On redonne le degrade a chaque lettre, et on garde le miroitement d'origine
   en le decalant legerement : l'or traverse le mot lettre apres lettre. */
.title__word .hw {
  background: linear-gradient(100deg, var(--deep) 0%, var(--primary) 30%, #c0688a 48%, var(--gold) 58%, var(--primary) 72%, var(--deep) 100%);
  background-size: 260% 100%;
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
  animation: shimmer calc(7s * var(--speed)) ease-in-out infinite;
  animation-delay: calc(var(--i, 0) * -.45s);
}
.is-writing .title__word .hw {
  animation:
    hero-write .52s cubic-bezier(.2, .8, .2, 1) forwards calc(var(--i, 0) * 68ms + 260ms),
    shimmer calc(7s * var(--speed)) ease-in-out infinite calc(var(--i, 0) * -.45s);
}
html[data-anim="off"] .is-writing .title__word .hw,
html[data-anim="off"] .title__word .hw { animation: none; opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .is-writing .title__word .hw, .title__word .hw { animation: none; opacity: 1; }
}

/* ==========================================================================
   V10 — LOT 4 : fluidite du defilement (priorite de l'utilisateur)
   ========================================================================== */

/* 1. La barre de navigation mobile est FIXE et donc visible pendant tout le
      defilement. Son backdrop-filter obligeait le GPU a re-flouter tout ce qui
      passe derriere, a chaque image : c'est l'effet CSS le plus couteux du
      site. Le nettoyage de performance existant (« V7 ») traitait deja 7 autres
      selecteurs mais avait oublie celui-la, le seul reellement actif.
      On le retire et on compense par un fond plus opaque. */
.dock { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; background: rgba(255, 250, 251, .97); }

/* 2. will-change cree une couche GPU permanente. .poster__inner la reservait
      pour un effet d'inclinaison au survol, explicitement desactive au toucher
      (js/app.js teste state.isTouch) : sur telephone cette couche ne sert a rien. */
@media (hover: none) {
  .poster__inner { will-change: auto; }
}

/* 3. Mise en pause de tout ce qui est anime dans une section eloignee.
      La classe is-offscreen est posee par un IntersectionObserver (js/app.js,
      observeOffscreen) avec une marge de 60 % d'ecran de part et d'autre :
      l'animation est donc deja repartie bien avant d'entrer dans le champ. */
.is-offscreen .petal,
.is-offscreen .deco,
.is-offscreen .over,
.is-offscreen .kenburns,
.is-offscreen .hearts i,
.is-offscreen .swatch i,
.is-offscreen .swatch i::before,
.is-offscreen .ribbon__track,
.is-offscreen .poster__inner::after,
.is-offscreen .env,
.is-offscreen .flourish__heart,
.is-offscreen .trail__heart { animation-play-state: paused; }

/* ==========================================================================
   V10 — LOT 5 : la photo secondaire etait trop petite pour qu'on y voie
   quoi que ce soit (133 px de large sur un telephone de 390 px, soit moins
   que la largeur d'un visage lisible). On elargit le medaillon sans toucher
   a sa position ni a l'alternance photo/texte de la vague.
   ========================================================================== */
.wm--second { width: 54%; right: -8%; }
@media (max-width: 760px) {
  .wm--second { width: 62%; right: -8%; bottom: -8%; }
}

/* ==========================================================================
   V10 — LOT 5b (ESSAI) : nettete des fonds d'environnement
   Les 10 fonds font tous 1642x958. Une section de 3112 px de haut sur mobile
   force l'image a couvrir 3,25x sa hauteur native, puis l'ecran multiplie
   encore par 3 (densite) : le fond est etire jusqu'a ~10,9x. C'est la cause
   des fonds flous, pas la qualite des fichiers (verifie : pas de sur-compression).
   On plafonne la hauteur de la couche au lieu d'agrandir les fichiers (0 Ko).
   ========================================================================== */
/* Un element sticky OCCUPE sa place dans le flux : la page s'allongeait de
   2700 px (+25 %). On annule cette contribution par une marge negative egale
   a sa propre hauteur. Et on lui rend du MOUVEMENT : la couche reste calee
   (donc nette) mais l'image derive verticalement au fil du defilement, pilotee
   par --envy depuis js/app.js. C'est une vraie parallaxe, composee sur le GPU,
   qui fonctionne aussi sur telephone contrairement a l'ancienne (coupee sous 760px). */
.universe .env, .memories .env, .closing .env {
  position: sticky; top: 0; height: 100vh; max-height: 900px;
  margin-bottom: calc(-1 * min(100vh, 900px));
  transform: translate3d(0, var(--envy, 0px), 0) scale(1.14);
  transform-origin: center center;
}
/* Le hero : sa couche de fond deborde volontairement (inset -6%) pour l'effet de
   zoom lent. On plafonne seulement sa hauteur, sans toucher au reste. */
.hero__bg { max-height: min(106vh, 940px); }
/* .theme (1,10x) et .infos (0,81x) ne sont pas etirees : on n'y touche pas. */

/* ==========================================================================
   V10 — LOT 7 : agrandissement des photos et des videos (demande utilisateur)
   Releve avant : grande photo 290 px sur mobile et 571 a 628 px sur desktop,
   medaillon secondaire 180 px / 308 px. Trop petit pour bien voir les visages.
   Le medaillon secondaire est exprime en % de la grande photo : il grandit donc
   automatiquement avec elle.
   ========================================================================== */
/* Desktop UNIQUEMENT : la colonne image prend nettement plus de place que la
   colonne texte. La borne min-width est indispensable : sans elle, cette regle
   ecrasait le passage en UNE colonne du bloc mobile (ligne 1003) parce qu'elle
   est ecrite plus bas dans le fichier, et les photos RETRECISSAIENT a 187 px. */
@media (min-width: 761px) {
  .wave__row { grid-template-columns: 1.68fr .82fr; gap: clamp(18px, 2.4vw, 44px); }
  .wave--dense .wave__row { grid-template-columns: 1.5fr .9fr; }
  /* Une ligne sur deux est inversee (.wave__row--flip place la photo en 2e colonne).
     Avec des colonnes tres inegales, la photo tombait alors dans la colonne ETROITE
     et retrecissait au lieu de grandir. On inverse donc aussi les colonnes. */
  .wave__row--flip { grid-template-columns: .82fr 1.68fr; }
  .wave--dense .wave__row--flip { grid-template-columns: .9fr 1.5fr; }
  .wm--second { width: 58%; right: -7%; }
  .infos__photo { width: clamp(180px, 22vw, 300px); }
}

@media (max-width: 760px) {
  /* Sur telephone la photo sort de la gouttiere du conteneur et prend toute la
     largeur de l'ecran : c'est le seul moyen d'atteindre l'agrandissement demande
     sans rogner le medaillon secondaire, qui deborde volontairement sur le cote. */
  /* ATTENTION : ne PAS revenir a "margin-left:50% + translateX(-50%)".
     C'etait la cause du site decale vers la droite sur iPhone. Une transformation
     ne deplace que le rendu, jamais la boite de mise en page. Chrome tient compte
     de la transformation pour calculer la largeur de la page et n'annoncait donc
     aucun debordement ; Safari calcule cette largeur AVANT transformation, et
     trouvait un bord droit a 581 px sur un ecran de 390 : 191 px de trop. La page
     devenait plus large que l'ecran, et tout le contenu centre sur la page
     paraissait pousse a droite. La barre du bas, elle, est en position fixe : elle
     se cale sur l'ecran et restait donc correcte, ce qui a mis sur la piste.
     Ici tout se joue en marges : la boite de mise en page EST au bon endroit. */
  .wave__media {
    max-width: none;
    width: auto;
    margin-inline: calc(50% - 50vw + 6px);
    transform: none;
  }
  .wm--second { width: 60%; right: 0; }
}

/* ==========================================================================
   V10 — LOT 8 : plus aucun texte par-dessus les photos au defilement
   Mesure : en descendant, le bloc de texte du hero glissait SUR la photo
   (chevauchement de 20 px a 239 px) tout en etant encore a 68 % d'opacite,
   parce qu'il portait z-index:3 contre 2 pour la photo. La photo passe devant :
   le texte s'efface proprement DERRIERE elle au lieu de la barrer.
   ========================================================================== */
.hero .arch { z-index: 6; }
.hero .arch__caption { z-index: 7; }

/* Section Theme : le titre et la phrase restaient sous le seuil de lisibilite
   (3,77 a 4,50 en moyenne, 1,17 au pire pixel sur la photo de champ de roses).
   On passe ces deux textes en prune profond et on renforce un peu le voile. */
#theme .section-title h2, #theme .theme__note { color: var(--deep); }
.theme .env::after {
  background: linear-gradient(180deg, rgba(255, 246, 248, .72), rgba(255, 246, 248, .58) 45%, rgba(255, 246, 248, .68));
}

/* ==========================================================================
   V10 — LOT 9 : FLUIDITE REELLE
   Mesure au processeur bride x6 (telephone milieu de gamme) : 43 ms par image,
   soit 23 images par seconde, dont 2711 ms de RECALCUL DE STYLE contre seulement
   255 ms de mise en page. Le cout n'est donc ni le script ni la geometrie : c'est
   le nombre d'animations qui tournent en permanence (144 relevees a mi-page).
   On en supprime le maximum sans toucher a ce qui fait vivre la page.
   ========================================================================== */

/* 1. Le curseur d'ecriture continuait a clignoter APRES la fin de l'ecriture :
      il etait seulement rendu transparent. 17 animations infinies pour rien. */
[data-fx="write"].is-done .caret { opacity: 0; animation: none; display: none; }

/* 2. Le prechargeur garde ses animations une fois masque. */
.preloader.is-hidden, .preloader.is-hidden * { animation: none !important; }

/* 3. Sur telephone, on coupe les animations decoratives les plus couteuses :
      elles portent sur de grandes surfaces ou sur de nombreux elements, pour un
      apport visuel faible une fois le contenu en mouvement. Les petales, les
      coeurs, le chemin dore et la derive des fonds sont CONSERVES. */
@media (max-width: 760px) {
  .aurora { display: none; }                 /* 3 grands degrades flous plein ecran */
  .deco { animation: none !important; }      /* balancement des decors */
  .arch, .poster { animation: none !important; }
  .kenburns { animation: none !important; }  /* zoom lent sur de grandes images */
  .swatch i, .swatch i::before { animation: none !important; }
  .flourish__heart { animation: none !important; }
  .btn--shine::after { animation: none !important; }
  .hero__bg { animation: none !important; }
}

/* Suite du lot 9, apres nouveau releve : 94 animations tournaient encore.
   Les 24 coeurs du bandeau pulsaient inutilement, et l'aurora continuait a
   s'animer malgre son display:none.
   RECTIFICATIF : ce commentaire affirmait que le bandeau ne defile plus sur
   telephone. C'est FAUX, et je l'avais ecrit sans le verifier. Mesure du
   deplacement reel de #ribbonTrack sur 1200 ms : -74,5 px a 320 px, -73,5 px a
   360, 390 et 430 px, soit environ 61 px par seconde. Aucune regle ne coupe
   .ribbon__track sous 760 px. Seul le pouls des coeurs est supprime ici. */
@media (max-width: 760px) {
  .ribbon__item i { animation: none !important; }
  .aurora, .aurora i { animation: none !important; }
  .ucard__heart { animation: none !important; }
}

/* ==========================================================================
   V10 — LOT 10 : le chemin dore ne doit plus passer par-dessus les photos
   Mesure par comparaison de pixels (le tracé est en pointer-events:none, donc
   invisible a un test de survol) : il recouvrait 0,7 a 9 % de CHAQUE photo.
   Cause : le svg #trail est pose a z-index 1 au niveau racine, alors que les
   photos n'avaient aucun z-index et restaient donc en dessous.
   ========================================================================== */
/* .closing__media a ete RETIRE de cette liste : voir le bloc V13 LOT 2 en fin de
   fichier. Cette photo est posee en position:absolute avec ses quatre ancrages ;
   lui imposer position:relative annulait ces ancrages et la faisait entrer dans
   le flux. Elle prenait alors 420 px en haut de la section, qui s'ajoutaient aux
   300 px reserves plus bas pour elle, d'ou 338 px de vide ; et sur grand ecran,
   un div vide sans hauteur ne rendait plus AUCUN pixel. */
.wave__media,
.infos__photo,
.theme__photo,
.theme__poster,
.river__big,
.river__small,
.arch {
  position: relative;
  z-index: 2;
}

/* Le hero porte isolation:isolate : tout z-index pose a l'interieur y reste
   prisonnier, et le hero entier restait donc SOUS le trace (z-1), qui descendait
   en plein milieu de la photo du couple. On remonte le hero au-dessus du trace :
   le chemin emerge visuellement au bas du hero au lieu de le traverser. */
.hero { z-index: 2; }
/* Meme situation pour le compte a rebours, lui aussi isole. */
.countdown { z-index: 2; }

/* ==========================================================================
   V11 — LOT 9 : FONDU DES PHOTOS ET DES VIDEOS, equilibre sur les 4 cotes
   Couverture du masque mesuree le long de chaque bord (bande de 16 px sur un
   carre noir plein) AVANT correction :
     omask--1     haut 2 %   bas 84 %   gauche 7 %   droite 86 %
     omask--wide  haut 0 %   bas 97 %   gauche 30 %  droite 83 %
     omask--heart haut 0 %   bas 78 %   gauche 0 %   droite 53 %
   Autrement dit le haut et la gauche se fondaient, mais le BAS et la DROITE
   etaient coupes net. Cause : les ellipses debordaient de la boite vers le bas et
   la droite, le degrade n'avait donc plus la place de s'eteindre avant le bord.
   Correction : chaque ellipse se termine DESORMAIS a l'interieur de la boite sur
   les quatre cotes (centre + rayon <= 96 %, centre - rayon >= 2 %). Le fondu est
   regulier tout autour, quel que soit le mode choisi dans le panneau.
   ========================================================================== */
.omask--1 {
  -webkit-mask-image: radial-gradient(ellipse 42% 36% at 48% 40%, #000 70%, transparent 100%), radial-gradient(ellipse 38% 32% at 54% 62%, #000 68%, transparent 100%), radial-gradient(ellipse 36% 26% at 44% 68%, #000 66%, transparent 100%);
  mask-image: radial-gradient(ellipse 42% 36% at 48% 40%, #000 70%, transparent 100%), radial-gradient(ellipse 38% 32% at 54% 62%, #000 68%, transparent 100%), radial-gradient(ellipse 36% 26% at 44% 68%, #000 66%, transparent 100%);
}
.omask--2 {
  -webkit-mask-image: radial-gradient(ellipse 42% 36% at 52% 40%, #000 70%, transparent 100%), radial-gradient(ellipse 38% 32% at 46% 62%, #000 68%, transparent 100%), radial-gradient(ellipse 34% 26% at 58% 68%, #000 66%, transparent 100%);
  mask-image: radial-gradient(ellipse 42% 36% at 52% 40%, #000 70%, transparent 100%), radial-gradient(ellipse 38% 32% at 46% 62%, #000 68%, transparent 100%), radial-gradient(ellipse 34% 26% at 58% 68%, #000 66%, transparent 100%);
}
.omask--3 {
  -webkit-mask-image: radial-gradient(ellipse 43% 38% at 50% 42%, #000 70%, transparent 100%), radial-gradient(ellipse 36% 30% at 42% 64%, #000 68%, transparent 100%), radial-gradient(ellipse 36% 30% at 58% 64%, #000 68%, transparent 100%);
  mask-image: radial-gradient(ellipse 43% 38% at 50% 42%, #000 70%, transparent 100%), radial-gradient(ellipse 36% 30% at 42% 64%, #000 68%, transparent 100%), radial-gradient(ellipse 36% 30% at 58% 64%, #000 68%, transparent 100%);
}
.omask--4 {
  -webkit-mask-image: radial-gradient(ellipse 42% 38% at 47% 42%, #000 70%, transparent 100%), radial-gradient(ellipse 38% 32% at 56% 58%, #000 68%, transparent 100%), radial-gradient(ellipse 34% 24% at 50% 70%, #000 66%, transparent 100%);
  mask-image: radial-gradient(ellipse 42% 38% at 47% 42%, #000 70%, transparent 100%), radial-gradient(ellipse 38% 32% at 56% 58%, #000 68%, transparent 100%), radial-gradient(ellipse 34% 24% at 50% 70%, #000 66%, transparent 100%);
}
.omask--arch {
  -webkit-mask-image: radial-gradient(ellipse 42% 34% at 50% 38%, #000 72%, transparent 100%), radial-gradient(ellipse 42% 32% at 50% 62%, #000 70%, transparent 100%);
  mask-image: radial-gradient(ellipse 42% 34% at 50% 38%, #000 72%, transparent 100%), radial-gradient(ellipse 42% 32% at 50% 62%, #000 70%, transparent 100%);
}
.omask--wide {
  -webkit-mask-image: radial-gradient(ellipse 44% 42% at 50% 48%, #000 70%, transparent 100%), radial-gradient(ellipse 36% 36% at 58% 50%, #000 68%, transparent 100%), radial-gradient(ellipse 34% 24% at 46% 70%, #000 66%, transparent 100%);
  mask-image: radial-gradient(ellipse 44% 42% at 50% 48%, #000 70%, transparent 100%), radial-gradient(ellipse 36% 36% at 58% 50%, #000 68%, transparent 100%), radial-gradient(ellipse 34% 24% at 46% 70%, #000 66%, transparent 100%);
}
.medallion {
  -webkit-mask-image: radial-gradient(ellipse 44% 42% at 50% 50%, #000 70%, transparent 100%), radial-gradient(ellipse 36% 36% at 58% 50%, #000 68%, transparent 100%);
  mask-image: radial-gradient(ellipse 44% 42% at 50% 50%, #000 70%, transparent 100%), radial-gradient(ellipse 36% 36% at 58% 50%, #000 68%, transparent 100%);
}

/* Fable a releve 15 curseurs d'ecriture qui clignotaient en permanence pour des
   titres pas encore a l'ecran : la liste de mise en pause les avait oublies.
   Gain pur, aucun changement visuel. */
/* Le clignotement lui-meme est supprime : 17 animations infinies permanentes
   pour une barre de 2 px. La barre reste visible pendant l ecriture et
   disparait quand le titre est fini (regle .is-done plus haut). */
[data-fx="write"] .caret { animation: none !important; }

/* ==========================================================================
   V11 — LOT 1 : LISIBILITE (mesures Fable)
   - lanterne du compte a rebours : 5727 px2 de recouvrement sur le titre, en
     mobile uniquement ; le fichier pese 140 Ko et n'est pas telecharge s'il est
     en display:none, donc autant de gagne sur les connexions lentes.
   - titre des infos : 3,76:1 sur ordinateur, 1,13 au pire pixel.
   - bloc date / lieu / dress code : 2,7 a 3,3:1 pour un seuil de 4,5. Cause :
     .info p utilise --text-soft, que js/app.js recalcule en #917782, lequel
     plafonne a 4,07:1 MEME sur du blanc pur.
   ========================================================================== */

/* --- Le grand jour approche --- */
@media (max-width: 760px) { .countdown .deco--lantern { display: none; } }
.countdown .section-title { position: relative; }
.countdown .section-title::before {
  content: ""; position: absolute; inset: -14% -10%; z-index: -1; border-radius: 50%;
  background: radial-gradient(ellipse at 50% 50%, rgba(74,23,41,.62) 0%, rgba(74,23,41,.34) 45%, rgba(74,23,41,0) 75%);
  pointer-events: none;
}
.section-title--light h2, .section-title--light p { text-shadow: 0 2px 6px rgba(40,10,24,.9), 0 6px 24px rgba(40,10,24,.7); }

/* --- Titre des infos pratiques, pose sur une surface --- */
#infos .section-title {
  background: rgba(255,250,251,.86); border-radius: 26px; padding: 18px 20px 10px;
  box-shadow: 0 0 0 1px rgba(212,176,106,.42); max-width: 640px; margin-inline: auto;
}
#infos .section-title h2, #infos .section-title p { text-shadow: none; }
#infos .section-title p { color: var(--deep); }
@media (max-width: 760px) { .infos .deco--envelope { top: -3%; right: -8%; width: 17vw; z-index: 0; } }

/* --- Bloc date / lieu / dress code / confirmation, en lignes sur une carte --- */
.infoline {
  background: rgba(255,250,251,.92);
  box-shadow: 0 0 0 1px rgba(212,176,106,.45), 0 18px 40px rgba(90,31,54,.12);
  border-radius: 28px; padding: 10px 22px; grid-template-columns: 1fr 1fr; gap: 0 28px;
}
.infoline::before { display: none; }
.infoline .info {
  display: grid; grid-template-columns: 44px 1fr;
  grid-template-areas: "ico h3" "ico p" "ico a";
  column-gap: 14px; row-gap: 3px; text-align: left; padding: 16px 0;
  border-bottom: 1px solid rgba(212,176,106,.35);
  background: none; border-left: 0; border-right: 0; border-top: 0; box-shadow: none;
}
.infoline .info:nth-last-child(-n+2) { border-bottom: 0; }
.infoline .info h3, .infoline .info p, .infoline .info a { text-shadow: none; }
.infoline .info__icon { grid-area: ico; width: 42px; height: 42px; margin: 0; box-shadow: 0 0 0 2px var(--gold-light); }
.infoline .info__icon .ic { width: 20px; height: 20px; }
.infoline .info h3 { grid-area: h3; font-size: 1.2rem; color: var(--deep); }
.infoline .info p { grid-area: p; color: var(--deep); font-size: .95rem; }
.infoline .info a { grid-area: a; justify-self: start; }
.infoline .info a.info__link {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 12px; margin-top: 6px;
  border-radius: 999px; background: #fff; border: 1px solid rgba(212,176,106,.6);
  font-size: .84rem; box-shadow: 0 6px 16px rgba(139,53,85,.12); border-bottom-width: 1px;
}
.info__link .ic { width: 15px; height: 15px; }
@media (max-width: 760px) {
  .infoline { grid-template-columns: 1fr; padding: 6px 16px; gap: 0; }
  .infoline .info { padding: 14px 0; }
  .infoline .info:nth-last-child(-n+2) { border-bottom: 1px solid rgba(212,176,106,.35); }
  .infoline .info:last-child { border-bottom: 0; }
  .infoline .info h3 { font-size: 1.15rem; }
  .infoline .info p { font-size: .92rem; }
}

/* ==========================================================================
   V11 — LOT 2 : ACCUEIL sans boutons
   Les pastilles et la citation deviennent UN SEUL cartouche : inline-grid avec
   justify-items:stretch donne a la citation exactement la largeur de la rangee
   de pastilles. La taille de police en vw garantit qu'elle tient sur une ligne.
   flex-wrap:nowrap corrige le cas des telephones de 360 px, ou la 2e pastille
   passait a la ligne (il ne restait que 3 px de marge).
   ========================================================================== */
.hero__lead { display: inline-grid; justify-items: stretch; gap: 10px; margin-top: 16px; max-width: 100%; }
.hero__lead .hero__meta { margin-top: 0; flex-wrap: nowrap; gap: 8px; }
.hero__lead .pill { white-space: nowrap; }
.hero__lead .hero__quote {
  margin: 0; max-width: none; width: 100%; white-space: nowrap; text-align: center;
  font-size: clamp(.95rem, 4.35vw, 1.28rem); padding: 8px 14px; letter-spacing: .005em;
}
@media (max-width: 370px) {
  .hero__lead .pill { padding: 9px 11px; font-size: .72rem; letter-spacing: .03em; gap: 7px; }
}
/* la couche de particules d'ecriture ne doit pas heriter d'un delai d'entree */
.hero__ink { animation: none !important; opacity: 1 !important; transform: none !important; }

/* ==========================================================================
   V11 — LOT 3 : EN-TETE
   Demande : « Myriam & Brice » en toutes lettres, en BLANC, visible pendant tout
   le defilement. Du blanc sur le rose clair d'origine donne 1,2:1, illisible :
   l'en-tete passe donc en ruban prune, comme le bandeau defilant du site. Blanc
   sur ce prune = 12,4:1, y compris quand une photo claire passe derriere.
   Sur ordinateur les 6 liens sont conserves (choix de l'utilisateur), le titre
   reste donc a gauche ; sur telephone il est centre et il n'y a plus de menu.
   ========================================================================== */
:root { --header-h: 58px; }
@media (min-width: 761px) { :root { --header-h: 68px; } }

.site-header, .site-header.is-scrolled {
  background: rgba(74, 23, 41, .94);
  border-bottom: 1px solid rgba(212, 176, 106, .55);
  box-shadow: 0 8px 24px rgba(40, 10, 24, .22);
}
.header__inner { grid-template-columns: 1fr; justify-items: center; align-items: center; }
.brand__names {
  font-family: var(--font-script); font-size: clamp(1.85rem, 6vw, 2.3rem); line-height: 1;
  color: #fff; text-shadow: 0 2px 10px rgba(40, 10, 24, .5); white-space: nowrap; display: block;
}
.brand__names em { font-style: normal; color: var(--gold); font-size: .8em; margin: 0 .08em; }

@media (min-width: 761px) {
  .header__inner { grid-template-columns: auto 1fr; justify-items: start; }
  .main-nav { justify-self: end; }
  .main-nav a { color: rgba(255, 240, 245, .92); }
  .main-nav a:hover, .main-nav a.is-active { color: #fff; }
  .main-nav a.is-active::after, .main-nav a::after { background: var(--gold); }
}
@media (max-width: 760px) { .main-nav { display: none; } }

/* La barre de progression se lit mieux en or sur le ruban prune. */
.progress-bar { height: 2px; background: linear-gradient(90deg, var(--gold), #fff3d6); box-shadow: none; }
/* Le monogramme du pied de page etait prune sur presque noir : 2,39:1. */
.site-footer .brand__mark, .site-footer .brand__names { color: #fff; }

/* ==========================================================================
   V11 — LOT 4 : BARRE DU BAS a 5 entrees, visible partout
   Meme ruban prune que l'en-tete : la page est ainsi encadree en haut et en bas
   par deux lisers dores, comme un faire-part, et non comme une application.
   « Je confirme » est au centre, en or, dans une cellule plus large : c'est le
   SEUL appel au formulaire sur tout le site.
   ========================================================================== */
.dock {
  display: grid; grid-template-columns: 1fr 1fr 1.35fr 1fr 1fr;
  width: min(94vw, 460px); padding: 6px; gap: 2px;
  background: rgba(74, 23, 41, .96); border-radius: 22px;
  box-shadow: 0 16px 40px rgba(40, 10, 24, .35), 0 0 0 1px rgba(212, 176, 106, .55);
}
.dock a, .dock button {
  color: #fbe4ec; font-size: .6rem; letter-spacing: .03em; text-transform: uppercase;
  font-weight: 600; padding: 7px 2px 5px; gap: 2px; border-radius: 16px;
}
.dock .ic { width: 20px; height: 20px; stroke-width: 1.6; }
.dock .dock__rsvp { background: linear-gradient(135deg, var(--gold), #e8cd8f); color: var(--deep) !important; }
.dock .dock__rsvp .ic { fill: currentColor; stroke: none; }
body { padding-bottom: 88px; }
.preview-badge, .music-toggle { bottom: 96px; }
.toast { bottom: 100px; }

/* Feuille « Plus » : reutilise le composant .sheet du calendrier, zero CSS de conteneur. */
.sheet__panel { max-height: 86vh; overflow: auto; }
.plus__facts { display: grid; margin-bottom: 6px; }
.plus__fact { display: grid; grid-template-columns: 22px 1fr; gap: 12px; align-items: start; padding: 10px 4px; border-bottom: 1px solid rgba(212,176,106,.35); }
.plus__fact:last-child { border-bottom: 0; }
.plus__fact .ic { width: 20px; height: 20px; color: var(--primary); margin-top: 3px; }
.plus__fact b { display: block; font-family: var(--font-display); font-size: 1.1rem; color: var(--deep); }
.plus__fact span { display: block; font-size: .9rem; color: var(--text); }
.plus__fact a { display: inline-block; margin-top: 4px; font-size: .86rem; font-weight: 600; color: var(--primary); border-bottom: 1px solid rgba(139,53,85,.35); }
.plus__h { margin-top: 14px; }
#plusNav a.is-off { display: none; }

/* A 320 px, « JE CONFIRME » en capitales passait sur deux lignes dans sa cellule.
   On resserre le libelle sur les tres petits ecrans plutot que de le tronquer. */
@media (max-width: 360px) {
  .dock { grid-template-columns: 1fr 1fr 1.5fr 1fr 1fr; padding: 5px; }
  .dock a, .dock button { font-size: .54rem; letter-spacing: .01em; padding: 6px 1px 4px; }
  .dock .ic { width: 18px; height: 18px; }
  .dock .dock__rsvp span { white-space: nowrap; }
}

/* ==========================================================================
   V11 — LOT 6 : FORMULAIRE EN 3 ETAPES
   Trois coeurs qui se dorent plutot que des numeros dans des ronds : on reste
   dans le vocabulaire du faire-part, pas dans celui d'une application.
   ========================================================================== */
.rsvp__steps { list-style: none; margin: -4px 0 0; padding: 0; display: flex; justify-content: center; gap: 14px; }
.rsvp__steps li {
  width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  font-size: .85rem; color: rgba(212,176,106,.5); border: 1px solid rgba(212,176,106,.5);
  background: #fff; transition: color .3s, background .3s, border-color .3s;
}
.rsvp__steps li.is-current { color: #fff; background: linear-gradient(135deg, var(--gold), #e8cd8f); border-color: var(--gold); }
.rsvp__stepname { margin: -8px 0 0; text-align: center; font-size: .76rem; letter-spacing: .08em; text-transform: uppercase; color: var(--primary); }
.rsvp__step { border: 0; padding: 0; margin: 0; min-width: 0; display: none; gap: 14px; }
.rsvp__step.is-current { display: grid; }
.rsvp__nav { display: grid; grid-template-columns: auto 1fr; gap: 10px; }
.rsvp__recap { margin: 0; display: grid; gap: 8px; padding: 14px 16px; border-radius: 16px; background: #fff; border: 1px solid rgba(212,176,106,.5); }
.rsvp__recap div { display: grid; grid-template-columns: 96px 1fr; gap: 10px; font-size: .92rem; }
.rsvp__recap dt { color: var(--primary); font-size: .74rem; letter-spacing: .08em; text-transform: uppercase; padding-top: 3px; }
.rsvp__recap dd { margin: 0; color: var(--deep); font-weight: 600; overflow-wrap: anywhere; }
.rsvp__slogan { margin: 0; font-size: 1.55rem; color: var(--primary); line-height: 1.2; }
.rsvp__after { display: grid; gap: 8px; width: 100%; margin: 4px 0 2px; }
.rsvp__after .btn { width: 100%; }

/* ==========================================================================
   V11 — LOT 7 : MOUVEMENT
   H2 : les fonds du theme et des infos derivent comme les trois autres. Le
   mecanisme existe deja (js/app.js ecrit --envy sur TOUS les .env, seuls trois
   le consommaient) : zero ligne de JS en plus, deux couches composees de plus,
   plafonnees a 900 px comme les autres.
   ========================================================================== */
.theme .env, .infos .env {
  position: sticky; top: 0; height: 100vh; max-height: 900px;
  margin-bottom: calc(-1 * min(100vh, 900px));
  transform: translate3d(0, var(--envy, 0px), 0) scale(1.14);
  transform-origin: center center;
}

/* H3 ECARTE APRES MESURE : animation-timeline: view() est bien reconnue par le
   navigateur (la regle @supports passe), mais la transformation restait bloquee
   a sa valeur finale quelle que soit la position de defilement, verifie sur cinq
   positions successives. Elle n'apportait donc AUCUN mouvement et decalait les
   decors de 34 px. On ne la garde pas.
   Le mouvement des fonds (H2, plus haut) fonctionne, lui : --envy varie bien de
   -30 a +45 px au fil du defilement, sur sept fonds. */

/* ==========================================================================
   V11 — LOT 8 : lisibilite des textes de section, titre agrandi, bouton Fermer
   ========================================================================== */

/* 1. Lisibilite des textes de section, SANS forme visible.
      Premiere tentative : un voile ovale opaque derriere le texte. Rejete par
      l'utilisateur, et a juste titre : l'ellipse se voyait comme une tache creme
      avec un bord net, posee sur la photo.
      Ici : un halo dense qui epouse EXACTEMENT les lettres (plusieurs ombres
      superposees, la meme repetee pour cumuler l'opacite pres du glyphe), plus
      un voile sans bord lateral, qui deborde de part et d'autre de l'ecran et ne
      se ferme donc jamais en forme. On ne voit plus qu'une brume, pas un objet. */
.wave__text::before {
  inset: -26px -24px;
  border-radius: 0;
  filter: none;
  background: linear-gradient(180deg,
    rgba(255, 249, 250, 0) 0%,
    rgba(255, 249, 250, .55) 26%,
    rgba(255, 249, 250, .62) 50%,
    rgba(255, 249, 250, .55) 74%,
    rgba(255, 249, 250, 0) 100%);
}
.wave__cap::before {
  inset: -16px -24px;
  border-radius: 0;
  filter: none;
  background: linear-gradient(180deg,
    rgba(255, 249, 250, 0) 0%,
    rgba(255, 249, 250, .52) 30%,
    rgba(255, 249, 250, .58) 50%,
    rgba(255, 249, 250, .52) 70%,
    rgba(255, 249, 250, 0) 100%);
}
.wave__cap { position: relative; z-index: 2; }
.wave__cap::before { content: ""; position: absolute; z-index: -1; }
/* Le halo qui suit les lettres : la meme ombre repetee cumule son opacite tout
   pres du glyphe et s'eteint vite, donc aucune boite ne se dessine. */
.wave__text h3, .wave__text p, .wave__cap {
  text-shadow:
    0 0 3px rgba(255, 249, 250, .95),
    0 0 3px rgba(255, 249, 250, .95),
    0 0 7px rgba(255, 249, 250, .9),
    0 0 14px rgba(255, 249, 250, .8),
    0 1px 2px rgba(255, 249, 250, .9);
}

/* 2. Les titres de souvenir grandissent de 10 % et recoivent un leger relief. */
.wave__text h3, .wave__cap {
  font-size: clamp(2.42rem, 4.18vw, 3.74rem);
  text-shadow: 0 1px 0 rgba(255, 255, 255, .55), 0 3px 10px rgba(139, 53, 85, .22);
}
@media (max-width: 760px) {
  /* La taille reellement rendue sur telephone etait 2,2rem (le minimum du clamp),
     et non la valeur de la regle mobile d'origine. +10 % donne donc 2,42rem. */
  .wave__text h3 { font-size: 2.42rem; }
  .wave__cap { font-size: 2.42rem; }
}

/* 3. Le bouton Fermer du panneau « Plus » tombait 145 px SOUS l'ecran : le
      panneau etait defilable mais le bouton hors de vue. Il reste desormais
      colle en bas du panneau, toujours atteignable. */
#plusSheet .sheet__panel { display: flex; flex-direction: column; gap: 10px; }
/* Le bouton Fermer n'est plus colle en bas : il recouvrait les liens Parcourir.
   La croix en haut a droite assure la fermeture a tout moment. */
#plusSheet #plusClose { position: static; margin-top: 10px; box-shadow: none; }

/* ==========================================================================
   V11 — LOT 10 : le panneau « Plus » devient une fenetre CENTREE
   Il arrivait par le bas, colle au bord de l'ecran, ce qui se lisait mal sur
   telephone. Il se detache maintenant au milieu, avec une croix en haut a
   droite et le bouton Fermer conserve en bas.
   ========================================================================== */
#plusSheet[open] { align-items: center; justify-content: center; padding: 16px; }
#plusSheet .sheet__panel {
  width: min(92vw, 420px);
  max-height: min(78vh, 640px);
  border-radius: 26px;
  padding: 18px 20px calc(16px + env(safe-area-inset-bottom));
  animation-name: pop;
  box-shadow: 0 30px 80px rgba(40, 10, 24, .45), 0 0 0 1px rgba(212, 176, 106, .5);
}
#plusSheet .sheet__grip { display: none; }
.sheet__x {
  position: absolute; top: 10px; right: 10px; z-index: 2;
  width: 38px; height: 38px; border: 0; border-radius: 50%;
  background: rgba(139, 53, 85, .08); color: var(--primary);
  display: grid; place-items: center; cursor: pointer;
}
.sheet__x svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; }
#plusSheet .sheet__panel { position: relative; }
#plusSheet h3:first-of-type { margin-top: 2px; padding-right: 34px; }

/* ==========================================================================
   V12 — iOS : la page s'affichait decalee vers la droite
   Cause : plusieurs elements debordent VOLONTAIREMENT sur les cotes (decors
   d'angle, couche de fond du hero, couche d'environnement agrandie). Ils
   comptaient sur overflow: clip pour etre coupes. Or overflow: clip n'existe
   pas sur Safari iOS avant la version 16 : rien n'etait coupe, la page devenait
   plus large que l'ecran (581 px au lieu de 390) et se decalait.
   On supprime le debordement A LA SOURCE, au lieu de compter sur un decoupage.
   ========================================================================== */

/* 1. Le hero n'a aucun element colle en defilement : overflow:hidden y est sur
      et fonctionne sur toutes les versions d'iOS. */
.hero { overflow: hidden; }

/* 2. La couche d'environnement etait agrandie de 14 %, donc elle depassait de
      7 % de chaque cote. On la fait simplement PLUS HAUTE : la derive verticale
      reste couverte, et plus rien ne depasse sur les cotes. */
.universe .env, .memories .env, .closing .env, .theme .env, .infos .env {
  height: calc(100vh + 120px);
  max-height: 1020px;
  top: -60px;
  margin-bottom: calc(-1 * min(100vh + 120px, 1020px));
  transform: translate3d(0, var(--envy, 0px), 0);
}

/* 3. Les decors d'angle des sections : sur telephone ils rentrent dans l'ecran
      au lieu de deborder. L'effet de debordement reste sur grand ecran. */
@media (max-width: 760px) {
  .section .deco, .closing .deco { max-width: 26vw; }
  .deco--tr, .deco--br, .deco--garland-r, .deco--rose-r, .infos .deco--envelope { right: 0 !important; }
  .deco--tl, .deco--bl, .deco--garland-l, .deco--rose-l, .deco--lantern-l { left: 0 !important; }
}

/* La brume derriere les textes debordait de 50 % de la largeur d'ecran de chaque
   cote pour n'avoir aucun bord visible. Sur iOS, ou overflow:clip n'existe pas
   avant Safari 16, ce debordement rendait la page 581 px de large au lieu de 390
   et la decalait vers la droite. On la garde dans l'ecran et on eteint ses bords
   gauche et droit par un masque : le resultat visuel est le meme, sans forme. */
.wave__text::before, .wave__cap::before {
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 16%, #000 84%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0%, #000 16%, #000 84%, transparent 100%);
}

/* ==========================================================================
   V12 — suite : cadre des infos affine, et bandeau qui ne deborde plus
   ========================================================================== */

/* Le cadre blanc des infos pratiques etait trop epais : grandes marges internes,
   rayon de 28 px et double ombre. On l'allege sans toucher a la lisibilite,
   qui vient du fond opaque et non de l'epaisseur du cadre. */
#infos .section-title { padding: 12px 16px 6px; border-radius: 20px; box-shadow: 0 0 0 1px rgba(212,176,106,.3); }
.infoline { border-radius: 20px; padding: 2px 16px; box-shadow: 0 0 0 1px rgba(212,176,106,.3), 0 10px 26px rgba(90,31,54,.08); }
@media (max-width: 760px) {
  .infoline { padding: 0 14px; }
  .infoline .info { padding: 12px 0; }
}

/* Le bandeau defilant est agrandi de 3 % et pivote : son cadre fait donc 407 px
   pour un ecran de 390. Sur iOS, sans overflow:clip sur #main, ces 17 px
   decalaient la page. On le garde penche, mais dans l'ecran. */
.ribbon { transform: rotate(-1.1deg) scale(1); }
@media (min-width: 761px) { .ribbon { transform: rotate(-1.1deg) scale(1.02); } }

/* ==========================================================================
   V12 — « Myriam & Brice » reste anime
   Le bloc portait seulement hero-in, l'animation d'ENTREE, qui se termine et
   laisse le nom fige. On lui rend une respiration doree permanente. Les deux
   animations cohabitent car elles touchent des proprietes DIFFERENTES :
   hero-in agit sur opacity et transform, celle-ci sur filter. Une seule
   animation supplementaire sur un seul element, cout mesure ci-dessous.
   ========================================================================== */
.hero__text .names {
  animation:
    hero-in .9s cubic-bezier(.2, .8, .2, 1) both,
    names-lueur calc(5.5s * var(--speed)) ease-in-out 1.4s infinite;
}
@keyframes names-lueur {
  0%, 100% { filter: drop-shadow(0 0 0 rgba(212, 176, 106, 0)); }
  50%      { filter: drop-shadow(0 0 14px rgba(212, 176, 106, .6)); }
}
/* Le « & » dore scintille doucement, en plus. */
.hero__text .names em {
  background: linear-gradient(100deg, var(--gold) 0 40%, #fff3d6 50%, var(--gold) 60% 100%);
  background-size: 260% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: shimmer calc(6s * var(--speed)) ease-in-out infinite;
}
html[data-anim="off"] .hero__text .names,
html[data-anim="off"] .hero__text .names em { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .hero__text .names, .hero__text .names em { animation: none; }
  .hero__text .names em { color: var(--gold); -webkit-text-fill-color: var(--gold); }
}
/* La lueur ne doit tourner que quand le hero est a l'ecran : une animation de
   filter sur un grand texte est chere, et les noms ne sont visibles qu'en haut. */
.is-offscreen .names, .is-offscreen .names em { animation-play-state: paused !important; }

/* ==========================================================================
   V12 — ZOOM des videos dans le medaillon
   Le masque etait pose SUR la video : l'agrandir agrandissait aussi le fondu,
   donc le medaillon changeait de taille au lieu de cadrer la video. Le masque
   passe sur le CADRE, la video vit librement a l'interieur et peut donc etre
   agrandie ou reduite, et deplacee, sans toucher a la forme du fondu.
   ========================================================================== */
.wm--video { aspect-ratio: 4 / 3.2; overflow: hidden; display: block; }
/* La base est « entiere » (contain) et NON « remplir » (cover) : ainsi le curseur
   de zoom est un vrai recul / rapprochement.
     zoom 1,00 : la video est entiere, on voit tout
     zoom 1,25 : elle remplit exactement le medaillon (l'ancien reglage par defaut)
     au-dela   : on se rapproche, l'image est rognee
   Avec une source carree de 560 px affichee dans un cadre de 378 x 302, l'image
   reste REDUITE (donc nette) jusqu'a environ 1,85 ; au-dela elle est agrandie et
   se ramollit. C'est pourquoi le curseur s'arrete a 2. */
.wm--video video {
  width: 100%; height: 100%; display: block;
  object-fit: contain;
  object-position: var(--pos, center);
  transform: scale(var(--zoom, 1.25));
  transform-origin: center center;
  opacity: .92;
  aspect-ratio: auto;
}
@media (min-width: 761px) { .wm--video { aspect-ratio: 4 / 3.4; } }

/* ==========================================================================
   V12 — LISIBILITE DES TEXTES DE SECTION
   Releve avant : texte des souvenirs 17,3 px en graisse 400, sous-titres 18,4 px,
   texte des infos 14,7 px, texte de cloture 16,8 px. Cormorant Garamond est une
   police a fort contraste et deliee : a graisse 400 elle parait plus petite
   qu'elle n'est. On monte la taille ET la graisse pour que la lecture se fasse
   sans effort, comme demande.
   ========================================================================== */
.wave__text p {
  font-size: clamp(1.25rem, 1.75vw, 1.5rem);
  font-weight: 500;
  line-height: 1.55;
}
.section-title p, .section-title--left p {
  font-size: clamp(1.22rem, 1.7vw, 1.45rem);
  font-weight: 500;
}
.closing__desc { font-size: clamp(1.1rem, 1.4vw, 1.25rem); font-weight: 500; }
.infoline .info p { font-size: 1.02rem; font-weight: 500; }
.infoline .info h3 { font-weight: 600; }
.wave__cap, .wave__text h3 { font-weight: 400; }   /* les titres calligraphies restent fins */

@media (max-width: 760px) {
  .wave__text p { font-size: 1.25rem; }
  .section-title p, .section-title--left p { font-size: 1.22rem; }
  .infoline .info p { font-size: 1.02rem; }
  .closing__desc { font-size: 1.1rem; }
}

/* ==========================================================================
   V12 — LE HALO BLANC NUISAIT AU TEXTE COURANT
   Le contour blanc epais aidait quand le texte etait petit et fin. Maintenant
   qu'il est plus grand et plus gras, ce contour l'empate et le rend MOINS net.
   Les grands titres, eux, le portent bien : on le leur laisse.
   Pour le texte courant : contour retire, voile legerement renforce a la place.
   ========================================================================== */
.wave__text p {
  text-shadow: 0 1px 1px rgba(255, 249, 250, .85);
}
.wave__text::before {
  background: linear-gradient(180deg,
    rgba(255, 249, 250, 0) 0%,
    rgba(255, 249, 250, .68) 24%,
    rgba(255, 249, 250, .74) 50%,
    rgba(255, 249, 250, .68) 76%,
    rgba(255, 249, 250, 0) 100%);
}
/* Les grands titres calligraphies gardent leur halo, qui leur va bien. */
.wave__text h3, .wave__cap {
  text-shadow:
    0 0 3px rgba(255, 249, 250, .95),
    0 0 3px rgba(255, 249, 250, .95),
    0 0 10px rgba(255, 249, 250, .85),
    0 1px 2px rgba(139, 53, 85, .25);
}

/* ==========================================================================
   V12 — DEPLACEMENT HORIZONTAL des medaillons
   Le fondu est porte par l'element lui-meme (le masque est sur la photo, ou sur
   le cadre pour une video) : le deplacer emporte donc SON FONDU AVEC LUI, et on
   ne peut pas se retrouver avec l'image d'un cote et son fondu de l'autre.
   ========================================================================== */
.wm--main { transform: translateX(var(--dx, 0)); }
.wm--second { transform: translateX(var(--dx2, 0)); }
/* La petite photo peut passer a gauche au lieu de la droite. */
.wm--second--gauche { right: auto; left: -7%; }
@media (max-width: 760px) { .wm--second--gauche { left: 0; right: auto; } }
.wave__row--flip .wm--second--gauche { left: auto; right: -7%; }
@media (max-width: 760px) { .wave__row--flip .wm--second--gauche { right: 0; left: auto; } }

/* Reglages globaux des decors, pilotes depuis le panneau (Decor & animations).
   La taille et l'ecart sont appliques par une transformation : composee par la
   carte graphique, donc sans cout de mise en page. */
.section .deco, .closing .deco, .hero .deco {
  opacity: var(--deco-opacite, 1);
  transform: translate3d(calc(var(--deco-ecart, 0px) + var(--dx-deco, 0px)), var(--py, 0px), 0) scale(var(--deco-taille, 1)) scaleX(var(--miroir, 1));
}

/* ==========================================================================
   V13 — LOT 1 : iPhone, contenu central pousse vers la droite
   ------------------------------------------------------------------------
   Symptome rapporte : sur iPhone, la barre de boutons du bas s'affiche bien
   mais tout le reste est decale vers la droite, a l'accueil en premier.
   C'est cette dissymetrie qui a livre la cause : la barre du bas est en
   position FIXE, elle se cale sur l'ecran et ne depend donc pas de la largeur
   de la page. Le reste, lui, est dans le flux et se centre sur la LARGEUR DE
   LA PAGE. Si la page est plus large que l'ecran, tout ce qui est centre
   parait pousse a droite. Le probleme n'etait donc pas un centrage casse :
   c'etait une page trop large.

   Mon instrument etait faux jusqu'ici : je mesurais scrollWidth dans Chrome,
   qui tient compte des transformations CSS et annoncait 0 debordement. Or une
   transformation ne deplace que le RENDU, jamais la boite de mise en page, et
   Safari calcule la largeur de la page sur la boite de mise en page. Il fallait
   remonter la chaine offsetParent, insensible aux transformations. Deux causes
   sont apparues, chacune mesuree.

   1. .wave__media (corrige plus haut dans ce fichier, au media 760px) :
      "margin-left:50% + translateX(-50%)" posait la boite a un bord droit de
      581 px sur un ecran de 390. Chrome annulait ces 191 px grace a la
      transformation, Safari non. Remplace par un plein-ecran en marges seules.

   2. Le cartouche du hero, corrige ici. Il etait en display:inline-grid, donc
      sa largeur etait DEDUITE de son contenu, et ce contenu est en
      white-space:nowrap (deux pastilles sur une ligne, plus la citation de
      meme largeur). Marge restante mesuree : 22 px seulement a 390 px, et
      DEJA -10 px a 320 px. Il suffit que la police reelle de l'iPhone rende le
      texte un peu plus large que la police de secours de Chrome pour que ces
      22 px disparaissent, que le cartouche depasse, et que la page s'elargisse.

   Principe de la correction : la largeur du cartouche est desormais IMPOSEE
   (display:grid + width chiffree + marges auto), plus jamais deduite du
   contenu. Meme si un texte insecable se revelait un peu trop large sur un
   telephone particulier, la boite reste dans le conteneur : la page ne peut
   plus s'elargir, et rien ne se decale. On ajoute par-dessus une vraie marge
   en faisant varier taille de police et rembourrage avec la largeur d'ecran.
   ========================================================================== */

.hero__lead {
  display: grid;                    /* et non inline-grid : plus de largeur deduite du contenu */
  justify-items: stretch;
  gap: 10px;
  margin: 16px auto 0;              /* centrage par les marges, sans dependre de text-align */
  width: min(100%, 520px);          /* largeur imposee */
  max-width: 100%;
}
/* min-width:0 : sans lui, un element flex refuse de descendre sous la largeur
   minimale de son texte, et pousse donc son parent au lieu de se comprimer. */
.hero__lead .hero__meta { margin-top: 0; flex-wrap: nowrap; min-width: 0; gap: clamp(5px, 1.8vw, 9px); }
/* La citation doit faire exactement la longueur des DEUX pastilles reunies.
   Elle occupe deja toute la largeur du cadre ; ce sont les pastilles qui ne la
   remplissaient pas : a 390 px elles totalisaient 321 px dans un cadre de 362,
   centrees, donc 20 px de vide de chaque cote. flex-grow leur fait remplir la
   ligne. L'espace libre se partage a parts egales, ce qui elargit un peu le
   rembourrage de chacune sans toucher au texte ni changer leur ordre de
   grandeur relatif. La largeur du cadre reste imposee : c'est le cadre qui
   commande aux pastilles, jamais l'inverse. */
.hero__lead .pill {
  flex: 1 1 auto;
  justify-content: center;
  white-space: nowrap;
  min-width: 0;
  font-size: clamp(.62rem, 3.2vw, .88rem);
  padding: 9px clamp(7px, 2.6vw, 16px);
  letter-spacing: clamp(.01em, .12vw, .05em);
  gap: clamp(5px, 1.8vw, 9px);
}
.hero__lead .hero__quote {
  margin: 0; width: 100%; max-width: none; min-width: 0;
  white-space: nowrap; text-align: center;
  font-size: clamp(.78rem, 3.7vw, 1.28rem);
  padding: 8px clamp(10px, 3vw, 14px);
  letter-spacing: .005em;
}
/* L'ancienne regle a 370 px imposait une taille fixe et annulait les clamp
   ci-dessus sur les petits telephones, la ou la marge est la plus mince. */
@media (max-width: 370px) {
  .hero__lead .pill { padding: 9px clamp(7px, 2.6vw, 16px); font-size: clamp(.62rem, 3.2vw, .88rem); letter-spacing: .01em; }
}

/* Le bouquet du theme sortait de 11 px a droite (right:-3% sur 38vw de large).
   Sur iOS il n'etait retenu que par overflow:clip, absent avant Safari 16. */
@media (max-width: 760px) {
  .deco--bouquet { right: 0; }
}

/* Filet de securite pour les iPhone d'avant Safari 16, ou overflow:clip
   n'existe pas : tout le confinement du site repose dessus, et sans lui le
   moindre element trop large elargit la page. On ne le pose que sur la racine :
   la page reste le conteneur de defilement, donc les couches en position
   sticky (la derive des fonds) continuent de fonctionner normalement. */
@supports not (overflow-x: clip) {
  html, body { overflow-x: hidden; }
}

/* ==========================================================================
   V13 — LOT 2 : la photo du baiser retrouve son role de fond
   ------------------------------------------------------------------------
   Regression que j'avais introduite. Pour empecher le chemin dore (svg #trail,
   z-index 1 a la racine) de passer par-dessus les photos, j'avais ajoute
   .closing__media a une liste posant "position: relative; z-index: 2". Or cette
   photo est ancree par ses quatre cotes (site.css:383 inset, puis :1277 et :1279
   left/right/top/bottom et height:420px). Passee en relative, ces ancrages ne
   positionnent plus rien et elle entre dans le flux.

   Degats mesures : sur telephone elle prenait 420,00 px en tete de section, qui
   s'ajoutaient au padding-top de 300 px que .closing__text reserve justement
   pour la laisser passer EN SUPERPOSITION, d'ou 338,62 px de vide entre la photo
   et le premier mot, et un bloc RSVP decale de 331 px du centre de sa grille.
   Sur grand ecran, aucune regle ne donne de hauteur a un div vide en relative :
   hauteur 0,00 px, la photo du baiser ne rendait tout simplement AUCUN PIXEL.

   Correction : elle redevient absolue. Le probleme d'origine, le chemin dore qui
   la traversait, est resolu autrement : .closing ne cree pas de contexte
   d'empilement (isolation:auto, site.css:1377), donc ses enfants se comparent
   directement au trace. On remonte donc toute la famille au-dessus de lui EN
   CONSERVANT SON ORDRE INTERNE, sans quoi le voile sombre passerait derriere la
   photo et le texte blanc deviendrait illisible.
   ========================================================================== */
.closing__media { position: absolute; z-index: 2; }
.closing__veil  { z-index: 3; }
.closing .hearts { z-index: 4; }

/* Suite du lot 2. En rendant a la photo son role de fond, le texte de cloture
   s'est retrouve POSE DESSUS, alors qu'il tombait avant sur une zone unie. Le
   voile existant, un simple degrade horizontal a 25-45 % d'opacite, ne suffit
   plus. Mesure au pixel a 390 px, avant ce correctif :
     .closing__tag  mediane 1,58:1   20,5 % des pixels au-dessus de 4,5:1
     h2             mediane 3,51:1   41,5 %
     .closing__desc mediane 2,15:1    0,0 %  (meilleur pixel : 3,06)
   Le voile devient donc VERTICAL sur telephone : transparent en haut pour ne
   pas ternir le baiser, puis assombri a partir de 30 % de la section, la ou le
   premier mot commence (mesure : le .closing__tag debute a 28 % de la hauteur
   de section). La photo reste pleinement visible, le texte redevient lisible. */
@media (max-width: 760px) {
  .closing__veil {
    background: linear-gradient(180deg,
      rgba(60,14,32,.08) 0%,
      rgba(60,14,32,.20) 22%,
      rgba(52,12,28,.68) 38%,
      rgba(46,10,25,.84) 52%,
      rgba(46,10,25,.88) 100%);
  }
}

/* L'accroche de cloture reste le seul texte faible apres le renforcement du
   voile : mediane 3,19:1 et 16 % des pixels au-dessus de 4,5:1, contre 10,80 et
   82 % pour le titre, 9,19 et 75 % pour le paragraphe (mesure au pixel, chaque
   texte amene au centre de l'ecran et son apparition terminee).
   La cause est sa fonte : Great Vibes est une cursive tres fine, elle depose peu
   d'encre, donc peu de pixels atteignent leur pleine couleur. On ne peut pas
   assombrir davantage le voile sans ternir le baiser. On agit donc sur le texte
   lui-meme : une couleur plus claire, et surtout un halo sombre serre qui
   fonce le fond IMMEDIATEMENT autour de chaque delie. */
.closing__tag {
  color: #fdeaef;
  text-shadow:
    0 1px 2px rgba(30,6,16,.92),
    0 0 6px rgba(30,6,16,.85),
    0 2px 14px rgba(30,6,16,.75);
}

/* ==========================================================================
   V13 — LOT 3 : lisibilite et cadrages
   ========================================================================== */

/* --- 3.1 Les ornements n'etaient JAMAIS dessines ---------------------------
   Les six .flourish de la page portent deux courbes dorees en stroke-dasharray
   120 / stroke-dashoffset 120, c'est a dire entierement escamotees. La seule
   regle qui remet l'offset a 0 est ".reveal.is-visible .flourish__line", or
   AUCUN ancetre d'aucun flourish ne porte la classe reveal (verifie sur les six
   occurrences de index.html). Les courbes n'ont donc jamais ete visibles.
   Il ne restait que le coeur, mesure a 1,00:1 de contraste sur le fond du compte
   a rebours, soit invisible lui aussi. Resultat : un bloc de 39,59 px de haut,
   prouve en le supprimant, qui ne montrait rien et creusait un trou de 47,20 px
   entre le titre et le sous-titre, contre 30,22 et 28,00 px pour les intervalles
   suivants. On dessine les courbes. Cout : nul, c'est du SVG deja dans la page. */
.flourish__line { stroke-dashoffset: 0; }

/* --- 3.2 Section theme : centrage et ordre des blocs ----------------------- */
.theme__text { text-align: center; }
.theme__text .section-title { margin-left: auto; margin-right: auto; }
/* Le texte de presentation a quitte le bloc de titre pour passer sous la
   plaque : il reprend ici la typographie qu'il avait en tant que .section-title p. */
.theme__intro {
  margin: 22px auto 0;
  max-width: 620px;
  font-size: clamp(1.22rem, 1.7vw, 1.45rem);
  font-weight: 500;
  color: var(--deep);
}
.theme__note { margin-top: 14px; }

/* --- 3.3 La plaque de couleurs, plus epaisse ------------------------------- */
/* Aucune hauteur n'est imposee a .palette : elle decoule des pastilles, du gap
   et du padding. On epaissit donc par ces trois leviers. Mesure avant : 254,63 px
   de haut a 390 px. Aucune butee au-dessus ni en dessous, la suite se decale
   simplement dans le flux. */
.palette {
  padding: 30px 20px 26px;
  gap: 22px 10px;
  grid-auto-rows: 1fr;      /* rangees de hauteur egale : voir 3.4 */
}
.swatch i { width: clamp(72px, 8vw, 92px); }
/* A 320 px, "Rose poudre" demandait 91,23 px d'encre pour une colonne de 79,33 :
   il passait sur deux lignes et rendait la premiere rangee 24,32 px plus haute
   que la seconde. "Champagne" debordait en plus de 4,28 px de sa case. On reduit
   legerement le nom sur les petits ecrans, et grid-auto-rows:1fr ci-dessus egalise
   les deux rangees quoi qu'il arrive. */
.palette .swatch span { font-size: clamp(.8rem, 3.1vw, .95rem); line-height: 1.25; }

/* --- 3.4 L'affiche Save the Date, agrandie -------------------------------- */
/* Rendue a 260,63 px de large a 390 px pour un fichier de 933 px : la limite de
   nettete sur ecran a double densite est a 466 px, on en est loin. On passe le
   plafond de 72 % a 100 % du conteneur, soit x1,389, sans debordement possible
   puisque la largeur est celle du conteneur lui-meme. */
@media (max-width: 760px) {
  .theme__poster { max-width: 100%; margin: 0 auto; }
}

/* --- 3.5 Compte a rebours : le titre, agrandi ----------------------------- */
/* site.css:1055 fige .section-title h2 a 2,3rem de 320 a 760 px : aucune
   fluidite sur telephone. Marge mesuree avant passage a deux lignes : x1,159 a
   320 px (42,6 px maxi) et x1,436 a 390 px (52,9 px maxi). On reste sous ces
   plafonds, avec de la marge pour les metriques de police d'un vrai iPhone. */
.countdown .section-title h2 { font-size: clamp(2.45rem, 11.5vw, 3.4rem); }
/* L'encre du titre touchait deja l'ornement : 2,63 px a 320 et 390 px, et un
   CHEVAUCHEMENT de 1,38 px a 1440. En agrandissant le titre il faut donc ecarter
   l'ornement, sans quoi l'agrandissement rentre dedans. */
.countdown .flourish { margin-top: 16px; }

/* --- 3.6 Compte a rebours : le sous-titre ne glisse plus tout net ---------- */
/* [data-fx="fade"] anime opacity ET translateY(22px). Mais site.css:1333
   ".section-title--light p { opacity: .95 }" a une specificite superieure et
   gagne : le sous-titre restait donc PLEINEMENT VISIBLE pendant qu'il glissait
   de 22 px vers sa place. Il ne s'estompait pas, il se deplacait sous les yeux,
   d'ou l'impression de mal lire signalee. On lui rend son fondu. */
.section-title--light p[data-fx="fade"] { opacity: var(--p, 1); }

/* --- 3.7 Les decors ne doivent plus manger le texte ------------------------ */
/* Mesure : .deco--rings recouvrait 74,1 % de la case "jours" du chrono a 390 px,
   et le chiffre y tombait a 2,90:1 de contraste. On le descend sous la grille. */
@media (max-width: 760px) {
  .deco--rings { bottom: 6%; left: 2%; opacity: .55; }
}
/* A 1440, .deco--silk-top (z-index 2) passe AU-DESSUS du voile sombre pose sous
   le titre par .countdown .section-title::before (z-index -1) : 32,8 % des pixels
   du titre tombaient sous 4,5:1, le pire a 1,50:1. On remonte le bloc de titre
   au-dessus du ruban ; son ::before, enferme dans son propre contexte
   d'empilement, remonte avec lui et protege de nouveau le texte. */
.countdown .section-title { position: relative; z-index: 3; }

/* --- 3.8 La pastille de citation : plus epaisse et plus lisible ------------ */
/* Griefs mesures. Epaisseur : la citation est 2,29 a 3,12 px plus fine que la
   rangee des pastilles a 320-430 px (2 px de rembourrage en moins, 2 px de
   bordure absente), et surtout elle ne peint que sa hauteur + 2 px la ou les
   pastilles peignent + 18 px, faute d'ombre portee. Lisibilite : son texte a une
   mediane de 1,64 a 2,00:1 et seulement 7,3 a 9,5 % de pixels au-dessus de
   4,5:1, contre 29 a 48 % pour les pastilles, parce que Cormorant italique 400
   depose 8,22 px2 d'encre par caractere contre 28,44 px2 pour Manrope 700, soit
   3,46 fois moins. Optiquement la citation est 14 a 29 % PLUS PETITE que les
   pastilles malgre une taille nominale superieure de 16 %.
   Trois leviers, tous mesures comme tenant dans la place disponible :
   la graisse passe a 600 (le maximum : Cormorant Garamond n'existe PAS en
   italique 700, seules 400, 500 et 600 sont chargees, et Chrome ne fabrique pas
   de faux gras) ; passer de 400 a 600 ne coute que 1,4 % de largeur ; la taille
   remonte, en restant sous le plafond de x1,245 mesure a 320 px ; et on aligne
   le rembourrage, la bordure et l'ombre sur ceux des pastilles. */
.hero__lead .hero__quote {
  font-weight: 600;
  font-size: clamp(.92rem, 4.1vw, 1.34rem);
  padding: 9px clamp(10px, 3vw, 14px);
  border: 1px solid rgba(212,176,106,.45);
  box-shadow: 0 8px 22px rgba(110,40,65,.1);
  background: rgba(255,255,255,.82);
}

/* ==========================================================================
   V13 — LOT 4 : la decoration, sans alourdir
   ------------------------------------------------------------------------
   Quatre decors etaient servis en DEUX fichiers : l'original et une variante
   "-m". Verification faite avant de toucher a quoi que ce soit, en retournant
   l'original et en le comparant au fichier -m : ecart quadratique moyen de
   0,0070 a 0,0167, c'est a dire la MEME IMAGE, au bruit de recompression pres.
     corner-tl-m.webp      246 274 o
     bouquet-ribbon-m.webp 195 216 o
     lantern-m.webp        139 858 o
     silk-m.webp            24 118 o
                    TOTAL  605 466 o telecharges pour rien
   Ces quatre elements pointent desormais vers l'original et sont retournes par
   le CSS, ce qui ne coute rien. La variable --miroir est ajoutee a la
   transformation globale des decors plutot qu'en regle separee : une seconde
   declaration de transform ECRASERAIT la premiere, et les decors perdraient au
   passage leur parallaxe et leur reglage de taille. */
.deco--tr        { --miroir: -1; }
.deco--bl        { --miroir: -1; }
.deco--silk-top  { --miroir: -1; }
.deco--lantern-l { --miroir: -1; }

/* Placement des decors semes dans les zones qui n'en avaient aucun. Regle de
   conduite : discrets, en retrait sur les cotes, jamais derriere un texte, et
   opacite basse pour ne pas concurrencer les photos. Les positions en pourcentage
   sont relatives a la section, qui porte position:relative. */
/* Premier placement mesure : trois de ces decors mordaient sur du texte, de 4 a
   13 % de la surface d'un titre de carte ("Aux Seychelles", "Toi & Moi") ou d'un
   libelle du formulaire. Un decor discret ne doit RIEN recouvrir de lisible. On
   les repousse donc hors de la colonne de texte : ils depassent des bords de la
   section, qui les rogne, et n'apparaissent plus qu'en retrait. */
.deco--souv-1 { left: -9%;  top: 12%; width: clamp(64px, 12vw, 140px); opacity: .5; }
.deco--souv-2 { right: 0; --dx-deco: 22px; top: 36%; width: clamp(54px, 10vw, 110px); opacity: .45; }
.deco--souv-3 { left: -7%;  top: 58%; width: clamp(50px, 9vw, 100px);  opacity: .45; }
.deco--souv-4 { right: 0; --dx-deco: 20px; top: 82%; width: clamp(56px, 11vw, 120px); opacity: .4; }
.deco--fin-1  { left: -6%;  bottom: 24%; width: clamp(50px, 9vw, 100px);  opacity: .38; z-index: 5; }
.deco--fin-2  { right: 0; --dx-deco: 20px; bottom: 5%; width: clamp(56px, 11vw, 118px); opacity: .34; z-index: 5; }

/* Les decors de DROITE ne peuvent pas etre poses en right negatif : une valeur
   negative deplace la BOITE DE MISE EN PAGE hors de l'ecran, et c'est elle, pas
   le rendu, qui determine la largeur de la page sur Safari. C'est exactement ce
   qui decalait tout le contenu vers la droite sur iPhone. Mesure apres un premier
   essai en right:-5%/-6% : 19 px de debordement a 320 px et 23 px a 390.
   On les ancre donc a right:0 et on les decale VISUELLEMENT par --dx-deco, qui
   entre dans la transformation existante : une transformation ne deplace que le
   rendu, jamais la boite. Le decor deborde a l'oeil, la page ne s'elargit pas.
   --dx-deco est ajoute DANS la transformation globale et non en regle separee :
   une seconde declaration de transform ecraserait la premiere. */

/* ======================= V14 (conception Fable) ======================= */
/* ==========================================================================
   V14 - MONOGRAMME « MB » (remplace le texte M♥B)
   Le coeur U+2665 n'existe dans aucune des trois polices du site : il etait
   rendu par une police systeme, droit entre deux lettres italiques, et
   different sur chaque telephone (mesure : chasse identique a celle d'une
   police inexistante). Le monogramme est maintenant un SVG inline dont les
   lettres sont les contours exacts de Great Vibes (voir monogramme.html).
   Il ne depend plus des polices : sur 3G lent la police n'arrive qu'a 13,6 s,
   apres que le prechargeur s'est cache (9,7 s) ; l'ancien monogramme du
   prechargeur n'a donc JAMAIS ete vu dans la bonne police sur ces connexions.
   Le viewBox est 2.41 fois plus large que haut : on ne fixe que la hauteur, la
   largeur suit (aspect intrinseque du SVG).
   ========================================================================== */
/* aspect-ratio indispensable : le <svg> hote ne porte pas de viewBox, il n'a
   donc AUCUN rapport intrinseque, et width:auto retombe sur la taille par defaut
   d'un element remplace, soit 300 px. Mesure : boite de 300 x 44 px pour un
   dessin qui n'en occupe que 98, centre dedans. A 320 px la boite depassait le
   conteneur de 8 px (rattrape de justesse par overflow:hidden du pied de page).
   Le rapport est celui du viewBox du symbole : 2155 / 972. */
.mono { display: block; height: 1em; width: auto; aspect-ratio: 2155 / 972; overflow: visible; }
.mono__lettre { fill: currentColor; }
.mono__coeur  { fill: var(--gold); }

/* Prechargeur : fond clair, lettres prune (var(--primary), 5,9:1 sur #fbe7ec),
   coeur or. La respiration « breathe » existante reste sur .preloader__mark ;
   elle n'anime que transform, et le prechargeur disparait apres 4 s. */
.preloader__mark { font-size: clamp(56px, 14vw, 92px); color: var(--primary); line-height: 1; display: grid; place-items: center; }
.preloader__mark .mono { height: 1em; }

/* Pied de page : fond quasi noir, lettres blanches (17,7:1), coeur or clair
   (#efd9a4 : 12,3:1, l'or standard #d4b06a ne fait que 7,9:1 mais reste OK). */
.footer__mono { display: block; color: #fff; text-decoration: none; font-size: 44px; }
.footer__mono .mono { height: 1em; margin-inline: auto; }
.site-footer .mono__coeur { fill: var(--gold-light); }

/* Animations coupees ou reduites : le monogramme est statique de toute facon. */

/* ==========================================================================
   V14 - PIED DE PAGE (a AJOUTER en fin de site.css ; ces regles remplacent par
   la cascade celles de site.css:417-431, 524-525, 990, 1264, 1893 et 1911,
   qu'on peut ensuite supprimer).
   Etat mesure avant (fable3/MESURES.md, 320 et 390 px) : 380 px de haut plus
   88 px de bande rose pale sous le fond sombre ; « Myriam & Brice » a 1,42:1
   (prune sur presque noir, couleur heritee de l'ancien fond clair) ; date et
   lieu a 4,39:1 ; « L'amour reste… » a 2,35:1 ; six liens de 31,5 px de haut ;
   un bloc reseaux vide qui occupait une ligne ; huit espacements differents.
   Apres : tout en blanc ou or clair (>= 12:1 partout, mesure au pixel), deux
   valeurs d'espacement (4 px dans une paire, 16 px entre blocs), liens de
   44 px, plus de bande claire.
   ========================================================================== */

/* La reserve pour la barre du bas (88 px, site.css:1911) passe DANS le pied de
   page : la page se termine sur le fond sombre, plus sur une bande rose. */
body { padding-bottom: 0; }
.site-footer {
  position: relative; overflow: hidden; z-index: 2; margin-top: -2px;
  padding: 28px 0 calc(24px + 88px);
  background: linear-gradient(180deg, #2e0c1c 0%, #250819 100%); color: #fff;
  border-top: 0;
}
/* Le lisere dore du haut etait un border-top ecrase par margin-top:-2px (pixel
   mesure #6b4935) : il devient un pseudo-element, au-dessus de tout. */
.site-footer::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px; z-index: 2;
  background: linear-gradient(90deg, transparent, rgba(212, 176, 106, .9) 28%, rgba(212, 176, 106, .9) 72%, transparent);
}

.footer__inner { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 0; position: relative; z-index: 1; }

/* Monogramme : 44 px de haut, la piece centrale. Selecteur a deux classes :
   .site-footer a (site.css:991) impose un blanc a 85 % a tous les liens, ce
   qui teintait les lettres en rose pale (mesure rgb(231,212,...)). */
.site-footer .footer__mono { display: block; color: #fff; text-decoration: none; font-size: 44px; line-height: 1; margin: 0 0 16px; }
.footer__mono .mono { height: 1em; width: auto; margin-inline: auto; display: block; }
.site-footer .mono__coeur { fill: var(--gold-light); }

/* Noms en blanc, esperluette or clair. Great Vibes 27 px : 15:1 sur ce fond. */
.footer__names { margin: 0; font-family: var(--font-script); font-weight: 400; font-size: 1.75rem; line-height: 1.15; color: #fff; }
.footer__names em { font-style: normal; color: var(--gold-light); font-size: .82em; }

/* Date et lieu en blanc, corps Manrope, point or entre les deux. */
.footer__date { margin: 4px 0 0; font-family: var(--font-body); font-size: .92rem; letter-spacing: .03em; color: #fff; }
.footer__date i { display: inline-block; width: 4px; height: 4px; border-radius: 50%; background: var(--gold); margin: 0 10px; vertical-align: middle; }

/* Les trois phrases : liste editable, en Great Vibes or clair (#efd9a4, 12:1).
   Elles se placent cote a cote quand la largeur le permet (>= 400 px), sinon
   passent a la ligne, separees par un point or. */
.footer__amour {
  list-style: none; margin: 16px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center; gap: 0 22px;
  font-family: var(--font-script); font-weight: 400; font-size: 1.4rem; line-height: 1.35; color: var(--gold-light);
}
.footer__amour li { position: relative; white-space: nowrap; }
.footer__amour li + li::before { content: ""; position: absolute; left: -13px; top: 50%; width: 4px; height: 4px; margin-top: -2px; border-radius: 50%; background: rgba(212, 176, 106, .75); }

/* Navigation : chaque lien fait 44 px de haut (cible tactile), sans espace
   vertical entre les rangs (la hauteur du lien EST l'espacement). */
.footer__nav { margin: 16px 0 0; display: flex; flex-wrap: wrap; justify-content: center; gap: 0 4px; }
.footer__nav a { display: inline-flex; align-items: center; min-height: 44px; padding: 0 12px; border-radius: 8px; color: rgba(255, 246, 248, .92); font-size: .9rem; text-decoration: none; }
.footer__nav a:hover, .footer__nav a:focus-visible { color: var(--gold-light); background: rgba(255, 255, 255, .05); }
.footer__nav a.is-off { display: none; }

/* Reseaux : le bloc ne prend AUCUNE place tant qu'il est vide. */
.footer__socials { margin: 16px 0 0; display: flex; gap: 10px; }
.footer__socials:empty { display: none; }

/* Note : 10,6:1 mesure. */
.footer__note { margin: 16px 0 0; font-size: .86rem; color: rgba(255, 246, 248, .8); }

/* Decor : anneaux en haut a droite, rose attenuee en bas a gauche. Aucune
   animation. Les deux sont derriere le contenu (z-index 0 contre 1). */
.footer__anneaux { position: absolute; z-index: 0; right: 4%; top: 22px; width: 96px; height: auto; opacity: .85; pointer-events: none; }
.footer__rose { position: absolute; z-index: 0; left: -38px; bottom: 74px; width: 156px; height: auto; opacity: .28; pointer-events: none; }

/* Telephone : la feuille « Plus » de la barre du bas propose deja les memes
   liens (index.html:392-398). Sur petit ecran la navigation du pied de page est
   donc un doublon de 88 px : elle est masquee sous 760 px. Pour la garder,
   supprimer la ligne .footer__nav ci-dessous : elle tient alors en 2 rangs de
   44 px (mesure 320 px : 88 px de plus). */
@media (max-width: 760px) {
  .site-footer { padding-top: 26px; }
  .footer__nav { display: none; }
  .footer__anneaux { width: 82px; right: 3%; top: 16px; }
  /* La rose descend sous la note (a 320 px elle passait sous « L'amour reste… »). */
  .footer__rose { width: 124px; left: -30px; bottom: 44px; }
}

/* ======================= V14 LOTS A et B (conception Fable) =======================
   Le lot C propose par Fable, qui SUPPRIME le miroitement de Save, Date et &,
   n est volontairement PAS applique : l utilisateur a demande PLUS d animation,
   pas moins, et ne s est jamais plaint de ce reflet. Fable le mesure a -40 % de
   peinture et -5,5 % de fil principal : si la fluidite se degrade, il est pret a
   etre pose (fable3/animations.css, bloc LOT C). */
/* ==========================================================================
   V14 - LOT A : RECUPERATION DES ANIMATIONS QUI TOURNENT HORS ECRAN
   Releve nominatif (fable3/anims-horsecran.mjs, 390 px, en haut de page) :
   52 animations en marche, dont 7 sur des elements qui ne sont PAS dans la
   fenetre et que la pause is-offscreen ne couvrait pas : silk-flow (ruban de
   soie sous le hero), bg-zoom du fond de cloture, 4 twinkle des etincelles du
   compte a rebours, et le defilement du bandeau (#ribbon n'etait pas observe).
   Les 28 petales et 6 coeurs restants sont des couches FIXES visibles : ils ne
   sont pas « hors ecran », on ne les touche pas ici.
   La liste is-offscreen de site.css:1535 ne nommait que 13 selecteurs : on
   couvre maintenant TOUT ce qui porte une animation infinie dans une section.
   ========================================================================== */
.is-offscreen .sparkles i,
.is-offscreen .silk img,
.is-offscreen .hero__bg,
.is-offscreen .section-bg,
.is-offscreen .countdown__bg,
.is-offscreen .closing__media,
.is-offscreen .title__word,
.is-offscreen .title__script,
.is-offscreen .eyebrow,
.is-offscreen .hw,
.is-offscreen .names::before,
.is-offscreen .arch,
.is-offscreen .poster,
.is-offscreen .scene__sun,
.is-offscreen .after__hearts,
.is-offscreen .cluster img,
.is-offscreen .wave__over,
.is-offscreen .wave__bg--a,
.is-offscreen .wave__bg--b,
.is-offscreen .river__over,
.is-offscreen .deco--envelope-form,
.is-offscreen .ucard__heart,
.is-offscreen .ribbon__item i,
.is-offscreen .btn--shine::after { animation-play-state: paused !important; }

/* ==========================================================================
   V14 - LOT B : L'ACCUEIL RESTE VIVANT
   Demande : « Myriam & Brice doit toujours etre anime, les lettres bougent, les
   mots bougent, les prenoms echangent leur place, des messages d'amour tournent
   puis ca revient a Myriam & Brice ; Nous nous disons oui pareil. »
   Contrainte : la fluidite prime. Mesures dans fable3/MESURES.md. Regle
   suivie : TOUT ce qui tourne en permanence n'anime que transform et opacity,
   proprietes composees par le processeur graphique (trace Chrome : 33
   animations composees, aucune refusee sauf le background-position du &).
   La lueur names-lueur (filter anime) est remplacee par un halo en opacite :
   mesure neutre a l'image pres, mais elle interdisait de faire bouger les
   lettres a l'interieur du paragraphe filtre sans le re-rasteriser.
   1. les lettres (span.hw, deja crees par heroSplit) ondulent en transform ;
   2. les prenoms glissent en transform, d'une distance mesuree une fois en JS
      (--dx-her, --dx-him) : la ligne garde exactement la meme largeur, donc
      AUCUN saut de mise en page ;
   3. le halo dore derriere les noms est un pseudo-element dont on anime
      l'opacite, a la place du filter ;
   4. les messages arrivent par l'ecriture deja existante (hero-write), qui
      est transitoire : rien de permanent ne s'ajoute.
   ========================================================================== */

/* Une ligne, toujours : une phrase qui passerait sur deux lignes chevaucherait
   le titre (line-height .86). Si une phrase depasse, le JS reduit sa taille. */
.hero__text .names, .hero__text .eyebrow { white-space: nowrap; }
.hero__text .names { position: relative; }

/* 1. Fin de la lueur par filter (site.css:2145-2153). L'entree hero-in est
      conservee telle quelle ; l'or fixe passe dans le text-shadow (gratuit). */
.hero__text .names {
  animation: hero-in .9s cubic-bezier(.2, .8, .2, 1) both;
  text-shadow: 0 8px 26px rgba(139, 53, 85, .18), 0 0 16px rgba(212, 176, 106, .38);
}
.hero__text .names::before {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  left: 8%; right: 8%; top: -28%; bottom: -28%; border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(212, 176, 106, .32), rgba(212, 176, 106, 0) 66%);
  opacity: .3; animation: names-halo calc(5.5s * var(--speed)) ease-in-out infinite;
}
@keyframes names-halo {
  0%, 100% { opacity: .22; transform: scale(.94); }
  50%      { opacity: .85; transform: scale(1.06); }
}

/* 2. Les lettres ondulent. Delais POSITIFS : chaque lettre part du repos, la
      vague se propage de gauche a droite sans saut au demarrage ni apres une
      ecriture (un delai negatif ferait apparaitre la lettre deja decalee). */
.is-vivant .hw {
  animation: lettre-vague calc(3.4s * var(--speed)) ease-in-out infinite;
  animation-delay: calc(var(--i, 0) * .12s);
}
@keyframes lettre-vague {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  32%      { transform: translateY(-.075em) rotate(1.8deg); }
  64%      { transform: translateY(.025em) rotate(-.9deg); }
}
/* « Nous nous disons oui » : meme famille, mais le paragraphe ENTIER flotte,
   pas ses lettres. Mesure (fable3/MESURES.md, x6, 3 tours) : lettres des noms
   seules -1 image/s, lettres du sourcil seules -1 image/s, les DEUX ensemble
   -5 images/s (29 couches composees d'un coup) ; le flottement entier du
   sourcil ne coute rien de mesurable. hero-in est fini depuis longtemps quand
   cette classe est posee (heroVivant part apres l'ecriture, > 2,5 s) : on
   garde hero-in dans la liste pour conserver son opacite finale, et le
   flottement reprend transform a partir du repos, sans saut. */
.eyebrow.is-vivant {
  animation: hero-in .9s cubic-bezier(.2, .8, .2, 1) both, sourcil-flotte calc(4.6s * var(--speed)) ease-in-out infinite;
}
@keyframes sourcil-flotte {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(-4px) rotate(-.6deg); }
}

/* 3. L'echange des prenoms. Chaque prenom est une boite en ligne qui glisse de
      la distance mesuree par heroVivantMesure(), en arc (l'un passe au-dessus
      du « & », l'autre en dessous) pour ne pas se croiser dessus. Aucune
      propriete de mise en page n'est touchee. */
.names [data-bind="general.her"], .names [data-bind="general.him"], .names em { display: inline-block; }
/* Le « & » glisse aussi, en ligne droite, de la difference des largeurs des deux
   prenoms (Myriam est plus large que Brice de ~48 px a 390) : sans cela, dans
   l'etat echange, le prenom large recouvre l'esperluette (constate en capture). */
.names.is-echange em { animation: echange-amp calc(1.1s * var(--speed)) cubic-bezier(.65, 0, .3, 1) forwards; }
.names.is-retour  em { animation: echange-amp-retour calc(1.1s * var(--speed)) cubic-bezier(.65, 0, .3, 1) forwards; }
@keyframes echange-amp        { from { transform: translateX(0); } to { transform: translateX(var(--dx-amp, 0px)); } }
@keyframes echange-amp-retour { from { transform: translateX(var(--dx-amp, 0px)); } to { transform: translateX(0); } }
.names.is-echange [data-bind="general.her"] { --dx: var(--dx-her, 0px); --arc: -.3em; animation: echange-aller calc(1.1s * var(--speed)) cubic-bezier(.65, 0, .3, 1) forwards; }
.names.is-echange [data-bind="general.him"] { --dx: var(--dx-him, 0px); --arc: .22em; animation: echange-aller calc(1.1s * var(--speed)) cubic-bezier(.65, 0, .3, 1) forwards; }
.names.is-retour  [data-bind="general.her"] { --dx: var(--dx-her, 0px); --arc: .22em; animation: echange-retour calc(1.1s * var(--speed)) cubic-bezier(.65, 0, .3, 1) forwards; }
.names.is-retour  [data-bind="general.him"] { --dx: var(--dx-him, 0px); --arc: -.3em; animation: echange-retour calc(1.1s * var(--speed)) cubic-bezier(.65, 0, .3, 1) forwards; }
@keyframes echange-aller {
  from { transform: translate(0, 0); }
  50%  { transform: translate(calc(var(--dx) * .5), var(--arc)); }
  to   { transform: translate(var(--dx), 0); }
}
@keyframes echange-retour {
  from { transform: translate(var(--dx), 0); }
  50%  { transform: translate(calc(var(--dx) * .5), var(--arc)); }
  to   { transform: translate(0, 0); }
}

/* 4. Changement de texte : les lettres s'effacent (300 ms), puis le nouveau
      texte s'ecrit avec hero-write (site.css:1453). hero-in tient l'opacite du
      paragraphe a 1 (fill both) : on fait donc sortir les LETTRES, pas le
      paragraphe. Specificite (0,3,0) pour passer devant .is-vivant .hw. */
.is-vivant.is-sortie .hw { animation: lettre-sortie .3s ease-in forwards; animation-delay: calc(var(--i, 0) * 12ms); }
@keyframes lettre-sortie { to { opacity: 0; transform: translateY(.35em); } }
.is-vivant.is-writing .hw {
  opacity: 0;
  animation: hero-write .52s cubic-bezier(.2, .8, .2, 1) forwards;
  animation-delay: calc(var(--i, 0) * 68ms + 260ms);
}

/* Le hero n'est plus a l'ecran : tout s'arrete (le JS suspend aussi la rotation). */
.is-offscreen .names [data-bind] { animation-play-state: paused !important; }

/* Animations coupees (panneau, ou « reduire les animations ») : le JS n'installe
   rien ; ces regles sont le filet si l'attribut change apres coup. */
html[data-anim="off"] .hw, html[data-anim="off"] .names::before, html[data-anim="off"] .names [data-bind], html[data-anim="off"] .names em, html[data-anim="off"] .eyebrow.is-vivant { animation: none !important; opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .hw, .names::before, .names [data-bind], .names em, .eyebrow.is-vivant { animation: none !important; opacity: 1; transform: none; }
}

/* ==========================================================================
   V14 — LOT 5 : le bandeau defilant traverse enfin l'ecran
   ------------------------------------------------------------------------
   Signale : « on a l'impression que c'est une barre rectangulaire, on voit les
   contours dans les angles de l'ecran ; normalement ca doit traverser ».
   Mesure a 390 px : le bandeau occupe bien toute la largeur (0 a 390), mais il
   porte transform: rotate(-1.1deg) et border-radius: 6px. Une barre inclinee ne
   peut PAS joindre les deux bords d'un rectangle : a chaque extremite elle
   laisse un triangle de fond haut de (largeur / 2) x sin(1,1 deg), soit 3,7 px
   sur un ecran de 390 et 8,1 px en paysage a 844. Les coins arrondis de 6 px
   s'y ajoutent. C'est exactement ce qui se lit comme « des contours dans les
   angles », et c'est pire en paysage, ou la barre est plus large.
   On redresse donc la barre et on supprime l'arrondi : elle traverse l'ecran
   d'un bord a l'autre, sans aucun angle visible. L'inclinaison etait un parti
   pris graphique ; si elle manque, il faudra la retablir AVEC un debordement
   lateral suffisant pour que les triangles sortent de l'ecran, pas sans.
   ========================================================================== */
.ribbon {
  transform: none;
  border-radius: 0;
  margin: 0;
}
@media (min-width: 761px) { .ribbon { transform: none; } }

/* ==========================================================================
   V14 — LOT 6 : des coeurs enfin visibles, et identiques sur tous les appareils
   ------------------------------------------------------------------------
   Deux defauts cumules. Le nombre : 6 coeurs seulement traversaient toute la
   page sur telephone (porte a 16, voir js/app.js). Et le dessin : c'etait le
   caractere U+2665, absent des trois polices du site, donc rendu par la police
   systeme de chaque appareil, avec le risque d'un emoji couleur sur iPhone qui
   ignore la couleur demandee. Le coeur est desormais dessine par le CSS, a
   partir du meme trace que la barre du bas : identique partout, zero octet.
   On n'anime que transform et opacity, les deux seules proprietes que le
   navigateur compose sur le processeur graphique : le cout reste faible malgre
   le nombre, ce qui est verifiable au bridage x6.
   ========================================================================== */
.hearts i {
  width: var(--fs, 18px);
  height: var(--fs, 18px);
  font-size: 0;                     /* plus aucun texte a rendre */
  background-color: rgba(255, 196, 214, .72);
  -webkit-mask-image: var(--coeur); mask-image: var(--coeur);
  -webkit-mask-repeat: no-repeat;   mask-repeat: no-repeat;
  -webkit-mask-size: 100% 100%;     mask-size: 100% 100%;
  filter: drop-shadow(0 0 7px rgba(255, 170, 200, .75));
  text-shadow: none;
}
:root {
  --coeur: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 21s-7.5-4.6-9.5-9.1C.9 8.2 3.3 4.5 7 4.5c2 0 3.6 1.1 5 2.8 1.4-1.7 3-2.8 5-2.8 3.7 0 6.1 3.7 4.5 7.4C19.5 16.4 12 21 12 21z'/%3E%3C/svg%3E");
}
/* Les coeurs de la cloture sont sur un fond sombre : on les eclaircit un peu. */
.closing .hearts i { background-color: rgba(255, 214, 226, .8); }
