/* ==========================================================================
   Save the Date — la pochette

   Organisation :
     0. Polices
     1. Jetons (couleurs, géométrie de la scène)
     2. Base
     3. Enveloppe : pochette à deux volets, découpée dans une photo
     4. Carte
     5. CTA
     6. Animation (états `.js`, `.is-animating`, `.is-final`)
     7. Accessibilité — mouvement réduit

   Toute la géométrie dérive d'un seul jeton, `--u` : la composition entière
   se redimensionne d'un nombre, de 320 px de large jusqu'au desktop.
   ========================================================================== */

/* --- 0. Polices (auto-hébergées) ---------------------------------------

   Cormorant Garamond et Pinyon Script (SIL Open Font License 1.1), sous-ensemble
   latin servi par Google Fonts. Hébergées ici plutôt que chez un tiers : un
   aller-retour réseau en moins au premier rendu, aucune dépendance externe pour
   un lien ouvert depuis WhatsApp, et un rendu identique partout.
   ---------------------------------------------------------------------- */

@font-face {
  font-family: 'Cormorant Garamond';
  font-style: normal;
  font-weight: 400 600; /* fonte variable : une seule requête pour toutes les graisses */
  font-display: swap;
  src: url('../fonts/cormorant-garamond-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Pinyon Script';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/pinyon-script-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --- 1. Jetons ---------------------------------------------------------- */

:root {
  --bg: #f3eee5;

  /* Encres.
     L'orange #b25c34 et le vert #7a8470 de la charte n'atteignent le contraste
     AA que sur les grands textes, face au papier réel de la carte (≈ #e5e2d9) :
       terracotta        3,62:1  « Mariage », les prénoms (grand texte, min. 3:1)
       sage              3,02:1  « SAVE THE DATE » et la date — d'où leurs
                                 tailles, qui les qualifient comme grand texte
       terracotta-deep   4,53:1  texte courant (min. 4,5:1)
       sage-deep         4,56:1  fond du CTA, face à l'ivoire #fbf7f0 */
  --terracotta: #b25c34;
  --terracotta-deep: #9b502d;
  --sage: #7a8470;
  --sage-deep: #6b7463;

  /* Ombres : une seule teinte chaude, jamais du noir pur. */
  --shade: 74 58 43;

  /* Zones sûres iPhone (encoche, barre d'accueil). */
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);

  /* Hauteur utile de la scène — `svh` évite le saut des barres mobiles. */
  --stage-h: calc(100vh - var(--safe-t) - var(--safe-b));

  /* Unité de base. Carte et pochette en dérivent toutes deux, ce qui permet
     d'exprimer leur rapport d'échelle par un nombre pur (`--card-tucked`) :
     une division entre deux longueurs serait invalide en CSS.
       carte     109 × 184.75 u  (rapport 0.590, celui du visuel fourni)
       pochette  100 × 134.23 u  (rapport 0.745, celui de la photo) */
  --u: max(1.6px, min(0.7706vw, 3.119px, calc((var(--stage-h) - 56px) / 196)));

  /* Espace entre le bas du carton et le bouton. */
  --cta-gap: calc(var(--u) * 7);

  --card-w: calc(var(--u) * 109);
  --card-h: calc(var(--u) * 184.75);
  --env-w: calc(var(--u) * 100);
  --env-h: calc(var(--u) * 134.23);

  /* Échelle de la carte tant qu'elle est dans la pochette : 96 % de la hauteur
     intérieure, donc entièrement masquée par les volets fermés. */
  --card-tucked: 0.6975;

  /* Rythme de la séquence. Toutes les durées et tous les retards ci-dessous
     sont multipliés par ce seul nombre : 1 = 4,6 s au total, 1.6 = 7,4 s.
     C'est le seul réglage à toucher pour accélérer ou ralentir l'ouverture. */
  --tempo: 1.6;
}

@supports (height: 100svh) {
  :root {
    --stage-h: calc(100svh - var(--safe-t) - var(--safe-b));
  }
}

/* --- 2. Base ------------------------------------------------------------ */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  min-height: 100%;
  background: var(--bg);
  color: var(--terracotta);
  font-family: 'Cormorant Garamond', Garamond, 'Times New Roman', serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

h1,
p {
  margin: 0;
}

/* --- 3. Enveloppe ------------------------------------------------------- */

.scene {
  display: grid;
  place-items: center;
  height: var(--stage-h);
  margin-top: var(--safe-t);
  margin-bottom: var(--safe-b);
}

.stack {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--cta-gap);
}

/* Repère de l'enveloppe : exactement le gabarit de la carte. Les pièces de la
   pochette, plus petites, s'y centrent ; les volets ouverts en débordent
   librement, rien ne les rogne. */
.stage {
  position: relative;
  width: var(--card-w);
  height: var(--card-h);
}

/* Fond de la pochette : ce qu'on découvre quand les volets s'écartent. */
.envelope__inside {
  position: absolute;
  inset: 0;
  margin: auto;
  z-index: 1;
  width: var(--env-w);
  height: var(--env-h);
  background: #e3ded2 url('../img/paper.webp') center / cover;
  box-shadow:
    inset 0 0 calc(var(--u) * 9) rgb(var(--shade) / 0.16),
    0 calc(var(--u) * 2) calc(var(--u) * 5) rgb(var(--shade) / 0.1),
    0 calc(var(--u) * 7) calc(var(--u) * 16) rgb(var(--shade) / 0.13);
}

/* Un volet = trois niveaux.
   `.envelope__flap` place et fait disparaître (2D) · `.envelope__hinge` porte
   la perspective · `.envelope__pivot` tourne. Appliquer l'opacité directement
   sur le contexte 3D l'aplatirait et casserait les faces avant/arrière. */
.envelope__flap {
  position: absolute;
  z-index: 3;
  top: calc(50% - var(--u) * 67.115);
  height: var(--env-h);
}

.envelope__flap--left {
  left: calc(50% - var(--u) * 50);
  width: calc(var(--u) * 50.14);
}

.envelope__flap--right {
  left: calc(50% + var(--u) * 0.14);
  width: calc(var(--u) * 49.86);
}

.envelope__hinge {
  width: 100%;
  height: 100%;
  perspective: calc(var(--u) * 300);
}

/* Le point de fuite est placé sur la couture, au centre de la composition :
   les deux battants convergent alors vers le regard, et non chacun vers soi. */
.envelope__flap--left .envelope__hinge {
  perspective-origin: 100% 50%;
}

.envelope__flap--right .envelope__hinge {
  perspective-origin: 0% 50%;
}

.envelope__pivot {
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
}

.envelope__flap--left .envelope__pivot {
  transform-origin: left center;
}

.envelope__flap--right .envelope__pivot {
  transform-origin: right center;
}

.envelope__face {
  position: absolute;
  inset: 0;
  display: block;
  backface-visibility: hidden;
  box-shadow: 0 calc(var(--u) * 1.5) calc(var(--u) * 4) rgb(var(--shade) / 0.12);
}

/* Extérieur : la photo elle-même, à son cadrage exact. */
.envelope__flap--left .envelope__face--out {
  background: url('../img/flap-left.webp') center / 100% 100% no-repeat;
}

.envelope__flap--right .envelope__face--out {
  background: url('../img/flap-right.webp') center / 100% 100% no-repeat;
}

/* Intérieur : le papier nu, dans l'ombre du pli. */
.envelope__face--in {
  transform: rotateY(180deg);
  background: #ded8cb url('../img/paper.webp') center / cover;
  filter: brightness(0.94);
}

/* Sceau de cire : posé à cheval sur la couture, aux coordonnées relevées sur
   la photo d'origine (`scripts/build-images.py`). */
.envelope__seal {
  position: absolute;
  z-index: 4;
  left: calc(50% + var(--u) * 0.68);
  top: calc(50% + var(--u) * 2.46);
  width: calc(var(--u) * 29.23);
  height: calc(var(--u) * 34.72);
  margin-left: calc(var(--u) * -14.6);
  margin-top: calc(var(--u) * -17.36);
  background: url('../img/seal.webp') center / contain no-repeat;
}

/* --- 4. Carte ----------------------------------------------------------- */

.card {
  position: absolute;
  inset: 0;
  z-index: 2;
  overflow: hidden;
  background: #f2eee5 url('../img/paper.webp') center / cover;
  box-shadow:
    0 1px 2px rgb(var(--shade) / 0.07),
    0 calc(var(--u) * 3) calc(var(--u) * 7) rgb(var(--shade) / 0.1),
    0 calc(var(--u) * 8) calc(var(--u) * 18) rgb(var(--shade) / 0.09);
  /* Toute la typographie de la carte est exprimée en `em` : le contenu suit
     la carte au pixel près, à toutes les tailles d'écran. */
  font-size: calc(var(--u) * 7.032);
}

.card__body {
  position: relative;
  height: 100%;
  /* Marges hautes et basses en `em`, pas en pourcentage : un pourcentage de
     padding se calcule sur la LARGEUR du bloc, même en haut et en bas. */
  padding: 2em 5.5%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}

/* Aucun bloc ne se comprime : sur un écran étroit, mieux vaut que la mesure
   reste juste que de voir le texte s'écraser. */
.card__body > * {
  flex: none;
}

.card__title {
  margin-top: 2.5em;
  font-size: 1em; /* annule le 2em par défaut de <h1> */
  display: flex;
  flex-direction: column;
  align-items: center;
  font-weight: 400;
}

.card__script {
  font-family: 'Pinyon Script', 'Cormorant Garamond', cursive;
  font-size: 3.19em;
  line-height: 0.95;
  color: var(--terracotta);
  /* La script déborde à gauche du fait de son inclinaison : on recentre. */
  padding-inline: 0.08em;
}

.card__names {
  /* La queue du « g » de Pinyon Script descend largement sous sa ligne : les
     prénoms se logent dans cet espace, juste sous elle. */
  margin-top: 0.62em;
  font-size: 1.375em;
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: 0.01em;
  color: var(--terracotta);
}

.card__kicker {
  color: var(--sage);
  font-size: 1.27em;
  font-weight: 600;
  line-height: 1.1;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  /* Compense l'espacement ajouté après la dernière lettre. */
  text-indent: 0.1em;
}

.card__date {
  margin-top: 1.44em;
  font-size: 2.20em;
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: 0.005em;
  color: var(--sage);
  /* Chiffres bas de casse par défaut dans Cormorant Garamond : les chiffres
     capitales, tous de même hauteur, sont ceux du visuel de référence. */
  font-variant-numeric: lining-nums;
}

/* --- 5. CTA ------------------------------------------------------------- */

.cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.62em;
  min-height: 44px; /* cible tactile */
  padding: 0.82em 1.5em;
  border-radius: 20px;
  background: var(--sage-deep);
  color: #fbf7f0;
  /* Le bouton est une commande, pas de la papeterie : une sans serif système
     le distingue du carton, et ne coûte aucun octet à télécharger. */
  font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto,
    'Helvetica Neue', Arial, sans-serif;
  /* Il n'est plus sur le papier : sa taille se règle sur la carte (`--u`) et
     non plus sur la typographie de celle-ci. Une sans serif paraissant plus
     grande qu'une serif à taille égale, elle est un cran en dessous. */
  font-size: calc(var(--u) * 5.45);
  font-weight: 500;
  letter-spacing: 0.015em;
  text-decoration: none;
  box-shadow: 0 2px 6px rgb(var(--shade) / 0.14);
  transition: background-color 180ms ease, transform 180ms ease;
}

.cta__icon {
  width: 1.22em;
  height: 1.22em;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
}

.cta__icon circle {
  fill: currentColor;
  stroke: none;
}

@media (hover: hover) {
  .cta:hover {
    background: #5c6455;
  }
}

.cta:active {
  transform: translateY(1px);
}

.cta:focus-visible {
  outline: 2px solid var(--terracotta);
  outline-offset: 3px;
}

.cta-fallback {
  max-width: var(--card-w);
  font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto,
    'Helvetica Neue', Arial, sans-serif;
  font-size: calc(var(--u) * 5);
  line-height: 1.45;
  text-align: center;
  color: var(--terracotta-deep);
}

.cta-fallback a {
  color: inherit;
}

/* --- 6. Animation ------------------------------------------------------- */

/* Sans JavaScript, la page est directement dans son état final : la carte est
   centrée, lisible et le CTA fonctionne. La pochette n'existe que pendant
   l'animation. */
.envelope__part {
  display: none;
}

.js.is-animating .envelope__part {
  display: block;
}

/* Repli pour les navigateurs sans `inert` : la carte ne reçoit ni clic ni
   survol tant que les volets la cachent. */
.js.is-animating:not(.is-final) .card {
  pointer-events: none;
}

/* Le cachet cède, se soulève, puis se détache. */
@keyframes seal-break {
  0% {
    transform: none;
    opacity: 1;
  }
  35% {
    transform: translate3d(0, -1.6%, 0) scale(1.03) rotate(-2deg);
    opacity: 1;
  }
  100% {
    transform: translate3d(0, 13%, 0) scale(0.95) rotate(-5.5deg);
    opacity: 0;
  }
}

/* Les deux battants s'ouvrent vers l'extérieur, bord libre vers le regard. */
@keyframes flap-left-open {
  from {
    transform: rotateY(0deg);
  }
  to {
    transform: rotateY(-150deg);
  }
}

@keyframes flap-right-open {
  from {
    transform: rotateY(0deg);
  }
  to {
    transform: rotateY(150deg);
  }
}

@keyframes envelope-fade {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

/* La carte ne sort pas de la pochette : elle y est montée, on la découvre,
   puis elle grandit jusqu'à occuper l'écran. */
@keyframes card-grow {
  from {
    transform: scale(var(--card-tucked));
  }
  to {
    transform: scale(1);
  }
}

@keyframes cta-in {
  from {
    opacity: 0;
    transform: translateY(calc(var(--u) * 3));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Chronologie, en millisecondes de base — à multiplier par `--tempo`
   (1.6 par défaut, soit les valeurs entre parenthèses) :
     0–900      pochette fermée, sceau intact          (0–1,4 s)
     900–1500   le cachet cède et se détache           (1,4–2,4 s)
     1400–2700  le volet gauche s'ouvre                (2,2–4,3 s)
     1520–2820  le volet droit suit, légèrement décalé (2,4–4,5 s)
     2750–3650  la pochette s'efface                   (4,4–5,8 s)
     3200–4600  la carte grandit et prend l'écran      (5,1–7,4 s)
     3900–4600  le bouton apparaît sous le carton      (6,2–7,4 s)
     4600       état final, définitif                  (7,4 s) */
.js.is-animating .envelope__seal {
  animation: seal-break calc(600ms * var(--tempo)) cubic-bezier(0.3, 0, 0.3, 1)
    calc(900ms * var(--tempo)) both;
}

.js.is-animating .envelope__flap--left .envelope__pivot {
  animation: flap-left-open calc(1300ms * var(--tempo)) cubic-bezier(0.4, 0.02, 0.3, 1)
    calc(1400ms * var(--tempo)) both;
  will-change: transform;
}

.js.is-animating .envelope__flap--right .envelope__pivot {
  animation: flap-right-open calc(1300ms * var(--tempo)) cubic-bezier(0.4, 0.02, 0.3, 1)
    calc(1520ms * var(--tempo)) both;
  will-change: transform;
}

.js.is-animating .envelope__inside,
.js.is-animating .envelope__flap {
  animation: envelope-fade calc(900ms * var(--tempo)) ease calc(2750ms * var(--tempo)) both;
}

.js.is-animating .cta {
  animation: cta-in calc(700ms * var(--tempo)) ease calc(3900ms * var(--tempo)) both;
}

.js.is-animating .card {
  animation: card-grow calc(1400ms * var(--tempo)) cubic-bezier(0.33, 0, 0.2, 1)
    calc(3200ms * var(--tempo)) both;
  will-change: transform;
}

/* État final : plus aucune animation en cours, plus rien à composer.
   Les valeurs correspondent exactement à la dernière image de la séquence :
   le passage est invisible. */
.js.is-final .envelope__part {
  display: none;
}

.js.is-final .card,
.js.is-final .cta {
  animation: none;
  will-change: auto;
}

/* --- 7. Mouvement réduit ------------------------------------------------ */

/* Le JavaScript n'arme jamais la séquence dans ce cas ; cette règle est un
   garde-fou si la préférence change en cours de route. */
@media (prefers-reduced-motion: reduce) {
  .js.is-animating .envelope__part {
    display: none;
  }

  .js .card,
  .js .cta,
  .js .envelope__part,
  .js .envelope__pivot,
  .js .envelope__seal {
    animation: none !important;
  }

  .cta {
    transition: none;
  }
}
