/* =============================================================================
   Liora & Joshua — 11 novembre 2026
   Design system : burgundy · olivine · rose poudré · crème
   Mobile-first. Aucune dépendance.
   ========================================================================== */

/* --- 1. Tokens ----------------------------------------------------------- */
:root {
  /* la marge qui fait voir le contour de l'enveloppe fermée */
  --env-marge: clamp(10px, 3vw, 22px);
  /* Rotation de teinte du velours, posée par app.js quand les mariés
     choisissent une couleur. `none` = le bordeaux d'origine, image intacte. */
  /* Le velours photographié pivote du bordeaux d'origine vers le vert sauge.
     app.js recalcule ce delta si les mariés changent la couleur dans le carnet. */
  --teinte: hue-rotate(122deg);
  /* Vert sauge — décliné du #B1CDAB du faire-part papier. Les jetons gardent
     leur nom « wine » : ils désignent le rôle (fond profond, encre d'accent),
     pas la couleur, et deux cents règles s'y réfèrent. */
  --wine-900: #16220F;
  --wine-800: #22331A;
  --wine-700: #2E4423;
  --wine-600: #3E5931;
  --wine-500: #4E6C40;
  --wine-ground: #3E5931;
  --wine-ground-2: #4F6C41;
  --sage-300: #B1CDAB;   /* le vert du faire-part, en touches seulement */

  /* Rose poudré (mood board) */
  --rose-500: #B08A88;
  --rose-400: #BF9D9B;
  --rose-300: #D8BEBA;
  --rose-200: #EEDFDB;

  /* Olivine (Pantone 18-0316) */
  --olive-700: #43442F;
  --olive-600: #57573D;
  --olive-500: #676849;
  --olive-300: #9B9C80;

  /* Crème & sable */
  --cream-050: #FDFBF7;
  --cream-100: #FAF5EE;
  --cream-200: #F3ECE1;
  --cream-300: #E7DCCB;
  --sand-500:  #B79C77;
  --sand-400:  #C8B296;
  --sand-300:  #DBC9B2;

  --ink:       #1C221A;
  --ink-soft:  #4A5245;

  /* Sémantique */
  --bg:            var(--cream-100);
  --surface:       var(--cream-050);
  --fg:            var(--ink);
  --fg-soft:       var(--ink-soft);
  --accent:        var(--wine-700);
  --accent-quiet:  var(--wine-500);
  /* Olivine du mood board : c'est elle qui porte les capitales et les labels.
     L'or n'existe que dans les filets. */
  --ink-label:     var(--olive-600);
  --lace:          #FCF9F4;
  --ink-label-on-wine: #B7B89A;
  --rule-ink:      #8A6A45;
  --rule:          rgba(71, 18, 36, 0.16);
  --rule-soft:     rgba(71, 18, 36, 0.08);

  /* Typographie */
  --display: "Cormorant Garamond", "Times New Roman", serif;
  --title:   "Cormorant Garamond", serif;
  --label:   "Marcellus", "Cormorant Garamond", serif;
  --hebrew:  "Frank Ruhl Libre", "Cormorant Garamond", serif;
  --hebrew-ui: "Assistant", "Frank Ruhl Libre", sans-serif;

  /* Rayons : deux valeurs, pas cinq */
  --r-paper: 3px;   /* tout ce qui simule du papier */
  --r-pill: 999px;  /* les seules commandes flottantes */

  /* Rythme — échelle 4/8 */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px; --s-5: 24px;
  --s-6: 32px; --s-7: 48px; --s-8: 64px; --s-9: 96px;
  --section-y: clamp(56px, 13vw, 112px);
  --gutter: clamp(18px, 5vw, 40px);
  --measure: 30rem;

  /* Motion */
  --e-out: cubic-bezier(0.22, 1, 0.36, 1);
  --e-in:  cubic-bezier(0.55, 0, 0.68, 0.28);
  --e-soft: cubic-bezier(0.4, 0, 0.2, 1);
  --t-fast: 180ms;
  --t-base: 260ms;
  --t-slow: 460ms;

  /* Élévation */
  --lift-1: 0 1px 2px rgba(36, 20, 25, 0.05), 0 6px 18px -12px rgba(36, 20, 25, 0.28);
  --lift-2: 0 2px 6px rgba(36, 20, 25, 0.06), 0 24px 48px -28px rgba(36, 20, 25, 0.38);
  --lift-3: 0 40px 90px -50px rgba(36, 20, 25, 0.55);

  /* Couches */
  --z-nav: 60;
  --z-envelope: 100;

  /* Taille du sceau de cire — partagée par le sceau de l'enveloppe et celui
     du collage : ils doivent se superposer au pixel près au raccord. */
  --seal-w: clamp(80px, 22vw, 104px);

  --navbar-h: 72px;
}

/* --- 2. Base ------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: var(--s-6);
}

body {
  margin: 0;
  min-height: 100svh;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--display);
  font-size: 17px;
  line-height: 1.7;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* Grain de papier — un seul calque, en fixed, sans coût de peinture au scroll */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.5;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.055'/%3E%3C/svg%3E");
}

body.is-locked { overflow: hidden; }

img { display: block; max-width: 100%; height: auto; }

a { color: inherit; text-decoration: none; }

button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

::selection { background: var(--rose-300); color: var(--wine-800); }

:focus-visible {
  outline: 2px solid var(--wine-600);
  outline-offset: 3px;
  border-radius: 2px;
}
/* La barre basse donne le focus à la section atteinte — nécessaire aux
   lecteurs d'écran — mais Safari dessine alors l'anneau même au clic souris,
   et un panneau entier encadré de vert n'aide personne. Le focus reste, son
   anneau disparaît sur ces cibles de défilement uniquement. (La règle dédiée
   de `.counters`, plus bas dans la feuille, reprend la main pour le clavier.) */
[tabindex="-1"]:focus,
[tabindex="-1"]:focus-visible { outline: none; }

[hidden] { display: none !important; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --- 3. Direction hébraïque ---------------------------------------------- */
/* Toute la palette typographique bascule d'un bloc : aucun texte hébreu
   ne peut se retrouver dans une police latine. */
body[data-lang="he"] {
  --display: "Frank Ruhl Libre", "Cormorant Garamond", serif;
  --title:   "Frank Ruhl Libre", serif;
  --label:   "Assistant", "Frank Ruhl Libre", sans-serif;
  line-height: 1.85;
}
/* L'hébreu n'a ni capitales ni interlettrage décoratif */
body[data-lang="he"] .kicker,
body[data-lang="he"] .hero-overline,
body[data-lang="he"] .env-to,
body[data-lang="he"] .env-date,
body[data-lang="he"] .btn,
body[data-lang="he"] .nav-label,
body[data-lang="he"] .field-label,
body[data-lang="he"] .event-badge,
body[data-lang="he"] .fp-hebrew-date,
body[data-lang="he"] .footer-date,
body[data-lang="he"] .env-skip {
  letter-spacing: 0.04em;
  text-transform: none;
}
/* Marcellus n'a pas d'hébreu : les libellés en petites capitales basculent
   sur la face d'interface hébraïque plutôt que sur un repli latin disloqué. */
body[data-lang="he"] .event-badge,
body[data-lang="he"] .fp-hebrew-date { font-family: var(--hebrew-ui); }
body[data-lang="he"] .kicker,
body[data-lang="he"] .hero-overline { font-size: 12.5px; }
body[data-lang="he"] .btn { font-size: 13px; }
body[data-lang="he"] .nav-label { font-size: 12px; }
body[data-lang="he"] .field-label { font-size: 12px; }
body[data-lang="he"] .promo-code { letter-spacing: 0.3em; }
/* le verset et la mention בס״ד restent en RTL même en version française */
.verse, .hero-bsd { direction: rtl; unicode-bidi: isolate; }

/* --- 4. Typographie ------------------------------------------------------ */
/* Cormorant a des chiffres elzéviriens : superbes dans le texte courant,
   illisibles dans une ligne de capitales (« 2o26 ») ou dans un compteur. */
.hero-overline, .env-date, .env-to, .footer-date, .promo-code, .kicker,
.meta-when, .meta-hour, .meta-place, .meta-address, .fp-date, .fp-hebrew-date,
.input, .counter-sub, .counter-title, .event-hebrew-date,
.event-badge, .hotel-sub, .btn {
  font-variant-numeric: lining-nums;
}

/* Pas de veuve, pas d'orpheline */
.section-title, .event-title, .hero-names, .footer-mazal, .env-names,
.event-badge, .kicker, .hotel-district { text-wrap: balance; }
.lede, .p, .memory, .meta-place, .meta-hour, .promo-help, .event-note, .counter-sub { text-wrap: pretty; }
.meta-when, .fp-date { text-wrap: balance; }
.kicker {
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--ink-label);
  margin: 0 0 var(--s-4);
  display: block;
}
.section--wine .kicker { color: var(--ink-label-on-wine); }

.section-title {
  font-family: var(--display);
  font-weight: 300;
  font-size: clamp(30px, 8.5vw, 46px);
  line-height: 1.15;
  letter-spacing: -0.005em;
  margin: 0 0 var(--s-5);
  color: var(--wine-700);
}
.section-title em { font-style: italic; color: var(--wine-600); }
.section--wine .section-title { color: var(--cream-100); }
.section--wine .section-title em { color: var(--rose-300); }

.lede {
  font-size: 18px;
  line-height: 1.78;
  color: var(--fg-soft);
  max-width: var(--measure);
  margin: 0 auto var(--s-5);
}

.p { max-width: var(--measure); margin: 0 auto var(--s-4); }

/* --- 5. Ornements -------------------------------------------------------- */
.rule--rose { max-width: 186px; height: 24px; }
.rule--olive { max-width: 190px; height: 21px; color: var(--olive-600); }
.section--wine .rule--olive { color: var(--ink-label-on-wine); }
.rule {
  display: block;
  width: 100%;
  max-width: 152px;
  margin: var(--s-5) auto;
  height: 9px;
  color: var(--rule-ink);
  opacity: 1;
}
.section--wine .rule { color: var(--rose-400); opacity: 1; }

/* --- 6. Sections --------------------------------------------------------- */
.section {
  position: relative;
  z-index: 1;
  padding: var(--section-y) var(--gutter);
  text-align: center;
}
.section-inner { max-width: 660px; margin: 0 auto; }

.section--wine {
  background: var(--wine-ground);
  color: var(--cream-200);
}
.section--wine .p { color: var(--cream-300); }
.section--wine .lede,
.section--wine .p,
.section--wine .memory { font-weight: 400; letter-spacing: 0.006em; }
.section--wine .verse { color: var(--cream-100); }
.section--wine .lede,
.section--wine .p { color: var(--rose-200); }

.section--cream2 { background: var(--cream-200); }

/* --- 7. Boutons ---------------------------------------------------------- */
.btn {
  --btn-fg: var(--cream-050);
  --btn-bg: var(--wine-700);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 48px;
  padding: 13px 26px;
  font-family: var(--label);
  font-size: 12px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--btn-fg);
  background: var(--btn-bg);
  border: 1px solid var(--btn-bg);
  border-radius: 2px;
  transition: background var(--t-base) var(--e-soft),
              color var(--t-base) var(--e-soft),
              border-color var(--t-base) var(--e-soft),
              transform var(--t-fast) var(--e-out);
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.btn:active { transform: scale(0.975); }

.btn--ghost {
  --btn-fg: var(--wine-700);
  --btn-bg: transparent;
  border-color: var(--rule);
}
.btn--ghost:hover { border-color: var(--wine-600); background: rgba(71, 18, 36, 0.04); }

.btn--onwine {
  --btn-fg: var(--wine-800);
  --btn-bg: var(--cream-200);
  border-color: var(--cream-200);
}
.btn--block { width: 100%; }

.btn svg { width: 16px; height: 16px; flex: none; }

/* --- 8. Enveloppe velours (écran d'ouverture) ----------------------------- */
/* Reproduction du modèle : rabat de velours bordeaux ourlé de dentelle en V,
   sceau de cire ovale posé à la pointe. Géométrie : les branches du V partent
   des bords à --v-edge et se rejoignent à --v-tip. --seal-rest est la position
   finale du sceau, identique à celle du sceau du collage (héros) dessous. */
.envelope-screen {
  --v-edge: 36%;
  --v-tip: 57%;
  /* Le sceau tombe du V (57 dvh) jusqu'au sceau du collage, dont le centre est
     à 64 dvh + 36 % × 36 dvh = 76,96 dvh. Les deux sceaux ont exactement la
     même taille (--seal-w) et la même inclinaison : le raccord est invisible,
     sans le moindre fondu pour le masquer. */
  --seal-travel: 19.96svh;
  position: fixed;
  inset: 0;
  z-index: var(--z-envelope);
  overflow: hidden;
  perspective: 1400px;
  /* Le fond sombre déborde de l'enveloppe : c'est lui qui donne à voir son
     contour. Il s'efface avec l'écran à l'ouverture. */
  background: var(--wine-900);
  transition: opacity 260ms linear, visibility 260ms, background-color 350ms linear;
}
/* Dès l'ouverture, le cadre sombre s'efface : les papiers du collage doivent
   apparaître dans les marges à mesure que la poche recule — c'est tout le
   théâtre du déballage. Fermée, l'enveloppe garde son contour. */
.envelope-screen.is-open,
.envelope-screen.is-arming { background-color: transparent; }
.envelope-screen.is-open { transition-delay: 1500ms, 1500ms; opacity: 0; }
.envelope-screen.is-gone { opacity: 0; visibility: hidden; pointer-events: none; }

/* La poche : velours sombre, pli en V inversé discret vers le bas */
.env-pocket {
  position: absolute;
  inset: var(--env-marge);
  border-radius: 10px;
  overflow: hidden;
  box-shadow: 0 10px 40px -18px rgba(0, 0, 0, 0.55);
  /* Aplat de repli, raccordé à la première ligne de velvet-pocket.webp : il ne
     se voit que dans la zone située au-dessus du cadrage de l'image, pendant
     les ~300 ms où le rabat a déjà basculé et où la poche n'a pas encore
     reculé. Le velours y entre en fondu (::before) au lieu d'être coupé net. */
  background: #561A28;
  /* fermé : la poche couvre tout l'écran ; à l'ouverture elle recule vers le
     bas jusqu'à la géométrie exacte de la poche du collage, et les papiers
     semblent sortir de l'enveloppe. */
  clip-path: polygon(0 0, 50% 0, 100% 0, 100% 100%, 0 100%);
  /* départ retenu : la poche ne doit pas « fuir » sous les papiers, sinon
     l'œil comprend le truquage — elle s'ouvre en même temps qu'ils montent */
  transition: clip-path 620ms cubic-bezier(0.52, 0.03, 0.3, 1);
  /* l'aplat de repli et l'image de velours suivent la teinte d'un seul bloc */
  filter: var(--teinte);
}
/* MÊME CADRAGE que .clg-pocket (le collage, dessous) : la poche du collage
   est un rectangle 100vw × 36svh où velvet-pocket.webp (736×1312, ratio
   0,561) est posé en `cover`, donc redimensionné à 100vw × 100vw/0,561 et
   centré. On reproduit ici exactement ce cadrage, ancré sur le même centre
   (82 dvh = milieu du bandeau bas), pour que la trame du velours ne « nage »
   pas au moment du relais enveloppe → collage.
   L'image vit sur une couche à part pour porter son propre masque : son bord
   haut, sinon, traçait un trait horizontal franc en travers de l'écran. */
.env-pocket::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("../img/velvet-pocket.webp");
  background-repeat: no-repeat;
  background-size: 100vw 178.253vw;
  background-position: center calc(82svh - 89.127vw);
  -webkit-mask-image: linear-gradient(180deg, transparent calc(82svh - 89.127vw),
                      #000 calc(82svh - 89.127vw + 150px));
  mask-image: linear-gradient(180deg, transparent calc(82svh - 89.127vw),
              #000 calc(82svh - 89.127vw + 150px));
}
.envelope-screen.is-open .env-pocket {
  /* géométrie finale = exactement celle de la poche du collage, dessous */
  clip-path: polygon(0 64%, 50% 68.3%, 100% 64%, 100% 100%, 0 100%);
  /* Retenue jusqu'à 600 ms : avant cela, le rabat rétréci par la perspective
     ne couvre plus toute la largeur et la rétraction découvrirait deux
     encoches de fond crème dans les coins hauts. */
  transition-delay: 600ms;
}
.env-pocket::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(64deg,  rgba(20, 4, 10, 0.30) 0%, rgba(20, 4, 10, 0) 34%),
    linear-gradient(-64deg, rgba(20, 4, 10, 0.30) 0%, rgba(20, 4, 10, 0) 34%),
    linear-gradient(0deg,   rgba(20, 4, 10, 0.34) 0%, rgba(20, 4, 10, 0) 26%);
}
/* L'ombre que le rabat projette sur la poche pendant qu'il se lève : elle
   balaie vers le bas puis se dissipe. Sans elle, le rabat a l'air d'un
   aplat qui pivote dans le vide. */
.env-pocket::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0;
  background: linear-gradient(180deg,
    rgba(12, 2, 6, 0.62) 0%, rgba(12, 2, 6, 0.38) 42%, rgba(12, 2, 6, 0) 78%);
  transform-origin: top center;
}
.envelope-screen.is-open .env-pocket::after { animation: env-cast 1150ms linear forwards; }
@keyframes env-cast {
  0%   { opacity: 0;    transform: scaleY(0.32); }
  22%  { opacity: 0.85; transform: scaleY(0.52); }
  58%  { opacity: 0.55; transform: scaleY(0.86); }
  100% { opacity: 0;    transform: scaleY(1.08); }
}
/* vignettage général de l'écran fermé */
.envelope-screen::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  background: radial-gradient(120% 90% at 50% 42%, rgba(0,0,0,0) 55%, rgba(16, 3, 8, 0.38) 100%);
  transition: opacity 420ms var(--e-soft);
}
.envelope-screen.is-open::after { opacity: 0; }

/* Le rabat : velours plus clair, lumière rasante, pointe en V */
.env-flap {
  position: absolute;
  inset: var(--env-marge) var(--env-marge) auto var(--env-marge);
  /* la pointe du V reste au même endroit de l'écran : on retranche la marge */
  height: calc(var(--v-tip) - var(--env-marge));
  border-radius: 10px 10px 0 0;
  /* PAS d'overflow:hidden : la dentelle doit déborder du cadre, comme un
     ourlet qui dépasse d'une vraie enveloppe */
  transform-origin: top center;
  transform: rotateX(0deg);
  will-change: transform, opacity;
  /* Le rabat ET sa dentelle prennent la teinte ensemble : la dentelle emprunte
     déjà sa couleur au velours par mix-blend-mode, elle doit donc rester dans
     le même groupe de rendu. Posée sur la seule face du rabat, la teinte
     donnait un rabat vert sur une poche restée grenat. */
  filter: var(--teinte);
  z-index: 2;
  /* Le rabat s'efface en opacité avant d'atteindre la verticale : il n'a plus
     besoin de preserve-3d (que l'opacité aplatirait de toute façon), ni de
     dos peint. L'ombre du pli est portée par les bandes de dentelle. */
  transition: transform 110ms cubic-bezier(0.34, 1.4, 0.64, 1);
}
/* Anticipation : au toucher, le rabat se tend une fraction de seconde contre
   son pli avant que la cire ne cède. C'est ce micro-temps qui fait la
   différence entre « un panneau qui pivote » et « une enveloppe qu'on ouvre ».
   Il faut que ce soit VU : 3,2° en 110 ms, pas 1° en 190 ms. */
.envelope-screen.is-arming .env-flap { transform: rotateX(3.2deg); }
/* Le rabat s'ENTROUVRE, il ne se retourne pas. Image par image, la vidéo de
   référence ne montre aucune bascule à 180° : l'écran surexpose vers le blanc
   en ~0,15 s et, quand la lumière retombe, le collage est déjà là. Une
   rotation complète se lit comme un panneau qui pivote — mécanique. Ici le
   rabat part sur 62°, la lumière prend le relais, et l'échange se fait dans le
   blanc. Corollaire : on ne voit jamais le dos du rabat, donc plus de
   croisement de faces ni de preserve-3d à entretenir. */
.envelope-screen.is-open .env-flap { animation: env-flap 900ms linear forwards; }
@keyframes env-flap {
  0%   { transform: rotateX(3.2deg); opacity: 1; }
  9%   { transform: rotateX(0deg); }
  20%  { transform: rotateX(-11deg); }
  32%  { transform: rotateX(-27deg); }
  44%  { transform: rotateX(-43deg); opacity: 1; }
  62%  { transform: rotateX(-56deg); opacity: 0; }
  100% { transform: rotateX(-62deg); opacity: 0; }
}
/* La nappe de lumière : c'est ELLE le mécanisme d'ouverture. Elle monte vite
   (0,2 s), tient le temps que la poche recule et que les papiers montent,
   puis se retire sur le collage déjà en place. */
.env-bloom {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(125% 82% at 50% 56%,
              #FFFFFF 0%, #FFFDFA 48%, rgba(253, 248, 240, 0.86) 72%,
              rgba(250, 245, 238, 0) 100%);
}
.envelope-screen.is-open .env-bloom { animation: env-bloom 1100ms linear forwards; }
@keyframes env-bloom {
  0%   { opacity: 0; }
  8%   { opacity: 0.22; }
  17%  { opacity: 1; }
  /* elle TIENT jusqu'à 62 % (~0,68 s) : c'est sous ce blanc que la poche
     recule et que les papiers montent. Se retirer plus tôt laissait voir un
     écran mauve vide le temps que le collage arrive. */
  62%  { opacity: 1; }
  84%  { opacity: 0.28; }
  100% { opacity: 0; }
}
.env-flap-face {
  position: absolute;
  inset: 0;
  display: grid;
  align-content: end;
  justify-items: center;
  gap: clamp(8px, 1.8vh, 16px);
  /* les textes se posent juste au-dessus du sceau, comme sur le modèle */
  padding: 0 var(--gutter) clamp(64px, 17vh, 150px);
  text-align: center;
  backface-visibility: hidden;
  background: url("../img/velvet-flap.webp") center / cover no-repeat, #7A2E3E;
  /* Le rabat et la poche sont le MÊME velours : l'écart de valeur entre les
     deux doit rester sous ~18 %, sinon on lit deux tissus différents cousus
     ensemble. Le relief est porté par la lumière rasante ci-dessous. */
  filter: brightness(1.10) saturate(0.96);
  /* 0.36 / 0.57 ≈ 63 % : les branches partent des bords à --v-edge */
  clip-path: polygon(0 0, 100% 0, 100% 63%, 50% 100%, 0 63%);
  box-shadow: inset 0 -44px 64px -55px rgba(16, 3, 8, 0.5);
}
/* lumière rasante : le haut du rabat est plus clair que sa pointe */
.env-flap-face::after {
  content: "";
  position: absolute;
  inset: 0;
  clip-path: inherit;
  background: linear-gradient(180deg, rgba(255, 214, 214, 0.16) 0%,
                              rgba(255, 214, 214, 0) 34%,
                              rgba(20, 4, 10, 0.22) 100%);
}
.env-from {
  margin: 0;
  position: relative;
  z-index: 2;
  font-family: var(--display);
  font-variant: small-caps;
  font-size: clamp(14px, 3.8vw, 19px);
  letter-spacing: 0.25em;
  text-indent: 0.25em;
  color: var(--cream-100);
}
.env-names {
  margin: 0;
  position: relative;
  z-index: 2;
  font-family: var(--display);
  font-size: clamp(20px, 5.4vw, 30px);
  line-height: 1.35;
  letter-spacing: 0.015em;
  text-wrap: balance;
  color: var(--cream-050);
  max-width: 20ch;
}
body[data-lang="he"] .env-names {
  font-family: var(--hebrew);
  font-size: clamp(19px, 5vw, 28px);
  line-height: 1.5;
}
/* La signature des mariés, en bas de l'enveloppe : c'est ELLE qui porte
   l'anglaise, comme sur une vraie lettre. Elle ne dépend pas du CRM. */
.env-letter {
  position: absolute;
  left: 50%;
  bottom: clamp(64px, 12vh, 140px);
  transform: translateX(-50%);
  z-index: 2;
  width: min(88vw, 22rem);
  text-align: center;
  pointer-events: none;
}
.env-letter-from {
  margin: 0 0 0.18em;
  font-family: var(--display);
  font-variant: small-caps;
  font-size: clamp(12px, 3.2vw, 15px);
  letter-spacing: 0.3em;
  text-indent: 0.3em;
  color: var(--cream-100);
  opacity: 0.9;
}
.env-letter-names {
  margin: 0;
  font-family: "Pinyon Script", var(--display), cursive;
  font-size: clamp(30px, 9vw, 46px);
  line-height: 1.15;
  color: var(--cream-050);
}
body[data-lang="he"] .env-letter-names {
  font-family: var(--hebrew);
  font-size: clamp(26px, 7.5vw, 40px);
  line-height: 1.3;
}
body[data-lang="he"] .env-letter-from { font-variant: normal; letter-spacing: 0.08em; text-indent: 0; }
.envelope-screen.is-open .env-letter { opacity: 0; transition: opacity 300ms var(--e-soft); }
body[data-lang="he"] .env-from { font-variant: normal; letter-spacing: 0.06em; text-indent: 0; }

/* La dentelle : une bande photographique répétée le long de chaque branche.
   app.js mesure le V et pose largeur + rotation sur chacune des deux bandes. */
.env-lace {
  position: absolute;
  top: 0;
  left: 0;
  height: clamp(38px, 12vw, 56px);
  background: url("../img/lace-band.webp") left center / auto 100% repeat-x;
  transform-origin: 0 0;
  pointer-events: none;
  /* Ton sur ton : la dentelle est du même fil que le velours, elle ne se lit
     qu'au relief. `luminosity` ne garde de la photo que sa lumière et lui
     emprunte la couleur du rabat — sans toucher à sa découpe (alpha). */
  mix-blend-mode: luminosity;
  /* un ourlet ne projette pas 6 px d'ombre uniforme */
  filter: drop-shadow(0 2px 3px rgba(16, 3, 8, 0.28));
  /* la jonction des deux bandes à la pointe du V se dissout au lieu de se voir */
  -webkit-mask-image: linear-gradient(to right, #000 88%, transparent 100%);
  mask-image: linear-gradient(to right, #000 88%, transparent 100%);
}
.env-lace--r {
  -webkit-mask-image: linear-gradient(to left, #000 88%, transparent 100%);
  mask-image: linear-gradient(to left, #000 88%, transparent 100%);
}

/* Le sceau de cire ovale — il ferme la pointe du V, puis se pose sur la poche */
.env-seal {
  position: absolute;
  left: 50%;
  top: var(--v-tip);
  z-index: 3;
  width: var(--seal-w);
  padding: 0;
  border: 0;
  background: none;
  /* tout se joue en transform : aucune propriété de mise en page animée,
     la séquence tient les 60 fps même sur un téléphone modeste */
  transform: translate(-50%, -50%);
  transition: transform 110ms cubic-bezier(0.34, 1.4, 0.64, 1);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.env-seal img {
  width: 100%;
  height: auto;
  filter: drop-shadow(0 7px 11px rgba(16, 3, 8, 0.42));
}
.env-seal::after { content: ""; position: absolute; inset: -14px; }
.env-seal:focus-visible { outline: 2px solid var(--cream-100); outline-offset: 6px; border-radius: 50%; }
.env-seal:focus:not(:focus-visible) { outline: none; }
/* Anticipation : la cire s'enfonce sous le doigt avant de céder. 10 % de
   compression en 110 ms se VOIT ; 4 % en 190 ms se lit « le tap n'a pas pris ». */
.envelope-screen.is-arming .env-seal { transform: translate(-50%, -50%) scale(0.90) translateY(1px); }
.envelope-screen.is-arming .env-seal img {
  filter: drop-shadow(0 3px 5px rgba(16, 3, 8, 0.55));
  transition: filter 110ms cubic-bezier(0.34, 1.4, 0.64, 1);
}
/* Puis elle se décolle, tombe en accélérant, touche la poche, s'y tasse d'un
   cheveu et se stabilise — exactement à la place et à la taille du sceau du
   collage qui l'attend dessous. */
/* `linear` + valeurs en t² : une chute libre n'a pas d'ease-in-out entre
   chaque paire de keyframes. Seuls le décollement (0→10 %) et l'amorti final
   (à partir de 80 %) portent une courbe, déclarée DANS le keyframe concerné. */
.envelope-screen.is-open .env-seal {
  animation: env-seal-drop 1080ms linear forwards;
  pointer-events: none;
}
.envelope-screen.is-open .env-seal img { animation: env-seal-shadow 1080ms linear forwards; }
@keyframes env-seal-drop {
  /* décollement : la cire comprimée se détache d'un coup */
  0%   { transform: translate(-50%, -50%) translateY(0) rotate(0deg) scale(0.90); animation-timing-function: ease-out; }
  /* apex du décollement : la cire s'y arrête une image, vitesse nulle — c'est
     le seul point de la course où elle a le droit d'être immobile */
  10%  { transform: translate(-50%, -50%) translateY(-1.1svh) rotate(-2.4deg) scale(1.02); }
  /* chute libre : y ∝ t² à partir de l'apex, la vitesse ne fait que croître
     jusqu'au contact. Aucun raccord de vitesse entre deux keyframes. */
  20%  { transform: translate(-50%, -50%) translateY(-0.66svh) rotate(-1.9deg) scale(1); }
  30%  { transform: translate(-50%, -50%) translateY(0.67svh)  rotate(-1.2deg) scale(1); }
  40%  { transform: translate(-50%, -50%) translateY(2.89svh)  rotate(-0.2deg) scale(1); }
  50%  { transform: translate(-50%, -50%) translateY(5.98svh)  rotate(1deg) scale(1); }
  60%  { transform: translate(-50%, -50%) translateY(9.98svh)  rotate(2.2deg) scale(1); }
  70%  { transform: translate(-50%, -50%) translateY(14.85svh) rotate(3.2deg) scale(1); }
  /* contact : la cire s'écrase d'un cheveu, rebondit, se pose */
  80%  { transform: translate(-50%, -50%) translateY(20.6svh) rotate(3.6deg) scale(1.035, 0.965); animation-timing-function: ease-out; }
  90%  { transform: translate(-50%, -50%) translateY(19.2svh) rotate(3deg) scale(0.99, 1.01); animation-timing-function: ease-out; }
  100% { transform: translate(-50%, -50%) translateY(var(--seal-travel)) rotate(3deg) scale(1); }
}
/* L'ombre suit la chute : large et diffuse en l'air, courte et dense au contact */
@keyframes env-seal-shadow {
  0%   { filter: drop-shadow(0 3px 5px rgba(16, 3, 8, 0.55)); }
  20%  { filter: drop-shadow(0 12px 16px rgba(16, 3, 8, 0.4)); }
  60%  { filter: drop-shadow(0 20px 24px rgba(16, 3, 8, 0.34)); }
  80%  { filter: drop-shadow(0 4px 7px rgba(16, 3, 8, 0.5)); }
  100% { filter: drop-shadow(0 6px 10px rgba(16, 3, 8, 0.45)); }
}

/* L'invite, sous le sceau */
.env-cta {
  position: absolute;
  left: 50%;
  top: calc(var(--v-tip) + clamp(52px, 9vh, 84px));
  transform: translateX(-50%);
  margin: 0;
  z-index: 2;
  white-space: nowrap;
  font-family: var(--display);
  font-variant: small-caps;
  font-size: clamp(12px, 3.2vw, 15px);
  letter-spacing: 0.3em;
  text-indent: 0.3em;
  color: var(--cream-100);
  opacity: 0.94;
}
body[data-lang="he"] .env-cta { font-variant: normal; letter-spacing: 0.08em; text-indent: 0; }
.envelope-screen.is-open .env-cta { opacity: 0; transition: opacity 300ms var(--e-soft); }

/* La sortie de secours reste discrète et lisible */
.env-skip {
  position: absolute;
  left: 50%;
  bottom: max(40px, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 6;
  min-height: 44px;
  padding: 0 var(--s-4);
  font-family: var(--label);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--rose-300);
  opacity: 0.8;
}
.env-skip:hover { opacity: 1; }
.envelope-screen.is-open .env-skip { opacity: 0; pointer-events: none; }

/* --- 9. Hero : le collage sorti de l'enveloppe ---------------------------- */
/* Reproduction plan par plan de l'état ouvert du modèle : papiers empilés
   sur la poche de velours, chacun avec son ombre portée douce. */
.hero {
  position: relative;
  z-index: 1;
  min-height: 100svh;
  background: var(--cream-100);
  /* le collage dépasse des deux bords (carton rayé, fleurs) : on coupe en
     largeur seulement, l'amarante doit continuer de pendre sur la suite */
  overflow-x: clip;
  overflow-y: visible;
}

.hero-bsd {
  position: absolute;
  z-index: 8;
  top: calc(var(--s-3) + env(safe-area-inset-top));
  right: var(--gutter);
  left: auto;
  margin: 0;
  font-family: var(--hebrew);
  font-size: 13px;
  color: #856442;
  letter-spacing: 0.06em;
}

.collage-stage {
  position: relative;
  height: 100svh;
  max-width: 560px;
  margin: 0 auto;
}
.clg { position: absolute; }

/* Le carton rayé, qui dépasse en haut à droite du paquet */
.clg-striped {
  z-index: 1;
  /* juste au-dessus de la carte (9 %), mais assez bas pour laisser le בס״ד
     se lire sur le crème et non sur les rayures */
  top: 5%;
  right: -5%;
  width: 62%;
  height: 28%;
  background: var(--cream-050);
  padding: 9px;
  box-shadow: var(--lift-2);
}
.clg-striped::before {
  content: "";
  position: absolute;
  inset: 9px;
  background: repeating-linear-gradient(90deg,
    var(--wine-600) 0 8px, var(--cream-100) 8px 22px);
}

/* La carte principale : double filet bordeaux, SAVE THE DATE, noms en anglaise */
.clg-card {
  z-index: 2;
  /* descendus de 4 points : le papier rayé passait sur le בס״ד */
  top: 9%;
  left: 13%;
  width: 84%;
  height: 50%;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: clamp(4px, 1vh, 10px);
  /* Le retrait à gauche doit dégager le cadre ovale EN ENTIER : le cadre est
     au-dessus de la carte (z-index 3 contre 2), donc tout ce qui passe dessous
     est mangé — c'est la troisième ligne de la phrase qui disparaissait. */
  padding: 8% 3% 6% 41%;
  text-align: center;
  background: var(--cream-050);
  box-shadow: var(--lift-2);
}
.clg-card::before {
  content: "";
  position: absolute;
  inset: 8px;
  border: 1px solid var(--wine-600);
  pointer-events: none;
}
.clg-card::after {
  content: "";
  position: absolute;
  inset: 13px;
  border: 1px solid var(--wine-600);
  pointer-events: none;
}
.clg-std {
  margin: 0 0 clamp(4px, 1.4vh, 14px);
  font-family: var(--display);
  font-variant: small-caps;
  /* c'était 10 px avec 0,3 em d'interlettrage sur trois lignes : illisible.
     Corps relevé, interlettrage divisé par deux, interligne ouvert. */
  font-size: clamp(12px, 3.35vw, 17px);
  letter-spacing: 0.13em;
  text-indent: 0.13em;
  line-height: 1.65;
  /* bornée à ~16 caractères : la phrase se pose sur TROIS lignes, elle tenait
     sur deux lignes trop longues et trop serrées contre le cadre */
  max-width: 21ch;
  margin-inline: auto;
  text-wrap: balance;
  color: var(--ink-soft);
}
body[data-lang="he"] .clg-std { font-variant: normal; letter-spacing: 0.14em; text-indent: 0; }
.clg-names {
  margin: 0;
  display: grid;
  gap: clamp(0px, 0.4vh, 6px);
  font-family: "Pinyon Script", var(--display), cursive;
  font-weight: 400;
  font-size: clamp(28px, 8vw, 44px);
  line-height: 1.12;
  color: #37402F;
}
.clg-names .clg-amp { font-size: 0.58em; line-height: 1; }
body[data-lang="he"] .clg-names {
  font-family: var(--hebrew);
  font-weight: 300;
  font-size: clamp(26px, 7.4vw, 40px);
}

/* Le cadre ovale ornementé et la photo du couple */
.clg-frame {
  z-index: 3;
  top: 13%;
  left: 1%;
  width: 48%;
  aspect-ratio: 640 / 753;
  filter: drop-shadow(0 14px 18px rgba(36, 20, 25, 0.28));
}
.clg-frame-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.clg-frame .clg-frame-photo {
  position: absolute;
  inset: 15% 22%;
  border-radius: 50%;
  overflow: hidden;
  background: var(--cream-200);
}
.clg-frame .clg-frame-photo img,
.clg-frame .clg-frame-photo video { width: 100%; height: 100%; object-fit: cover; display: block; }

/* La pivoine en papier embossé, posée contre le cadre */
.clg-peony {
  z-index: 4;
  /* Rose en papier découpé, plate, comme dans la vidéo d'origine : elle se
     tient À GAUCHE du cadre et ne fait que mordre son bord, au lieu de lui
     passer dessus. Elle reste entière — plus de masque de fondu : on ne
     dissout pas le bord d'un objet qui, lui, a une découpe franche. */
  top: 8%;
  left: -13%;
  width: 27%;
  height: auto;
  transform: rotate(-8deg);
  filter: drop-shadow(0 8px 10px rgba(36, 20, 25, 0.18));
}
/* Sous 440 px, le stage fait toute la largeur : à -8 % la pivoine sortait du
   viewport et se faisait couper à la règle. On la rentre. */
@media (max-width: 440px) {
  .clg-peony { left: -2%; }
}

/* Le napperon cœur, qui dépasse en bas du paquet, avec la date */
.clg-doily {
  z-index: 3;
  top: 47%;
  left: 26%;
  width: 60%;
  filter: drop-shadow(0 10px 14px rgba(36, 20, 25, 0.22));
}
/* Le napperon doit être ivoire, dans la famille du crème, pas l'ocre kaki
   qu'aucune autre pièce de la palette ne porte : sinon c'est le deuxième bloc
   de valeur le plus lourd de l'écran, et il tire tout vers le jaune. */
.clg-doily img { width: 100%; height: auto; filter: saturate(0.5) brightness(1.08); }
/* La date est LE renseignement que l'invité vient chercher : elle est posée
   dans le haut du cœur, toujours au-dessus de la ligne de la poche (sinon le
   velours lui mange le pied), en encre sombre sur le napperon crème. */
.clg-date {
  position: absolute;
  /* centrée dans le cœur : 46 % puis recentrage sur soi-même. Le point bas du
     cœur tire son centre optique vers le haut, d'où les 4 % de moins que 50. */
  top: 46%;
  transform: translateY(-50%);
  left: 0;
  right: 0;
  margin: 0;
  text-align: center;
  font-family: var(--display);
  font-weight: 500;
  font-variant-numeric: lining-nums;
  font-size: clamp(21px, 6vw, 30px);
  line-height: 1;
  letter-spacing: 0.13em;
  text-indent: 0.13em;
  /* napperon éclairci : l'encre remonte en bordeaux sombre pour rester ≥ 7:1 */
  color: #4A2B2E;
}

/* La composition florale accrochée au bord droit de la poche ;
   l'amarante retombe et déborde sur la section suivante. */
.clg-floral {
  z-index: 6;
  /* Le bouquet est plus large que haut depuis qu'il a été refait d'après la
     vidéo (hortensias crème, roses poudrées, eucalyptus) : les anciens
     décalages, calés sur une composition très verticale, le faisaient sortir
     du cadre par le bas. Dégagé du sceau, qui reste au centre. */
  right: -20%;
  bottom: -3%;
  width: 58%;
  height: auto;
  pointer-events: none;
  filter: drop-shadow(0 12px 14px rgba(36, 20, 25, 0.30));
}

/* La poche de l'enveloppe au premier plan, sceau posé dessus */
/* Le 33 tours, posé en bas à gauche sur le velours, à hauteur du sceau. */
/* Le 33 tours se pose EN HAUT, dans le creux entre le cadre ovale et le cœur,
   et non plus en bas sur le velours. Le cœur se décale vers la droite pour lui
   faire place : le collage y gagne son léger déséquilibre. */
.clg-vinyl {
  position: absolute;
  left: -1%;
  top: 41.5%;
  width: 31%;
  aspect-ratio: 1;
  padding: 0;
  border: 0;
  background: none;
  z-index: 6;
  cursor: pointer;
  filter: drop-shadow(0 8px 16px rgba(20, 6, 12, 0.45));
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: transform var(--t-fast) var(--e-out);
}
.clg-vinyl:active { transform: scale(0.96); }
.vinyl-plate, .vinyl-arc { position: absolute; inset: 0; width: 100%; height: 100%; }
/* Reflets. Pas de mix-blend-mode : la nappe blanche déborderait sur le crème
   du collage. Un simple blanc translucide suffit — le vinyle est presque noir.

   ⚠️ Le reflet du VINYLE ne tourne pas. Il vient de la lumière de la pièce, pas
   du disque : c'est son immobilité qui fait lire la rotation des sillons. Le
   faire tourner à sa propre vitesse (9 s) pendant que les sillons tournaient en
   3,6 s donnait deux mouvements concurrents, et le disque ne semblait plus
   tourner du tout. Seule la pastille métal a une trame qui défile — et elle
   défile À LA VITESSE DU PLATEAU, puisqu'elle est solidaire de lui. */
.vinyl-gloss {
  position: absolute;
  border-radius: 50%;
  overflow: hidden;
  pointer-events: none;
}
.vinyl-gloss::before {
  content: "";
  position: absolute;
  inset: -30%;
}
.vinyl-gloss--disc { inset: 1%; }
/* fixe : les deux éclats tombent en haut à gauche et en bas à droite, dans
   l'axe de la lumière déjà peinte sur le plateau (v-sheen) */
.vinyl-gloss--disc::before {
  background: conic-gradient(from -65deg,
    rgba(255, 255, 255, 0) 0deg,
    rgba(255, 248, 238, 0.20) 22deg,
    rgba(255, 255, 255, 0) 58deg,
    rgba(255, 255, 255, 0) 158deg,
    rgba(255, 248, 238, 0.14) 186deg,
    rgba(255, 255, 255, 0) 222deg,
    rgba(255, 255, 255, 0) 360deg);
}
/* le métal de la pastille : reflet plus vif, plus serré, en sens inverse */
.vinyl-gloss--label { inset: 28.5%; }
.vinyl-gloss--label::before {
  background: conic-gradient(from 0deg,
    rgba(255, 255, 255, 0) 0deg,
    rgba(255, 255, 255, 0.55) 14deg,
    rgba(255, 255, 255, 0) 40deg,
    rgba(255, 255, 255, 0) 170deg,
    rgba(255, 255, 255, 0.38) 184deg,
    rgba(255, 255, 255, 0) 210deg,
    rgba(255, 255, 255, 0) 360deg);
}
/* solidaire du plateau : même durée, même sens que .vinyl-spin */
.clg-vinyl.is-playing .vinyl-gloss--label::before {
  animation: vinyl-gloss 3.6s linear infinite;
}
@keyframes vinyl-gloss { to { transform: rotate(360deg); } }
.vinyl-spin { transform-origin: 50% 50%; }
.clg-vinyl.is-playing .vinyl-spin { animation: vinyl-spin 3.6s linear infinite; }
@keyframes vinyl-spin { to { transform: rotate(360deg); } }
/* Texte gravé, en serif comme sur le modèle — pas une capitale géométrique */
.vinyl-arc text {
  font-family: var(--display), serif;
  font-size: 17px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  fill: #F6F1EA;
  fill-opacity: 0.96;
}
body[data-lang="he"] .vinyl-arc text { text-transform: none; letter-spacing: 0.02em; }
.vinyl-glyph {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 21%;
  height: 21%;
  transform: translate(-50%, -50%);
  /* le centre de la pastille est gris foncé : le symbole y passe en clair */
  color: #F4F0EA;
  pointer-events: none;
}
.vinyl-glyph svg { width: 100%; height: 100%; display: block; }
@media (prefers-reduced-motion: reduce) {
  .clg-vinyl.is-playing .vinyl-spin { animation: none; }
  .vinyl-gloss::before { animation: none; }
}

.clg-pocket {
  z-index: 5;
  /* la poche court sur toute la largeur, comme celle de l'enveloppe : même
     boîte 100vw × 36svh, donc EXACTEMENT le même cadrage de la texture, et
     la trame du velours ne bouge pas d'un fil au relais enveloppe → collage */
  left: 50%;
  right: auto;
  width: 100vw;
  transform: translateX(-50%);
  bottom: 0;
  height: 36%;
  clip-path: polygon(0 0, 50% 12%, 100% 0, 100% 100%, 0 100%);
  filter: drop-shadow(0 -10px 16px rgba(36, 20, 25, 0.30));
}
/* replis de la poche : deux diagonales d'ombre qui se croisent au sceau */
.clg-pocket::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(118deg, rgba(255, 214, 214, 0.07) 0%, rgba(255, 214, 214, 0) 30%),
    linear-gradient(64deg,  rgba(20, 4, 10, 0.32) 0%, rgba(20, 4, 10, 0) 40%),
    linear-gradient(-64deg, rgba(20, 4, 10, 0.32) 0%, rgba(20, 4, 10, 0) 40%),
    linear-gradient(0deg,   rgba(20, 4, 10, 0.28) 0%, rgba(20, 4, 10, 0) 30%);
}
/* Le sceau posé sur la poche : même taille, même place et même inclinaison
   que celui de l'enveloppe en fin de chute — c'est lui que l'invité voit
   atterrir, la bascule d'un calque à l'autre ne se voit pas. */
/* Le velours vit sur sa propre couche : la teinte le colore SANS emporter le
   sceau de cire, qui est un enfant de la poche et doit rester champagne. */
.clg-pocket::before {
  content: "";
  position: absolute;
  inset: 0;
  background: url("../img/velvet-pocket.webp") center / cover no-repeat, #5E1F2C;
  filter: var(--teinte);
}
.clg-pocket-seal {
  z-index: 1;
  position: absolute;
  left: 50%;
  top: 36%;
  width: var(--seal-w);
  height: auto;
  transform: translate(-50%, -50%) rotate(3deg);
  filter: drop-shadow(0 6px 10px rgba(16, 3, 8, 0.45));
}

/* Chorégraphie de sortie : tant que l'enveloppe est fermée, les papiers
   attendent dans la poche ; is-unpacking les fait glisser vers le haut,
   en léger décalage de couche en couche (effet « paquet de cartes »). */
body.is-locked:not(.is-unpacking) .clg-striped { transform: translateY(16vh); }
body.is-locked:not(.is-unpacking) .clg-card    { transform: translateY(14vh); }
body.is-locked:not(.is-unpacking) .clg-frame   { transform: translateY(13vh); }
body.is-locked:not(.is-unpacking) .clg-peony   { transform: rotate(-10deg) translateY(13vh); }
body.is-locked:not(.is-unpacking) .clg-doily   { transform: translateY(10vh); }
/* Le bouquet n'apparaît PAS en fondu (un objet ne devient pas translucide en
   arrivant) : il glisse de sous la lèvre de la poche, derrière elle (z 4 <
   z 5 de .clg-pocket), et ne repasse au premier plan qu'une fois posé. */
body.is-locked:not(.is-unpacking) .clg-floral  { transform: translateY(26vh); z-index: 4; }
/* Le paquet ne « monte » pas : il est tiré hors de la poche, dépasse d'un
   cheveu sur sa lancée puis retombe en place — d'où la courbe qui déborde
   au-delà de 1. Les couches partent en cascade, la plus basse en premier. */
body.is-unpacking .clg {
  transition: transform 560ms cubic-bezier(0.16, 1.05, 0.3, 1),
              opacity 380ms var(--e-soft);
}
body.is-unpacking .clg-doily   { transition-delay: 120ms; }
body.is-unpacking .clg-card    { transition-delay: 165ms; }
body.is-unpacking .clg-frame   { transition-delay: 195ms; }
body.is-unpacking .clg-striped { transition-delay: 220ms; }
body.is-unpacking .clg-peony   { transition-delay: 245ms; }
/* Le bouquet est le dernier posé : il sort de la poche pendant que
   l'enveloppe s'efface (1300 ms), pas après, sinon les deux mouvements se
   lisent l'un après l'autre au lieu de n'en faire qu'un. Le passage au
   premier plan attend la fin de sa course (1300 + 900 = 2200 ms). */
body.is-unpacking .clg-floral {
  z-index: 6;
  transition: transform 900ms cubic-bezier(0.16, 1.06, 0.3, 1) 1300ms,
              z-index 0ms linear 2200ms;
}

/* --- 10. Verset ---------------------------------------------------------- */
.verse {
  font-family: var(--hebrew);
  font-size: clamp(19px, 5.4vw, 25px);
  line-height: 1.9;
  color: var(--wine-600);
  margin: 0 0 var(--s-3);
  direction: rtl;
}

/* --- 11. Familles -------------------------------------------------------- */
/* Les deux générations sont composées par renderInvitation() en .fp-family
   (voir §26) : parents et grands-parents s'y distinguent au corps et à la
   couleur, séparés par un filet or. */

/* Le bouquet passe DERRIÈRE les prénoms, en grand et très peu opaque : c'est
   un filigrane, pas un ornement de marge. Centré sur la ligne des prénoms, il
   déborde volontiers sous les lignes voisines — c'est ce débordement qui le
   fait lire comme un fond et non comme une image posée. */
.faire-part { position: relative; }
.fp-bloom {
  position: absolute;
  z-index: 0;
  left: 50%;
  top: 57%;
  transform: translate(-50%, -50%);
  width: min(92%, 27rem);
  height: auto;
  opacity: 0.14;
  pointer-events: none;
  user-select: none;
}
.faire-part > :not(.fp-bloom) { position: relative; z-index: 1; }

/* Le filet à arabesque ouvre le paragraphe du souvenir — il remplace le trait
   plat qui servait de bordure haute au paragraphe. */
.rule--arabesque {
  display: block;
  width: min(72%, 17rem);
  margin: var(--s-4) auto var(--s-5);
  color: var(--rose-300);
}
.rule--arabesque svg { width: 100%; height: auto; display: block; }
.memory {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
  white-space: pre-line;
  font-style: italic;
  font-size: 15.5px;
  line-height: 1.8;
  color: var(--fg-soft);
  max-width: var(--measure);
  margin-inline: auto;
}
.section--wine .memory { color: var(--rose-200); }

/* --- 12. Cartes d'événement ---------------------------------------------- */
/* Le texte vient d'abord, l'illustration monte en fondu sous lui —
   pas d'encadré : chaque moment occupe la largeur de l'écran. */
.events { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; }
/* La dernière vignette court jusqu'à la section suivante : la marge basse de
   la section laissait sous elle une bande crème, lue comme un bandeau blanc
   en travers de la page. */
#s-events { padding-bottom: 0; }

.event {
  position: relative;
  text-align: center;
  scroll-margin-top: var(--s-4);
  scroll-margin-bottom: calc(var(--navbar-h) + var(--s-6));
  padding-top: var(--section-y);
}
.event:first-child { padding-top: var(--s-6); }

.event-body {
  padding: 0 var(--gutter);
  max-width: 34rem;
  margin: 0 auto;
}
.event-body .rule { margin: var(--s-4) auto var(--s-5); }

.event-badge {
  display: block;
  margin: 0 0 var(--s-3);
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--olive-600);
}
.event-title {
  font-family: var(--display);
  font-weight: 300;
  font-size: clamp(30px, 8.6vw, 44px);
  line-height: 1.1;
  color: var(--wine-700);
  margin: 0 0 var(--s-1);
}
.event-hebrew-date {
  font-family: var(--hebrew);
  font-size: 15px;
  color: var(--ink-label);
  margin: 0;
}

/* Pas de libellés « DATE / HORAIRE / LIEU » : la date EST le second niveau
   typographique de la carte, comme sur un carton imprimé. */
.event-meta {
  margin: 0 auto var(--s-5);
  max-width: 26rem;
  text-align: center;
}
.meta-when {
  margin: 0;
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(24px, 7vw, 30px);
  line-height: 1.25;
  color: var(--wine-700);
}
.meta-hour {
  margin: 8px 0 0;
  font-family: var(--display);
  font-size: clamp(17px, 4.4vw, 19px);
  line-height: 1.5;
  color: var(--wine-600);
}
.meta-place {
  margin: 24px 0 0;
  font-family: var(--display);
  font-style: italic;
  font-size: clamp(17.5px, 4.6vw, 19px);
  line-height: 1.45;
  color: var(--fg);
}
.meta-address {
  margin: 8px 0 0;
  font-size: 15px;
  line-height: 1.5;
  color: var(--fg-soft);
}

/* La phrase d'ouverture de la carte : elle vient AVANT les renseignements,
   c'est l'ordre du document des mariés. Même italique que la chute, mais en
   encre pleine — c'est une annonce, pas une remarque. */
.event-intro {
  margin: 0 0 var(--s-5);
  max-width: var(--measure);
  margin-inline: auto;
  font-family: var(--display);
  font-style: italic;
  font-size: clamp(17px, 1.35vw, 20px);
  line-height: 1.55;
  color: var(--ink);
  text-wrap: pretty;
}
body[data-lang="he"] .event-intro { font-style: normal; }

.event-note {
  font-style: italic;
  font-size: 16px;
  color: var(--fg-soft);
  margin: 0 auto var(--s-5);
  max-width: 24rem;
}

.event-actions { display: flex; flex-wrap: wrap; gap: var(--s-2); justify-content: center; }
.event-actions .btn { flex: 0 1 auto; min-width: 138px; }

/* L'adresse se copie d'un tap */
.address {
  position: relative;
  display: inline;
  padding: 0;
  text-align: inherit;
  font: inherit;
  color: inherit;
  text-decoration: underline dotted;
  text-underline-offset: 4px;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(71, 18, 36, 0.35);
  transition: color var(--t-fast) var(--e-soft), text-decoration-color var(--t-fast) var(--e-soft);
}
/* La cible tactile reste de 44 px sans épaissir la ligne */
.address::before { content: ""; position: absolute; inset: -10px -6px; }
.address:hover, .address.is-copied { color: var(--wine-700); text-decoration-color: var(--wine-600); }

/* L'illustration naît du fond : aucune arête, un fondu franc vers le haut */
.event-figure {
  position: relative;
  /* d'un bord à l'autre de l'écran, comme sur les cartons de référence */
  margin: var(--s-5) calc(var(--gutter) * -1) 0;
  /* la proportion native de l'image, posée par renderEvents() : en 4/3 imposé,
     une aquarelle en portrait était recadrée sur sa bande centrale — les mariés
     assis sous la houppa disparaissaient du cadre */
  aspect-ratio: var(--fig-ratio, 4 / 3);
  overflow: hidden;
  isolation: isolate;
  pointer-events: none;
  /* Un seul fondu, en haut. Il porte sur le bloc entier (image + voile
     bordeaux) : sans quoi le voile dessinerait un rectangle net au-dessus
     de l'aquarelle. En bas, l'image meurt nette sur le bord de la carte,
     comme sur les cartons de référence. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 22%, #000 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 22%, #000 100%);
}
.event-figure img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.95) contrast(1.02) brightness(1.02);
}
.event-figure::before {
  content: "";
  position: absolute; inset: 0; z-index: 1;
  mix-blend-mode: soft-light;
  opacity: 0.25;
  background: linear-gradient(180deg, #6E8A63 0%, var(--wine-ground) 100%);
}

/* --- 13. Hôtels ---------------------------------------------------------- */
.hotel-list { list-style: none; margin: var(--s-5) 0; padding: 0; display: grid; gap: var(--s-2); }
.hotel-list a {
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  min-height: 52px;
  padding: var(--s-3) var(--s-4);
  background: rgba(253, 251, 247, 0.06);
  border: 1px solid rgba(238, 223, 219, 0.24);
  border-radius: 2px;
  font-size: 17px;
  transition: background var(--t-base) var(--e-soft), border-color var(--t-base) var(--e-soft);
}
.hotel-list a:hover { background: rgba(253, 251, 247, 0.12); border-color: rgba(238, 223, 219, 0.45); }
.hotel-list svg { width: 15px; height: 15px; flex: none; opacity: 0.7; }

.promo {
  display: grid;
  grid-template-columns: minmax(0, 1fr);   /* sinon le code promo impose sa largeur */
  gap: var(--s-2);
  margin: var(--s-5) auto 0;
  padding: var(--s-5) var(--s-4);
  width: 100%;
  max-width: 420px;
  border: 1px solid rgba(238, 223, 219, 0.28);
  border-radius: 2px;
  background: rgba(253, 251, 247, 0.05);
}
.promo-code {
  max-width: 100%;
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  justify-content: center;
  min-height: 48px;
  padding: 0 var(--s-5);
  margin: var(--s-1) auto;
  background: var(--cream-200);
  color: var(--wine-800);
  border-radius: 2px;
  font-family: var(--label);
  font-size: clamp(15px, 4.6vw, 19px);
  letter-spacing: 0.28em;
  text-indent: 0.28em;
}
.promo-help { min-width: 0; overflow-wrap: anywhere; font-size: 14.5px; line-height: 1.65; color: var(--rose-200); opacity: 0.92; margin: 0; }

/* --- 14. RSVP ------------------------------------------------------------ */
.rsvp-hello {
  font-family: var(--display);
  font-style: italic;
  font-size: 17px;
  color: var(--fg-soft);
  margin: 0 0 var(--s-2);
}
.rsvp-name {
  font-family: var(--display);
  font-size: 25px;
  color: var(--wine-700);
  margin: 0 0 var(--s-5);
}

.form { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-5); text-align: start; margin-top: var(--s-5); }

.field { display: grid; gap: var(--s-2); }
.field-label {
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--wine-600);
}
.field-label .opt { text-transform: none; letter-spacing: 0.04em; color: var(--ink-label); font-size: 12px; }

/* Le cartouche : à partir de la case « nous ne pourrons pas », tout le
   formulaire entre dans un carton crème au double filet or. Sans lui, cinq
   rectangles pâles flottent sur du papier pâle et la page bascule du côté
   « ticket de support ». */
.form-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-5);
  padding: var(--s-6);
  background: var(--cream-050);
  border: 1px solid rgba(138, 106, 69, 0.45);
  border-radius: var(--r-paper);
  box-shadow: inset 0 0 0 5px var(--cream-050),
              inset 0 0 0 6px rgba(138, 106, 69, 0.25);
}

/* Les champs sont des lignes à remplir, comme sur un menu imprimé :
   pas de boîte, un simple filet bas. */
.input {
  width: 100%;
  min-height: 48px;
  padding: 11px 2px;
  font-family: var(--display);
  font-size: 17px;
  color: var(--fg);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule-soft);
  border-radius: 0;
  transition: border-color var(--t-base) var(--e-soft);
}
.input::placeholder { color: #8A7A72; font-style: italic; }
.input:focus-visible {
  outline: 2px solid var(--wine-600);
  outline-offset: 3px;
}
.input:focus {
  border-bottom-color: var(--wine-600);
  box-shadow: none;
}
textarea.input { min-height: 84px; line-height: 1.6; }
textarea.input--address { min-height: 72px; }

/* Le bouton d'envoi est une mention de carton, pas un aplat de CTA :
   filet bordeaux, encre bordeaux ; le plein ne vient qu'au contact. */
.btn--card {
  --btn-fg: var(--wine-700);
  --btn-bg: transparent;
  border-color: var(--wine-700);
}
.btn--card:hover,
.btn--card:focus-visible,
.btn--card:active {
  --btn-fg: var(--cream-050);
  --btn-bg: var(--wine-700);
}

.counters { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; }

.counter {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-4) 0;
  border-bottom: 1px solid var(--rule-soft);
  transition: border-color var(--t-base) var(--e-soft);
}
.counter:first-child { border-top: 1px solid var(--rule-soft); }
.counter.is-on { border-bottom-color: var(--rule); }
.counter.is-on .counter-title { color: var(--wine-700); }
.counter-label { display: grid; gap: 2px; min-width: 0; overflow-wrap: anywhere; }
.counter-title { font-size: 17px; line-height: 1.3; color: var(--wine-700); }
.counter-sub { font-size: 13px; color: var(--fg-soft); }

/* Un bouton par nombre possible. Rond, franc, l'actif en plein. */
.nb-choix { display: flex; gap: clamp(6px, 1.8vw, 10px); align-items: center; }
.nb {
  width: clamp(38px, 10vw, 44px);
  height: clamp(38px, 10vw, 44px);
  border-radius: 50%;
  border: 1px solid var(--rule-soft);
  font-family: var(--display);
  font-size: 17px;
  font-variant-numeric: lining-nums;
  color: var(--fg-soft);
  display: grid;
  place-items: center;
  transition: background var(--t-base) var(--e-soft), color var(--t-base) var(--e-soft),
              border-color var(--t-base) var(--e-soft);
}
.nb:hover { border-color: var(--wine-600); color: var(--wine-700); }
.nb--zero { border-style: dashed; }
.nb.is-on {
  background: var(--wine-700);
  border-color: var(--wine-700);
  color: var(--cream-050);
}

.decline {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: 52px;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--cream-300);
  border-radius: 3px;
  background: var(--cream-050);
  cursor: pointer;
  transition: border-color var(--t-base) var(--e-soft), background var(--t-base) var(--e-soft);
}
/* Dans le cartouche, la case suit la même langue que les champs : un filet
   bas, pas une boîte pâle sur du papier pâle. */
.form-card .decline {
  padding: var(--s-3) 2px;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule-soft);
  border-radius: 0;
}
.form-card .decline.is-on { border-bottom-color: var(--wine-600); background: transparent; }
.decline.is-on { border-color: var(--wine-600); background: #fff; }
.decline input { position: absolute; opacity: 0; pointer-events: none; }
.decline .box {
  width: 22px; height: 22px; flex: none;
  border: 1px solid var(--sand-400);
  border-radius: 2px;
  display: grid; place-items: center;
  color: transparent;
  transition: background var(--t-fast) var(--e-soft), border-color var(--t-fast) var(--e-soft), color var(--t-fast) var(--e-soft);
}
.decline.is-on .box { background: var(--wine-700); border-color: var(--wine-700); color: var(--cream-050); }
.decline .box svg { width: 13px; height: 13px; }
.decline span.txt { font-size: 16px; line-height: 1.4; }

/* Le message d'erreur reste dans la palette : pas de rouge d'alerte au milieu
   du carton, un filet bordeaux en marge. */
.form-error {
  padding: var(--s-3) var(--s-4);
  background: rgba(87, 41, 50, 0.06);
  border: 0;
  border-inline-start: 2px solid var(--wine-700);
  border-radius: 0;
  color: var(--wine-700);
  font-size: 15px;
  text-align: start;
}

.form-done { text-align: center; padding: var(--s-6) var(--s-3); }
/* `width` sur un span en ligne ne fait rien : sans `display: block`, la coche
   de confirmation s'affichait sur 220 px de haut au milieu du carton. */
.form-done .done-mark { display: block; width: 54px; margin: 0 auto var(--s-4); color: var(--olive-600); }
.form-done .done-mark svg { width: 100%; height: auto; display: block; }
.form-done h3 {
  font-family: var(--display);
  font-weight: 300;
  font-size: 30px;
  color: var(--wine-700);
  margin: 0 0 var(--s-2);
}
.form-done p { color: var(--fg-soft); margin: 0 0 var(--s-4); }

/* --- 15. Navigation basse ------------------------------------------------ */
.navbar {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: var(--z-nav);
  display: flex;
  justify-content: center;
  gap: 2px;
  padding: 6px 6px calc(6px + env(safe-area-inset-bottom));
  background: rgba(250, 245, 238, 0.985);
  border-top: 1px solid var(--rule-soft);
  box-shadow: 0 -10px 30px -22px rgba(36, 20, 25, 0.5);
}

.nav-item {
  flex: 1 1 0;
  max-width: 96px;
  min-height: 58px;
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 4px;
  /* 10 px sous la ligne de base : en hébreu (Assistant, boîte de ligne plus
     haute) le point d'onglet actif venait toucher le libellé. */
  padding: 6px 2px 10px;
  border-radius: var(--r-paper);
  color: #6B4550;
  opacity: 0.82;
  transition: opacity var(--t-base) var(--e-soft), background var(--t-base) var(--e-soft);
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.nav-item:active { background: rgba(71, 18, 36, 0.06); }
.nav-item.is-active { opacity: 1; }
.nav-item.is-active .nav-icon { color: var(--wine-700); }
.nav-item.is-active .nav-label { color: var(--wine-700); }
.nav-item.is-active::after {
  content: "";
  position: absolute;
  bottom: 2px;
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--wine-700);
}
.nav-item { position: relative; }

.nav-icon { width: 26px; height: 26px; color: var(--wine-600); }
.nav-label {
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.06em;
  line-height: 1.1;
  color: var(--wine-600);
  text-align: center;
}

/* --- 16. Sélecteur de langue & musique ----------------------------------- */
.utility {
  position: absolute;      /* dans le flux : plus rien ne flotte au-dessus du contenu */
  z-index: 12;
  top: max(12px, env(safe-area-inset-top));
  left: 12px;                 /* position physique : jamais renvoyée à droite en hébreu */
  right: auto;
  display: flex;
  gap: var(--s-2);
}
.footer .utility {
  position: static;
  justify-content: center;
  margin-top: var(--s-6);
}
.footer .utility button {
  background: rgba(253, 251, 247, 0.1);
  border-color: rgba(238, 223, 219, 0.3);
  color: var(--cream-200);
  box-shadow: none;
}
.utility button {
  min-height: 44px;
  min-width: 40px;
  padding: 0 var(--s-3);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: rgba(250, 245, 238, 0.9);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--rule-soft);
  border-radius: 999px;
  font-family: var(--label);
  font-size: 11.5px;
  letter-spacing: 0.08em;
  color: var(--wine-700);
  box-shadow: var(--lift-1);
  transition: background var(--t-base) var(--e-soft), transform var(--t-fast) var(--e-out);
}
.utility button:active { transform: scale(0.95); }
.utility svg { width: 15px; height: 15px; }

/* --- 17. Pied de page : draperie ivoire, monogramme au double filet ------- */
.footer {
  position: relative;
  z-index: 1;
  padding: 0;
  text-align: center;
  /* Le fond du pied de page est le crème de la section qui le précède : la
     draperie, masquée sur ses 56 premiers pixels, y fond au lieu d'être
     tranchée au couteau par un trait horizontal. */
  background: var(--cream-200);
  color: var(--cream-100);
  overflow: hidden;
}
/* La draperie est cadrée par le HAUT : on voit la tringle et la naissance des
   plis, pas un échantillon de tissu coupé au milieu. Le raccord avec le crème
   de la section RSVP se fait par un masque de 56 px, sinon le bord haut du
   pied de page est un trait horizontal au couteau. L'image d'origine tire vers
   le caramel : on la ramène vers l'ivoire froid de la référence. */
.footer-drape {
  position: absolute;
  inset: 0;
  background: var(--wine-700);
  isolation: isolate;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 104px);
  mask-image: linear-gradient(180deg, transparent 0, #000 104px);
}
/* L'image et le voile de couleur sont DEUX couches soeurs : un `filter` posé
   sur le parent s'appliquerait au groupe entier et annulerait le multiply du
   voile (le pied de page repartait en gris). */
.footer-drape::before {
  content: "";
  position: absolute;
  inset: 0;
  /* cadrée par le haut, mais décalée de 3 % : la tringle sombre sort de la
     zone de fondu, qui virait au gris sale au contact du crème */
  background: url("../img/drapery.webp") center 3% / cover no-repeat;
  filter: grayscale(1) brightness(1.42) contrast(1.02);
}
/* Voile bordeaux : il tient le contraste AA du texte crème ET ramène la
   draperie dans la palette. Sans lui l'image tire vers le brun-caramel,
   seule matière du site à sortir du bordeaux / crème / olive. */
.footer-drape::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, var(--wine-500) 0%,
              var(--wine-ground-2) 46%, var(--wine-700) 100%);
  mix-blend-mode: multiply;
}
.footer-body {
  position: relative;
  z-index: 1;
  padding: var(--s-9) var(--gutter) calc(var(--navbar-h) + var(--s-7));
}
/* Seconde couche, centrée sur la colonne de texte : en `cover`, le cadrage de
   la draperie tombe selon la largeur sur des plis très clairs et le voile plat
   ne suffit plus. Ce halo tient le contraste AA à toutes les largeurs. */
.footer-body::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(72% 52% at 50% 58%, rgba(36, 10, 19, 0.30), transparent 74%);
}
.footer-withlove {
  margin: 0 0 var(--s-5);
  font-family: var(--display);
  font-variant: small-caps;
  font-size: 14px;
  letter-spacing: 0.34em;
  text-indent: 0.34em;
  color: var(--cream-050);
  text-shadow: 0 1px 2px rgba(30, 16, 14, 0.55);
}
body[data-lang="he"] .footer-withlove { font-variant: normal; letter-spacing: 0.1em; text-indent: 0; }
/* l'ovale au double filet qui entoure le monogramme */
.footer-oval {
  position: relative;
  display: grid;
  place-items: center;
  width: 148px;
  height: 186px;
  margin: 0 auto var(--s-5);
  border: 1px solid rgba(250, 245, 238, 0.85);
  border-radius: 50%;
}
.footer-oval::before {
  content: "";
  position: absolute;
  inset: 6px;
  border: 1px solid rgba(250, 245, 238, 0.55);
  border-radius: 50%;
}
/* Le monogramme occupe un peu plus de la moitié de la largeur de l'ovale,
   comme dans la référence ; le glyphe entrelacé pèse à gauche, d'où le
   décalage optique de 2 px. */
/* 3 px vers le bas : l'encre du glyphe pèse en haut, le centrage
   géométrique le faisait donc lire trop haut dans l'ovale. */
.footer-mono { width: 88px; margin: 0; opacity: 1; transform: translateY(3px); }
/* Deux petites fioritures interrompent le filet aux pôles 12 h et 6 h */
.oval-tip {
  position: absolute;
  left: 50%;
  width: 7px;
  height: 7px;
  background: var(--cream-050);
  transform: translateX(-50%) rotate(45deg);
}
.oval-tip--top { top: -4px; }
.oval-tip--bottom { bottom: -4px; }
.footer-mazal {
  font-family: var(--display);
  font-style: italic;
  /* 24 px : au-dessous, « Mazal Tov » n'est pas du « large text » au sens
     WCAG et doit tenir 4,5:1 comme du texte courant. */
  font-size: 24px;
  color: var(--cream-050);
  text-shadow: 0 1px 2px rgba(30, 16, 14, 0.55);
  margin: 0 0 var(--s-4);
}
.footer-contact {
  max-width: 30rem;
  margin: 0 auto var(--s-5);
  font-family: var(--display);
  font-variant: small-caps;
  font-size: 15px;
  letter-spacing: 0.14em;
  line-height: 1.9;
  color: var(--cream-050);
  text-shadow: 0 1px 2px rgba(30, 16, 14, 0.55);
}
/* Le moyen de joindre les mariés, en clair comme dans la référence */
.footer-mail {
  display: inline-block;
  margin: calc(var(--s-2) * -1) 0 var(--s-5);
  font-family: var(--display);
  font-size: 16px;
  letter-spacing: 0.06em;
  color: var(--cream-050);
  text-shadow: 0 1px 2px rgba(30, 16, 14, 0.55);
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 1px;
  unicode-bidi: isolate;
  direction: ltr;
  overflow-wrap: anywhere;
}
body[data-lang="he"] .footer-contact { font-variant: normal; letter-spacing: 0.04em; }

/* --- 18. Révélations au scroll ------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translate3d(0, 18px, 0);
  transition: opacity 760ms var(--e-out), transform 760ms var(--e-out);
  transition-delay: calc(var(--d, 0) * 90ms);
}
.reveal.is-in { opacity: 1; transform: translate3d(0, 0, 0); }

/* --- 19. Grands écrans --------------------------------------------------- */
@media (min-width: 768px) {
  body { font-size: 18px; }
  .events { gap: var(--s-8); }
  .event { display: grid; grid-template-columns: 1fr 1fr; align-items: stretch; text-align: start; }
  .event-figure { aspect-ratio: auto; height: 100%; min-height: 340px; }
  .event:nth-child(even) .event-figure { order: 2; }
  .event-body { padding: var(--s-7); display: grid; align-content: center; }
  /* Un seul axe : tout le bloc texte s'aligne au fer, méta et boutons compris */
  .event-body,
  .event-meta,
  .event-note,
  .event-body .rule { text-align: start; margin-inline: 0; }
  .event-actions { justify-content: flex-start; }
  .event-body .btn { justify-self: start; }
  .event-body .link-quiet { justify-self: start; text-align: start; }
  /* L'illustration court jusqu'au bord de l'écran, et son masque fond aussi
     latéralement : plus d'arête vive au milieu de la page. */
  /* Marge LOGIQUE, pas physique : en hébreu les colonnes s'inversent, et la
     marge droite négative faisait saigner la vignette… sur la colonne de
     texte, qui disparaissait dessous. inline-end saigne toujours vers le
     bord de l'écran, quel que soit le sens de lecture. */
  .event-figure {
    width: 50vw;
    max-width: none;
    margin: 0;
    margin-inline-end: calc(50% - 50vw);
  }
  .event-figure {
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 12%, #000 88%, transparent 100%),
                        linear-gradient(to right, transparent 0%, #000 12%, #000 100%);
    mask-image: linear-gradient(to bottom, transparent 0%, #000 12%, #000 88%, transparent 100%),
                linear-gradient(to right, transparent 0%, #000 12%, #000 100%);
    -webkit-mask-composite: source-in;
    mask-composite: intersect;
  }
  /* même logique pour le fondu latéral : il regarde vers le texte */
  body[data-lang="he"] .event-figure {
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 12%, #000 88%, transparent 100%),
                        linear-gradient(to left, transparent 0%, #000 12%, #000 100%);
    mask-image: linear-gradient(to bottom, transparent 0%, #000 12%, #000 88%, transparent 100%),
                linear-gradient(to left, transparent 0%, #000 12%, #000 100%);
  }
  .navbar { gap: var(--s-2); padding-bottom: calc(8px + env(safe-area-inset-bottom)); }
  .nav-item { max-width: 120px; }

  /* Un formulaire de 760 px de large est un tableau, pas un carton : le nom
     s'étalait sur toute la largeur et le stepper se retrouvait à 600 px de
     son libellé. Tout le bloc de réponse tient dans une colonne de carte. */
  /* Une seule colonne de 30 rem : les filets des compteurs, le cartouche et
     le nom de l'invité s'alignent sur les mêmes deux bords, et le stepper ne
     s'éloigne jamais de son événement. */
  .form,
  .counters,
  #s-rsvp .rsvp-hello,
  #s-rsvp .rsvp-name { max-width: 30rem; margin-inline: auto; width: 100%; }
  .counter { grid-template-columns: minmax(0, 1fr) auto; }
}

@media (min-width: 1024px) {
  .section-inner { max-width: 760px; }
  .events { max-width: 960px; margin-inline: auto; }
  .faire-part { max-width: 36rem; }
  .fp-lead { max-width: 30rem; }
}

/* --- 20. Accessibilité motrice ------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .reveal { opacity: 1; transform: none; }
  .envelope-screen { transition: opacity 200ms linear; }
  /* sans ça le bouquet resterait 2,2 s derrière la poche avant de repasser
     au premier plan, alors que tout le reste est déjà en place */
  body.is-unpacking .clg { transition-delay: 0s !important; }
}

/* --- 21. Impression ------------------------------------------------------ */
@media print {
  .navbar, .utility, .envelope-screen, .hero-scroll, .btn,
  .footer-again, .link-quiet, #bench-badge { display: none !important; }
  body { background: #fff; }
  .section, .footer { background: #fff !important; page-break-inside: avoid; }
  /* Sans cette règle, les textes crème des sections bordeaux
     s'impriment en blanc sur blanc. */
  .section, .section *, .footer, .footer * { color: #000 !important; }
  .event-figure img { filter: none; }
}

/* --- 22. Emplacements photo ---------------------------------------------- */
.photo-slot { position: relative; }

.photo-slot.is-empty {
  display: grid;
  place-items: center;
  background:
    linear-gradient(158deg, var(--cream-200), var(--cream-300)),
    var(--cream-200);
  color: var(--sand-500);
}
.photo-slot.is-empty::before {
  content: "";
  position: absolute;
  inset: 10px;
  border: 1px solid rgba(183, 156, 119, 0.34);
  border-radius: inherit;
  pointer-events: none;
}
.photo-slot .slot-ornament { width: 96px; display: block; opacity: 0.75; }
.photo-slot.has-fallback img,
.photo-slot.has-photo img,
.photo-slot.has-photo video { width: 100%; height: 100%; object-fit: cover; display: block; }
.hero-photo.has-fallback img { object-position: center 34%; }

/* Emplacement du chapitre I : format paysage, encadré */
#s-invitation .photo-slot {
  width: min(100%, 460px);
  margin: var(--s-7) auto var(--s-4);
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: none;
}
/* Le fondu court aussi sur les côtés : pas d'arête vive de rectangle
   sur le bordeaux, comme un tirage collé sans cadre. */
#s-invitation .photo-slot img {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 24%, #000 76%, transparent 100%),
                      linear-gradient(to right, transparent 0%, #000 8%, #000 92%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 24%, #000 76%, transparent 100%),
              linear-gradient(to right, transparent 0%, #000 8%, #000 92%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
  opacity: 0.9;
}
#s-invitation .photo-slot img { width: 100%; height: 100%; object-fit: cover; }
#s-invitation .photo-slot.is-empty {
  background: rgba(253, 251, 247, 0.05);
  color: var(--rose-300);
}
#s-invitation .photo-slot.is-empty::before { border-color: rgba(238, 223, 219, 0.28); }

.hero-photo.is-empty { background: linear-gradient(158deg, var(--cream-200), var(--cream-300)); }


/* --- 23. Compléments ------------------------------------------------------ */
.mono-holder { display: block; }
.mono-holder svg { width: 100%; height: 100%; display: block; }
.mono--duo .mono-l { fill: var(--sand-400); }
.mono--duo .mono-j { fill: var(--wine-700); }
/* Sur le bordeaux, le L prend le rose poudré et le J le crème :
   sans ces deux valeurs, le monogramme se lit comme une seule lettre. */
/* Dans l'ovale du pied de page, le monogramme est d'un seul blanc, comme
   le modèle ; sur les sections bordeaux, il reste bicolore. */
.section--wine .mono--duo .mono-l { fill: var(--rose-400); }
.section--wine .mono--duo .mono-j { fill: var(--cream-050); }
/* Bicolore : d'un seul blanc, les deux lettres se lisaient comme un seul
   glyphe illisible. Le L garde le crème, le J passe au rose poudré — les deux
   sont dans la palette et se séparent nettement sur le bordeaux. */
.footer-mono .mono-l { fill: var(--cream-050); }
.footer-mono .mono-j { fill: var(--sand-400); }
.footer-mono svg { fill: var(--cream-050); }
/* un halo très doux décolle le monogramme de la draperie */
.footer-mono svg { filter: drop-shadow(0 2px 10px rgba(36, 10, 19, 0.55)); }
.hero-mono { color: var(--wine-700); }
.env-seal .mono svg { fill: currentColor; }

.hotel-name { display: grid; gap: 2px; min-width: 0; overflow-wrap: anywhere; text-align: start; }
/* Adresse et distance à pied : sans elles, quatre lignes rigoureusement
   identiques et l'invité doit ouvrir quatre onglets pour choisir. */
.hotel-sub {
  font-family: var(--label);
  font-size: 11.5px;
  letter-spacing: 0.12em;
  line-height: 1.5;
  color: var(--ink-label-on-wine);
}
.hotel-district {
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-label-on-wine);
  margin: 0 0 var(--s-3);
}
.promo-label {
  font-family: var(--label);
  font-size: 11.5px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-label-on-wine);
  margin: 0;
}
.counter-people {
  font-family: var(--label);
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-label);
  margin-top: 3px;
}
.counter.is-on .counter-people { color: var(--wine-700); }

.counters { border: 0; margin: 0; padding: 0; }
.counters:focus { outline: none; }          /* − à gauche, + à droite, dans les deux langues */
.decline { position: relative; }
textarea.input { resize: none; overflow: hidden; }

.footer-mazal-2 {
  display: block;
  font-family: var(--hebrew);
  font-style: normal;
  font-size: 20px;
  color: var(--cream-200);
  text-shadow: 0 1px 2px rgba(30, 16, 14, 0.55);
  margin-top: 4px;
}
/* Les deux lignes échangent leur langue selon la version du site : la police
   et l'italique doivent suivre le texte, pas la position. L'hébreu n'a pas
   d'italique — sans cela, « מזל טוב » était penché de force. */
body[data-lang="he"] .footer-mazal { font-family: var(--hebrew); font-style: normal; }
body[data-lang="he"] .footer-mazal-2 { font-family: var(--display); font-style: italic; }
.footer-word {
  max-width: 26rem;
  margin: var(--s-5) auto 0;
  font-size: 15.5px;
  font-style: italic;
  line-height: 1.75;
  color: var(--rose-200);
}

.lost { min-height: 100svh; display: grid; align-content: center; }
.lost-mono { width: 74px; margin: 0 auto var(--s-5); color: var(--wine-700); }

body.no-navbar .footer { padding-bottom: calc(var(--s-8) + env(safe-area-inset-bottom)); }
body.no-navbar .hero { padding-bottom: var(--s-8); }

/* Le sélecteur de langue reste atteignable dès le premier écran */
.utility { z-index: 110; }
.utility button { min-height: 44px; }

/* Le בס״ד se place toujours à droite, le sélecteur toujours à gauche */
.hero-bsd { inset-inline-end: auto; right: var(--gutter); left: auto; }

/* Barre de navigation : lisible, jamais tronquée */
.nav-item { min-width: 0; }
.nav-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; font-size: 11px; }
.nav-item.is-active { background: rgba(71, 18, 36, 0.07); }
.navbar { background: rgba(250, 245, 238, 0.97); }

/* Paysage : la couverture ne doit pas coûter trois écrans */
@media (orientation: landscape) and (max-height: 520px) {
  .collage-stage { max-width: 420px; }
}
/* Écran couché : on resserre le V et la typographie, on retire la sortie
   de secours du bas. */
@media (max-height: 560px) {
  .envelope-screen { --v-edge: 30%; --v-tip: 54%; --seal-rest: 74%; }
  .env-flap-face { padding-top: 5vh; gap: 6px; }
  .env-names { font-size: clamp(28px, 8vh, 42px); }
  .env-from { font-size: clamp(12px, 2.4vh, 16px); }
  .env-cta { top: calc(var(--v-tip) + clamp(46px, 11vh, 70px)); font-size: 12px; }
  .env-seal { width: clamp(70px, 17vh, 96px); }
  .env-skip { display: none; }
}


/* --- 24. Robustesse ------------------------------------------------------- */
/* Une adresse latine reste un îlot lu de gauche à droite, même en hébreu :
   sans cela, « 44 rue de la Victoire » s'affiche « rue de la Victoire 44 ». */
.address, .meta-when, .meta-hour, .meta-place, .meta-address,
.hotel-list a, .promo-code { unicode-bidi: isolate; }
.address { direction: ltr; }
[dir="rtl"] .address { text-align: right; }
/* Téléphone et e-mail sont deux îlots latins : ils se lisent de gauche à
   droite mais restent alignés sous leur libellé hébreu, tous les deux du
   même côté (avant, l'un était plaqué à gauche et l'autre à droite). */
[dir="rtl"] #f-phone,
[dir="rtl"] #f-email { direction: ltr; text-align: right; }
[dir="rtl"] #f-phone::placeholder,
[dir="rtl"] #f-email::placeholder { text-align: right; }
[dir="rtl"] .hotel-list svg { transform: scaleX(-1); }

/* L'hébreu ne s'interlettre jamais */
body[data-lang="he"] .hero-scroll,
body[data-lang="he"] .env-hint,
body[data-lang="he"] .promo-label,
body[data-lang="he"] .hotel-sub,
body[data-lang="he"] .counter-people,
body[data-lang="he"] .utility button { letter-spacing: 0.04em; text-transform: none; }
.utility button { letter-spacing: 0.04em; }



/* Focus visible sur la case à cocher, dont l'input est masqué */
.decline:has(input:focus-visible) { outline: 2px solid var(--wine-600); outline-offset: 3px; }
.decline input:focus-visible + .box { outline: 2px solid var(--wine-600); outline-offset: 2px; }
.counters:focus-visible { outline: 2px solid var(--wine-600); outline-offset: 6px; }

/* Lien d'évitement */
.skip-link {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  z-index: 200;
}
.skip-link:focus {
  width: auto; height: auto;
  clip-path: none;
  left: 50%;
  top: 12px;
  transform: translateX(-50%);
  padding: 12px 18px;
  background: var(--wine-700);
  color: var(--cream-050);
  border-radius: var(--r-paper);
  font-family: var(--label);
  font-size: 12px;
  letter-spacing: 0.12em;
}

/* La barre de navigation ne floute plus : à 97 % d'opacité, cela ne se voyait
   pas et coûtait une repeinte à chaque image. */
.navbar {
  background: rgba(250, 245, 238, 0.985);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* L'écran d'ouverture ne peint rien : c'est le rabat et la poche qui couvrent
   l'invitation, et c'est leur écartement qui la découvre. En contraste élevé,
   le bloc ci-dessous rétablit un fond opaque. */
@media (forced-colors: active) {
  .envelope-screen { background: Canvas; forced-color-adjust: none; }
  .envelope-screen::after { display: none; }
  .btn { border: 2px solid ButtonText; }
  .decline .box { color: Canvas; border-color: ButtonText; }
  .decline.is-on .box { color: HighlightText; background: Highlight; }
  .navbar { background: Canvas; }
  .nav-item.is-active { background: Highlight; color: HighlightText; }
  .event-figure::before { display: none; }
  body::before { display: none; }
}


/* --- 25. Corrections issues des essais utilisateurs ----------------------- */

/* La confirmation de copie s'affiche à côté de l'adresse, jamais à sa place */
.copy-tip {
  display: inline-block;
  margin-inline-start: 8px;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  background: var(--olive-600);
  color: var(--cream-050);
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.06em;
  opacity: 0;
  transform: translateY(2px);
  transition: opacity var(--t-base) var(--e-soft), transform var(--t-base) var(--e-soft);
}
.copy-tip.is-on { opacity: 1; transform: translateY(0); }
.address.is-copied { color: var(--olive-600); text-decoration-color: var(--olive-600); }

/* Compteurs mis en cause par le message d'erreur */
.counter.is-flagged { border-color: var(--wine-700); }

/* Récapitulatif de la réponse envoyée */
.done-recap {
  list-style: none;
  margin: 0 0 var(--s-5);
  padding: var(--s-4) var(--s-4);
  display: grid;
  gap: 6px;
  background: var(--cream-050);
  /* même filet or que le cartouche du formulaire : la réponse envoyée reste
     dans le même carton que la réponse à remplir */
  border: 1px solid rgba(138, 106, 69, 0.35);
  border-radius: var(--r-paper);
  font-size: 16.5px;
  color: var(--fg);
}
.done-recap strong { font-weight: 500; color: var(--wine-700); }

/* Ajout à l'agenda : discret, sous les deux boutons d'itinéraire */
.link-quiet {
  display: inline-block;
  margin-top: var(--s-3);
  min-height: 44px;
  padding: 12px 4px 0;
  font-family: var(--label);
  font-size: 12px;
  letter-spacing: 0.12em;
  color: var(--olive-600);
  border-bottom: 1px solid transparent;
}
.link-quiet:hover { border-color: var(--olive-600); }

/* Le sélecteur de langue s'efface quand on lit, revient quand on remonte */
.utility {
  transition: opacity var(--t-base) var(--e-soft), transform var(--t-base) var(--e-soft);
}
/* Aucun bouton ne se pose sur l'enveloppe : le choix de langue et la barre de
   navigation reviennent à l'ouverture, en fondu — sans ce fondu, ils
   apparaissent d'un coup au moment où l'enveloppe s'efface et l'œil ne voit
   plus que ce clignotement. */
body.is-locked .utility { opacity: 0; pointer-events: none; }
.utility, .navbar { transition: opacity 520ms var(--e-soft) 120ms; }
body.is-locked .navbar { opacity: 0; pointer-events: none; }

/* Le sélecteur est atteignable aux deux extrémités : en tête et dans le pied de page. */
.footer .utility { position: static; left: auto; }
.utility button .lang-code {
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.08em;
}

/* Écart entre le verset et le titre du chapitre I */
#s-invitation .section-title { margin-top: var(--s-2); }

/* Les boutons d'une carte ne doivent pas finir sous la barre de navigation */
.event { scroll-margin-bottom: calc(var(--navbar-h) + var(--s-6)); }
.section { scroll-margin-bottom: calc(var(--navbar-h) + var(--s-5)); }

/* Écrans très étroits (zoom 200 %, gros caractères) :
   le compteur passe en deux lignes plutôt que d'écraser son libellé. */
@media (max-width: 360px) {
  .counter { grid-template-columns: minmax(0, 1fr); gap: var(--s-3); }
  .nav-label { white-space: normal; line-height: 1.15; font-size: 10.5px; }
  .nav-item { min-height: 62px; }
  /* À 320 px la tige d'arum venait effleurer le « 6 » de 11.11.2026. La date
     est LE renseignement que l'invité vient chercher : le bouquet descend et
     se resserre pour lui laisser le champ entièrement libre. */
  .clg-floral { width: 54%; right: -24%; bottom: -3%; }
}

/* Carte de secours : visible seulement si le script n'a pas démarré */
.fallback-card {
  position: relative;
  z-index: 1;
  max-width: 30rem;
  margin: 0 auto;
  padding: var(--s-8) var(--gutter);
  text-align: center;
  color: var(--fg);
  font-size: 17px;
  line-height: 1.7;
}
.fallback-title {
  font-family: var(--display);
  font-weight: 300;
  font-size: 34px;
  color: var(--wine-700);
  margin: 0 0 var(--s-4);
}
.fallback-note { color: var(--fg-soft); font-style: italic; margin-top: var(--s-5); }
body.is-ready .fallback-card { display: none; }

/* La barre de navigation ne laisse rien passer au travers */
.navbar { background: var(--cream-100); }


/* --- 26. Faire-part : la mise en page classique --------------------------- */
.faire-part { max-width: 32rem; }
.fp-lead {
  text-wrap: balance;
  hyphens: none;
  overflow-wrap: normal;
  font-size: clamp(17.5px, 1.4vw, 20px);
  line-height: 1.85;
  color: var(--cream-200);
  margin: 0 auto var(--s-5);
  max-width: 26rem;
}
/* Une famille de chaque côté, à TOUTES les largeurs. Le modèle fourni par les
   mariés est lui-même un écran de téléphone et porte bien ses deux colonnes :
   les empiler sous 600 px fait perdre le vis-à-vis, qui est TOUT le sens de
   cette mise en page. C'est le corps qui descend, pas les colonnes qui cassent. */
.fp-families {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: clamp(12px, 4vw, 56px);
  /* une famille tient sur une ligne, l'autre sur trois : la courte se centre
     sur la haute au lieu de rester accrochée en haut */
  align-items: center;
  margin: var(--s-5) 0;
}
.fp-family--her { text-align: start; justify-self: start; }
.fp-family--him { text-align: end;   justify-self: end; }
@media (min-width: 600px) {
  .fp-families {
    grid-template-columns: auto auto;
    justify-content: center;
    column-gap: clamp(28px, 6vw, 80px);
    margin: var(--s-6) 0;
  }
  .fp-families .fp-family { white-space: nowrap; }
}
.fp-families + .fp-lead { margin-top: var(--s-5); }

.fp-family {
  font-family: var(--display);
  /* Chaque foyer tient sur UNE ligne, même dans une colonne de téléphone :
     le corps descend autant qu'il faut — un nom replié se lit mal. */
  font-size: clamp(9.5px, 2.75vw, 21px);
  line-height: 1.75;
  margin: 0;
  letter-spacing: 0.01em;
  /* pas de text-wrap ici : `balance` réactiverait le repli que nowrap interdit */
  white-space: nowrap;
  color: var(--cream-050);
}
/* Les deux prénoms sur UNE ligne, chacun avec son équivalent hébreu dessous —
   c'est la disposition du faire-part papier. */
.fp-couple {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(8px, 2.4vw, 20px);
  font-family: "Pinyon Script", var(--display), cursive;
  font-size: clamp(30px, 9.2vw, 56px);
  line-height: 1.1;
  color: var(--cream-050);
  margin: var(--s-5) 0 var(--s-3);
}
.fp-name { display: flex; flex-direction: column; align-items: center; }
.fp-name-main { line-height: 1.05; }
.fp-name-alt {
  font-family: var(--hebrew);
  font-size: 0.42em;
  line-height: 1.5;
  letter-spacing: 0.02em;
  color: var(--rose-300);
  margin-top: 0.12em;
}
body[data-lang="he"] .fp-name-alt {
  font-family: var(--display);
  font-style: italic;
  font-size: 0.4em;
}
body[data-lang="he"] .fp-couple { font-family: var(--hebrew); font-size: clamp(34px, 10vw, 50px); }
.fp-couple .amp {
  align-self: center;
  font-size: 0.62em;
  line-height: 1;
  color: var(--rose-300);
  margin: 0.06em 0;
}
/* En hébreu, l'esperluette latine n'a pas lieu d'être : un ornement rose */
.fp-couple .amp-ornament { display: block; }
/* en ligne entre les deux prénoms, l'ornement doit rester court */
.fp-couple .amp-ornament svg { width: clamp(38px, 11vw, 62px); height: auto; display: block; margin: 0 auto; }

/* Le point d'arrivée du faire-part : la date, juste sous les prénoms */
.fp-date {
  font-family: var(--display);
  font-size: clamp(24px, 6.4vw, 28px);
  line-height: 1.35;
  color: var(--cream-050);
  margin: 0;
}
.fp-hebrew-date {
  font-family: var(--label);
  font-size: 14px;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  text-transform: uppercase;
  color: var(--ink-label-on-wine);
  margin: 10px 0 0;
}

/* --- 27. Touches d'olivine ------------------------------------------------ */
.event-badge, .link-quiet { color: var(--olive-600); }
.section--wine .rule--olive { color: var(--olive-300); }
.footer-date { color: var(--ink-label-on-wine); }
.done-mark { color: var(--olive-600); }
.counter.is-on { border-bottom-color: var(--olive-500); }
.btn--ghost:hover { border-color: var(--olive-600); color: var(--olive-700); }

.counter-sub { font-variant-numeric: lining-nums; }

/* Revenir à l'invitation : le lien souligné du modèle */
.footer-again {
  display: inline-block;
  margin-top: var(--s-2);
  min-height: 44px;
  padding: 12px var(--s-3) 0;
  font-family: var(--display);
  font-variant: small-caps;
  font-size: 15px;
  letter-spacing: 0.22em;
  text-indent: 0.22em;
  color: var(--cream-050);
  text-shadow: 0 1px 2px rgba(30, 16, 14, 0.55);
  text-decoration: underline;
  text-underline-offset: 5px;
  text-decoration-thickness: 1px;
  transition: color var(--t-base) var(--e-soft);
}
.footer-again:hover { color: var(--cream-050); }
body[data-lang="he"] .footer-again { font-variant: normal; letter-spacing: 0.06em; text-indent: 0; }


/* Mouvement réduit : l'enveloppe est là, elle s'efface au lieu de pivoter */
.envelope-screen.is-still .env-flap,
.envelope-screen.is-still .env-pocket,
.envelope-screen.is-still .env-seal { transition: none; }
.envelope-screen.is-still.is-gone { transition: opacity 260ms linear, visibility 260ms; }

/* --- 29. Collage : proportions sur tablette et desktop --------------------- */
@media (min-width: 768px) {
  .collage-stage { max-width: 620px; }
  .clg-floral { width: 52%; right: -28%; bottom: -3%; }
  .clg-peony { left: -10%; }
  /* comme dans la vidéo desktop : la poche court d'un bord à l'autre */
  .clg-pocket {
    left: 50%;
    right: auto;
    width: 100vw;
    transform: translateX(-50%);
  }
}
@media (min-width: 1024px) {
  /* La vidéo est un écran large : le paquet garde ses proportions de carte,
     centré, la poche pleine largeur ; les fleurs ne couvrent pas les noms. */
  .collage-stage { max-width: 680px; }
  .clg-floral { width: 46%; right: -32%; bottom: -4%; }
  /* remonté : à cette largeur le napperon plongeait sous la poche et la date
     se retrouvait coupée par le velours */
  .clg-doily { width: 46%; left: 26%; top: 44%; }
  .clg-date { top: 45%; }
  .clg-card { height: 48%; }
}
