/* Fonts are linked from each page before this file — see fonts.css. */

/*
      ██████╗     ██╗    ███╗   ███╗          Vous lisez la feuille de style.
     ██╔════╝    ██╔╝    ████╗ ████║          Sincèrement : bravo.
     ╚█████╗    ██╔╝     ██╔████╔██║
      ╚═══██╗  ██╔╝      ██║╚██╔╝██║          4 œufs de Pâques sont cachés ici.
     ██████╔╝ ██╔╝       ██║ ╚═╝ ██║          Console → mariage.help()
     ╚═════╝  ╚═╝        ╚═╝     ╚═╝

     15 · 05 · 2027 — Quesnoy-sur-Deûle & Wambrechies
*/

/* ─── Design tokens ─── */
:root {
  /* Brand navy ramp */
  --navy-950:   #12244a;
  --dark:       #1e3a6e;
  --navy-600:   #35548c;
  --muted:      #5b6f95;
  --line:       #dde5f5;
  --cream:      #f4f7fd;
  --card-bg:    #ffffff;
  --white:      #ffffff;

  /* Gold — --gold is decorative (large type, rules, icons).
     --gold-ink is the only gold safe for small text: 5.2:1 on white. */
  --gold:       #c9a227;
  --gold-ink:   #856a15;
  --gold-light: #dfc05a;
  --gold-wash:  rgba(201, 162, 39, 0.10);

  /* On-navy text */
  --on-navy:      #e8eef8;
  --on-navy-soft: #b6c3d9;

  /* Fluid type scale */
  --step--1: clamp(0.78rem, 0.76rem + 0.1vw, 0.84rem);
  --step-0:  clamp(1rem, 0.97rem + 0.15vw, 1.06rem);
  --step-1:  clamp(1.1rem, 1.04rem + 0.3vw, 1.3rem);
  --step-2:  clamp(1.3rem, 1.2rem + 0.5vw, 1.65rem);
  --step-3:  clamp(1.7rem, 1.45rem + 1.1vw, 2.4rem);
  --step-4:  clamp(2.1rem, 1.6rem + 2.3vw, 3.4rem);
  --step-5:  clamp(2.6rem, 1.8rem + 3.6vw, 4.6rem);

  /* Spacing scale */
  --sp-1: 0.25rem; --sp-2: 0.5rem;  --sp-3: 0.75rem; --sp-4: 1rem;
  --sp-5: 1.5rem;  --sp-6: 2rem;    --sp-7: 3rem;    --sp-8: 4rem;
  --sp-9: clamp(4rem, 9vw, 7.5rem);

  /* Layered navy-tinted shadows */
  --shadow-sm: 0 1px 2px rgba(18,36,74,0.04), 0 1px 3px rgba(18,36,74,0.06);
  --shadow-md: 0 2px 4px rgba(18,36,74,0.04), 0 8px 16px -4px rgba(18,36,74,0.08);
  --shadow-lg: 0 4px 8px rgba(18,36,74,0.04), 0 16px 32px -8px rgba(18,36,74,0.10);
  --shadow-xl: 0 8px 16px rgba(18,36,74,0.05), 0 32px 64px -16px rgba(18,36,74,0.14);

  /* Radii */
  --r-sm: 8px; --r-md: 12px; --r-lg: 20px; --r-xl: 28px; --r-full: 999px;

  /* Motion */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 150ms;
  --dur:      250ms;
  --dur-slow: 600ms;
  --transition: var(--dur) var(--ease-out);

  /* Type families */
  --serif:  'Cormorant Garamond', Georgia, serif;
  --script: 'Great Vibes', cursive;
  --sans:   'Inter', system-ui, sans-serif;

  /* Layout */
  --max-w:  1100px;
  --prose:  60ch;
  --gutter: clamp(1.25rem, 5vw, 3rem);
  --nav-h:  72px;
}

/* ─── Reset & base ─── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--sans);
  font-size: var(--step-0);
  line-height: 1.7;
  background: var(--white);
  color: var(--dark);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a {
  color: var(--gold-ink);
  text-decoration: none;
  transition: color var(--transition);
}
a:hover { color: var(--dark); }

img, svg { display: block; max-width: 100%; }

/* Anchor targets clear the fixed nav instead of hiding beneath it. */
[id] { scroll-margin-top: calc(var(--nav-h) + var(--sp-5)); }

/* ─── Focus ─── */
:focus-visible {
  outline: 2px solid var(--gold-ink);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}
.btn:focus-visible,
.nav-rsvp:focus-visible { outline-offset: 4px; }

.skip-link {
  position: absolute;
  left: var(--sp-4);
  top: var(--sp-4);
  z-index: 300;
  padding: var(--sp-3) var(--sp-5);
  background: var(--dark);
  color: var(--white);
  border-radius: var(--r-full);
  font-size: var(--step--1);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transform: translateY(-160%);
  transition: transform var(--transition);
}
.skip-link:focus,
.skip-link:focus-visible { transform: translateY(0); color: var(--white); }

/* ─── Nav ─── */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 200;
  padding: 0 var(--gutter);
}

/* Le fond dépoli de la barre défilée vit sur un pseudo-élément, et il doit
   y rester.
   ⚠️ Ne le remontez pas sur .nav. backdrop-filter fait de l'élément qui le
   porte un bloc conteneur pour ses descendants en position:fixed — or le
   tiroir mobile (.nav-links) en est un, avec top:0 et bottom:0. Posé sur
   .nav, le filtre ne s'applique qu'une fois la page défilée : le tiroir
   passe alors de toute la hauteur de l'écran à celle de la barre (128px),
   et le menu paraît cassé dès qu'on n'est plus en haut de page.
   Un pseudo-élément n'est pas un ancêtre de .nav-links : la chaîne des
   blocs conteneurs reste intacte, et l'effet est identique à l'œil. */
.nav::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  box-shadow: 0 1px 0 var(--line), var(--shadow-sm);
  opacity: 0;
  transition: opacity var(--transition);
}
.nav.scrolled::before { opacity: 1; }
.nav-inner {
  max-width: var(--max-w);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  height: var(--nav-h);
}
.nav-monogram { display: flex; align-items: center; }
.nav-logo {
  height: 46px;
  width: 46px;
  object-fit: contain;
  transition: transform var(--transition);
}
.nav-monogram:hover .nav-logo { transform: scale(1.06); }

/* Gap kept tight on purpose: on index.html the hero splits 50/50, and a wider
   link row pushes the first item left of the photo edge. See the nav note in
   the README before loosening this or lengthening a label. */
.nav-links {
  list-style: none;
  display: flex;
  gap: var(--sp-5);
  align-items: center;
}
.nav-links a {
  position: relative;
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  transition: color var(--transition);
}
/* Colour the plain links only. A bare `.nav-links a` colour rule (0,1,1)
   out-specifies `.nav-rsvp` (0,1,0) and would tint the pill's white text. */
.nav-links a:not(.nav-rsvp) { color: var(--muted); }
/* Underline grows from the centre on hover / current page. */
.nav-links a:not(.nav-rsvp)::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -6px;
  height: 1.5px;
  background: var(--gold);
  transform: scaleX(0);
  transition: transform var(--dur) var(--ease-out);
}
.nav-links a:not(.nav-rsvp):hover,
.nav-links a:not(.nav-rsvp).active { color: var(--dark); }
.nav-links a:not(.nav-rsvp):hover::after,
.nav-links a:not(.nav-rsvp).active::after { transform: scaleX(1); }

.nav-rsvp {
  background: var(--dark);
  color: var(--white);
  padding: 10px 22px;
  border-radius: var(--r-full);
  letter-spacing: 0.14em;
  box-shadow: var(--shadow-sm);
  transition: background var(--transition), color var(--transition),
              box-shadow var(--transition);
}
.nav-rsvp:hover {
  background: var(--navy-950);
  color: var(--white);
  box-shadow: var(--shadow-md);
}
/* Current page: keep the navy pill, mark it with a gold ring rather than
   recolouring it to a muddy olive. */
.nav-rsvp.active {
  background: var(--dark);
  color: var(--white);
  box-shadow: 0 0 0 1.5px var(--gold), var(--shadow-sm);
}

/* Hamburger — hidden until the drawer breakpoint */
.nav-toggle {
  display: none;
  width: 44px; height: 44px;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--dark);
  border-radius: var(--r-sm);
  /* Must sit above the drawer (195), or the open drawer hides the close button */
  position: relative;
  z-index: 196;
}
/* Navy-on-navy would be invisible once the drawer is behind it */
body.nav-open .nav-toggle { color: var(--on-navy); }
.nav-toggle-bars {
  position: relative;
  width: 22px; height: 2px;
  background: currentColor;
  border-radius: 2px;
  transition: background var(--dur-fast) linear;
}
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  content: '';
  position: absolute;
  left: 0;
  width: 22px; height: 2px;
  background: currentColor;
  border-radius: 2px;
  transition: transform var(--dur) var(--ease-out);
}
.nav-toggle-bars::before { top: -7px; }
.nav-toggle-bars::after  { top: 7px; }
/* Bars collapse into an X when open */
.nav-toggle[aria-expanded="true"] .nav-toggle-bars { background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::before { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::after  { transform: translateY(-7px) rotate(-45deg); }

.nav-backdrop {
  position: fixed;
  inset: 0;
  z-index: 190;
  background: rgba(18, 36, 74, 0.45);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur) ease, visibility var(--dur) ease;
}
body.nav-open .nav-backdrop { opacity: 1; visibility: visible; }
body.nav-open { overflow: hidden; }

/* ─── Hero (index) ─── */
.hero {
  position: relative; /* anchors .hero-scroll-hint */
  min-height: 100svh;
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
  overflow: hidden;
}
.hero-photo-wrap {
  position: relative;
  overflow: hidden;
  background: var(--cream);
}
/* Light scrim so the navy monogram stays legible over a dark photo */
.hero-photo-wrap::after {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: calc(var(--nav-h) + 48px);
  background: linear-gradient(rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0));
  pointer-events: none;
}
.hero-photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  /* Scale only — never opacity. The photo must stay visible even if the
     animation never runs. */
  animation: hero-reveal 1.6s var(--ease-out) both;
}
@keyframes hero-reveal {
  from { transform: scale(1.06); }
  to   { transform: scale(1); }
}

.hero-text {
  position: relative;
  padding: calc(var(--nav-h) + var(--sp-6)) var(--gutter) var(--sp-8);
  display: flex;
  flex-direction: column;
  justify-content: center;
  background: var(--white);
}
.hero-text > * { position: relative; }

.hero-logo { margin-bottom: var(--sp-5); }
.hero-logo img {
  height: clamp(72px, 9vw, 104px);
  width: clamp(72px, 9vw, 104px);
  object-fit: contain;
}

.hero-text h1 {
  font-family: var(--script);
  font-size: var(--step-5);
  font-weight: 400;
  line-height: 1.05;
  color: var(--dark);
  margin-bottom: var(--sp-5);
}
.hero-text h1 .ampersand {
  display: block;
  font-family: var(--serif);
  font-style: italic;
  color: var(--gold-ink);
  font-size: 0.46em;
  line-height: 1.35;
}

.hero-date {
  position: relative;
  font-family: var(--serif);
  font-style: italic;
  font-size: var(--step-1);
  color: var(--muted);
  letter-spacing: 0.02em;
  padding-top: var(--sp-5);
  margin-bottom: var(--sp-7);
}
/* Short gold rule, so the date itself is free to run full width */
.hero-date::before {
  content: '';
  position: absolute;
  top: 0; left: 0;
  width: 64px; height: 1px;
  background: var(--gold);
}

.hero-actions { display: flex; gap: var(--sp-3); flex-wrap: wrap; }

.hero-scroll-hint {
  position: absolute;
  bottom: var(--sp-5);
  /* 75% = centre of the right-hand text column, not the column divide */
  left: 75%;
  transform: translateX(-50%);
  display: grid;
  justify-items: center;
  gap: var(--sp-2);
  color: var(--muted);
  font-size: 0.6rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.hero-scroll-hint::after {
  content: '';
  width: 1px; height: 40px;
  background: linear-gradient(var(--gold), transparent);
  animation: scroll-pulse 2.4s var(--ease-out) infinite;
  transform-origin: top;
}
@keyframes scroll-pulse {
  0%, 100% { transform: scaleY(0.4); opacity: 0.4; }
  50%      { transform: scaleY(1);   opacity: 1; }
}

/* ─── Buttons ─── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 48px;
  padding: 0 var(--sp-6);
  border: 1.5px solid transparent;
  border-radius: var(--r-full);
  font-family: var(--sans);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background var(--transition), color var(--transition),
              border-color var(--transition), box-shadow var(--transition);
}
/* Les boutons ne se soulèvent pas au survol. Le décollement de deux pixels
   déplaçait la cible sous le curseur pour ne rien dire de plus que le
   changement de fond et l'ombre qui l'accompagnent déjà — et il n'avait
   aucun sens en mode geek, où il ne reste aucune ombre au-dessus de
   laquelle flotter. Le `:active` qui annulait la lévitation est parti avec
   elle : sans elle, il n'annulait plus rien. */
.btn-primary {
  background: var(--dark);
  color: var(--white);
  box-shadow: var(--shadow-sm);
}
.btn-primary:hover {
  background: var(--navy-950);
  color: var(--white);
  box-shadow: var(--shadow-lg);
}
.btn-outline {
  background: transparent;
  color: var(--dark);
  border-color: var(--line);
}
.btn-outline:hover {
  background: var(--dark);
  color: var(--white);
  border-color: var(--dark);
  box-shadow: var(--shadow-md);
}
.btn:disabled,
.btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  box-shadow: none;
}

/* ─── Sections ─── */
.section { padding: var(--sp-9) var(--gutter); }
.section-inner { max-width: var(--max-w); margin: 0 auto; }
/* Trailing margin would double up with the section's bottom padding */
.section-inner > :last-child { margin-bottom: 0; }

.section-label {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--step--1);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold-ink);
  font-weight: 500;
  margin-bottom: var(--sp-4);
}
.section-label::before {
  content: '';
  width: 28px; height: 1px;
  background: var(--gold);
}

.section h2, .section h1 {
  font-family: var(--serif);
  font-size: var(--step-4);
  font-weight: 300;
  line-height: 1.1;
  letter-spacing: -0.01em;
  margin-bottom: var(--sp-5);
  color: var(--dark);
  text-wrap: balance;
}
.section h2 em, .section h1 em {
  font-family: var(--script);
  font-style: normal;
  font-size: 1.15em;
  /* gold-ink, not gold: this is text and must clear 3:1 at display size */
  color: var(--gold-ink);
  font-weight: 400;
}

.lead {
  font-size: var(--step-1);
  font-weight: 300;
  line-height: 1.65;
  color: var(--muted);
  max-width: var(--prose);
  margin-bottom: var(--sp-7);
  text-wrap: pretty;
}

/* Centred sections need the label rule centred too */
.section-about, .section-countdown, .section-contact { text-align: center; }
.section-about .lead,
.section-countdown .lead,
.section-contact .lead { margin-left: auto; margin-right: auto; }
.section-about .section-label::before,
.section-countdown .section-label::before,
.section-contact .section-label::before { display: none; }

/* ─── About ─── */
.section-about { background: var(--white); }

.about-story {
  max-width: var(--prose);
  margin: 0 auto;
  color: var(--muted);
  line-height: 1.75;
  text-wrap: pretty;
}
.about-story p { margin-bottom: var(--sp-5); }
.about-story p:last-child { margin-bottom: 0; }
.about-story s {
  text-decoration-thickness: 1px;
  text-decoration-color: var(--gold);
  opacity: 0.75;
}
.about-story em {
  font-style: normal;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--dark);
}
.about-aside {
  display: inline-block;
  margin-top: var(--sp-2);
  font-size: var(--step--1);
  opacity: 0.85;
}
.about-signoff {
  font-family: var(--script);
  font-size: var(--step-3);
  line-height: 1.2;
  color: var(--gold-ink);
  padding-top: var(--sp-2);
}

/* ─── Timeline ─── */
.section-schedule { background: var(--cream); }
.timeline {
  list-style: none;
  position: relative;
  margin-top: var(--sp-7);
  max-width: 720px;
}
.timeline::before {
  content: '';
  position: absolute;
  left: 88px;
  top: 8px; bottom: 8px;
  width: 1px;
  background: linear-gradient(var(--gold), var(--line) 70%, transparent);
}
/* gap must stay 0: the rail sits at exactly the column-1 width, so column 2
   has to start there too for the dots to line up on it. */
.timeline-item {
  display: grid;
  grid-template-columns: 88px 1fr;
  align-items: start;
  gap: 0;
  padding-bottom: var(--sp-7);
}
.timeline-item:last-child { padding-bottom: 0; }
.timeline-time {
  text-align: right;
  font-family: var(--serif);
  font-style: italic;
  font-size: var(--step-1);
  color: var(--gold-ink);
  padding-top: 2px;
  padding-right: var(--sp-4);
}
.timeline-content {
  position: relative;
  padding-left: var(--sp-6);
}
/* Dot centred on the rail: half the dot's width to the left of the edge */
.timeline-content::before {
  content: '';
  position: absolute;
  left: -4.5px; top: 11px;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--white);
  border: 1.5px solid var(--gold);
  transition: background var(--transition), transform var(--transition);
}
.timeline-item:hover .timeline-content::before {
  background: var(--gold);
  transform: scale(1.25);
}
.timeline-content strong {
  font-family: var(--serif);
  font-size: var(--step-2);
  font-weight: 600;
  display: block;
  margin-bottom: var(--sp-1);
  color: var(--dark);
}
.timeline-content p { color: var(--muted); }
.timeline-place {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  margin-top: var(--sp-2);
  font-size: var(--step--1);
  letter-spacing: 0.03em;
  color: var(--gold);
}
.timeline-place svg { width: 14px; height: 14px; flex: none; }
/* Trajet entre deux lieux : coupe le rail avec une icône voiture */
.timeline-move { padding-bottom: var(--sp-6); }
.timeline-move .timeline-content { padding-top: 1px; }
.timeline-move .timeline-content::before { display: none; }
.timeline-move-icon {
  position: absolute;
  left: -10px; top: 4px;
  width: 20px; height: 20px;
  color: var(--gold);
  background: var(--white);
  padding: 3px 0;
}
.timeline-move-note {
  font-size: var(--step--1);
  font-style: italic;
  color: var(--muted);
}

/* ─── Venue grid ─── */
.section-venue { background: var(--white); }
.venue-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--sp-5);
}
.venue-card {
  background: var(--card-bg);
  padding: var(--sp-6);
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition), box-shadow var(--transition),
              border-color var(--transition);
}
.venue-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
  border-color: rgba(201, 162, 39, 0.35);
}
.venue-icon {
  display: grid;
  place-items: center;
  width: 46px; height: 46px;
  margin-bottom: var(--sp-4);
  border-radius: var(--r-md);
  background: var(--gold-wash);
  color: var(--gold-ink);
}
.venue-icon svg { width: 22px; height: 22px; }
.venue-card h4 {
  font-family: var(--serif);
  font-size: var(--step-2);
  font-weight: 600;
  margin-bottom: var(--sp-2);
  color: var(--dark);
}
.venue-card p { font-size: var(--step--1); color: var(--muted); line-height: 1.65; }
.venue-card a { font-weight: 500; }

/* ─── Countdown ─── */
.section-countdown {
  position: relative;
  background: var(--dark);
  overflow: hidden;
}
.section-countdown::before {
  content: '';
  position: absolute;
  top: -30%; left: 50%;
  transform: translateX(-50%);
  width: min(760px, 90%); aspect-ratio: 1;
  background: radial-gradient(circle, rgba(223, 192, 90, 0.14), transparent 65%);
  pointer-events: none;
}
.section-countdown .section-inner { position: relative; }
.section-countdown .section-label { color: var(--gold-light); }
.section-countdown h2 { color: var(--white); }

.countdown-boxes {
  display: flex;
  gap: var(--sp-4);
  justify-content: center;
  flex-wrap: wrap;
  margin-top: var(--sp-6);
}
.countdown-box {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--r-lg);
  padding: var(--sp-5) var(--sp-6);
  min-width: 112px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-1);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
/* Required: `display: flex` above out-specifies the UA's `[hidden]` rule, so
   without this the JS-toggled boxes would stay visible. */
.countdown-box[hidden] { display: none; }
.countdown-box span {
  font-family: var(--serif);
  font-size: clamp(2.2rem, 5vw, 3.2rem);
  font-weight: 300;
  /* Cormorant defaults to oldstyle figures, where "1" reads as a small "I".
     Lining figures keep the countdown unambiguous. */
  font-variant-numeric: lining-nums tabular-nums;
  color: var(--white);
  line-height: 1.1;
}
.countdown-box small {
  font-size: 0.66rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--on-navy-soft);
}

/* ─── Contact ─── */
.section-contact { background: var(--cream); }

/* ─── Page hero (hotels / rsvp / contact) ─── */
.page-hero {
  padding: calc(var(--nav-h) + var(--sp-8)) var(--gutter) var(--sp-8);
  text-align: center;
  background: var(--cream);
  border-bottom: 1px solid var(--line);
}
.page-hero .section-inner { max-width: 780px; }
.page-hero h1 {
  font-family: var(--serif);
  font-size: var(--step-4);
  font-weight: 300;
  line-height: 1.1;
  margin-bottom: var(--sp-4);
  color: var(--dark);
  letter-spacing: 0.01em;
}
.page-hero .section-label { color: var(--gold-ink); }
.page-hero .section-label::before { display: none; }
.page-hero .lead { margin: 0 auto; }
/* The page hero already supplies bottom breathing room */
.page-hero + main > .section:first-child { padding-top: var(--sp-8); }

/* ─── Hotel cards ─── */
.hotel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--sp-6);
  margin-bottom: var(--sp-7);
}
.hotel-card {
  background: var(--card-bg);
  border-radius: var(--r-xl);
  overflow: hidden;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-md);
  transition: transform var(--transition), box-shadow var(--transition);
}
.hotel-card:hover { transform: translateY(-6px); box-shadow: var(--shadow-xl); }
.hotel-img-wrap { overflow: hidden; aspect-ratio: 3 / 2; }
.hotel-img-wrap img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-out);
}
.hotel-card:hover .hotel-img-wrap img { transform: scale(1.05); }
.hotel-body { padding: var(--sp-6); }
.hotel-body h3 {
  font-family: var(--serif);
  font-size: var(--step-3);
  font-weight: 400;
  margin-bottom: var(--sp-2);
  color: var(--dark);
}
.hotel-tag {
  display: inline-block;
  font-size: var(--step--1);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gold-ink);
  margin-bottom: var(--sp-3);
}
/* `:not()` because .hotel-tag is also a <p> here, and a bare `.hotel-body p`
   colour (0,1,1) would out-specify `.hotel-tag` (0,1,0). */
.hotel-body p:not(.hotel-tag) { color: var(--muted); }

/* Address / travel time / phone block */
.hotel-meta {
  display: grid;
  gap: var(--sp-3);
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
  font-size: var(--step--1);
}
.hotel-meta > div { display: grid; gap: 2px; }
.hotel-meta dt {
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--gold-ink);
}
.hotel-meta dd { margin: 0; color: var(--muted); line-height: 1.5; }
.hotel-meta dd a { color: var(--muted); text-decoration: underline; text-decoration-color: var(--line); text-underline-offset: 3px; }
.hotel-meta dd a:hover { color: var(--dark); text-decoration-color: var(--gold); }

.hotel-link {
  display: inline-block;
  margin-top: var(--sp-5);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--gold-ink);
}
.hotel-link:hover { color: var(--dark); }
.hotels-note { color: var(--muted); font-size: var(--step--1); }

/* ─── Forms (RSVP + contact) ─── */
.section-rsvp { background: var(--white); }
.rsvp-form {
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
}
.rsvp-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5); }
.rsvp-field { display: flex; flex-direction: column; gap: var(--sp-2); }
.rsvp-field label {
  font-size: var(--step--1);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dark);
  font-weight: 500;
}
.rsvp-field label span { color: var(--gold-ink); }

/* Radio groups use a real fieldset/legend for grouping semantics */
.rsvp-fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
.rsvp-fieldset legend {
  padding: 0;
  margin-bottom: var(--sp-3);
  font-size: var(--step--1);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dark);
  font-weight: 500;
}
.rsvp-fieldset legend span { color: var(--gold-ink); }

.rsvp-field input[type="text"],
.rsvp-field input[type="email"],
.rsvp-field input[type="number"],
.rsvp-field textarea {
  font-family: var(--sans);
  font-size: var(--step-0);
  color: var(--dark);
  background: var(--white);
  border: 1.5px solid var(--line);
  border-radius: var(--r-md);
  padding: 14px 16px;
  min-height: 50px;
  width: 100%;
  outline: none;
  transition: border-color var(--transition), box-shadow var(--transition),
              background var(--transition);
}
/* 4.5:1 on white — still lighter than the typed value, but legible */
.rsvp-field input::placeholder,
.rsvp-field textarea::placeholder { color: #647797; }
.rsvp-field input:hover:not(:disabled),
.rsvp-field textarea:hover:not(:disabled) { border-color: var(--navy-600); }
.rsvp-field input:focus-visible,
.rsvp-field textarea:focus-visible {
  border-color: var(--gold);
  box-shadow: 0 0 0 4px rgba(201, 162, 39, 0.28);
  /* Transparent outline stays visible in forced-colors mode, where
     box-shadow is dropped. */
  outline: 2px solid transparent;
  outline-offset: 0;
}
.rsvp-field input:disabled,
.rsvp-field textarea:disabled {
  background: var(--cream);
  color: var(--muted);
  cursor: not-allowed;
}
.rsvp-field textarea { resize: vertical; line-height: 1.65; }

/* Radios as selectable cards */
.rsvp-radio-group { display: flex; gap: var(--sp-3); flex-wrap: wrap; }
.rsvp-radio {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 13px var(--sp-5);
  border: 1.5px solid var(--line);
  border-radius: var(--r-full);
  font-size: var(--step-0);
  color: var(--dark);
  cursor: pointer;
  text-transform: none;
  letter-spacing: 0;
  transition: border-color var(--transition), background var(--transition);
}
.rsvp-radio:hover { border-color: var(--navy-600); }
.rsvp-radio:has(input:checked) {
  border-color: var(--gold);
  background: var(--gold-wash);
}
.rsvp-radio:has(input:focus-visible) {
  outline: 2px solid var(--gold-ink);
  outline-offset: 3px;
}
.rsvp-radio input {
  appearance: none;
  -webkit-appearance: none;
  width: 18px; height: 18px;
  margin: 0;
  border: 1.5px solid var(--muted);
  border-radius: 50%;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: border-color var(--transition);
}
.rsvp-radio input::after {
  content: '';
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--gold);
  transform: scale(0);
  transition: transform var(--dur-fast) var(--ease-out);
}
.rsvp-radio input:checked { border-color: var(--gold); }
.rsvp-radio input:checked::after { transform: scale(1); }

.rsvp-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  flex-wrap: wrap;
  margin-top: var(--sp-2);
}
/* ── Champs en erreur ── */
/* Le message vit sous son champ : la barre d'état sous le bouton dit qu'il y a
   quelque chose à corriger, elle ne peut pas dire quoi pour chaque champ. */
.field-error {
  font-size: var(--step--1);
  color: #b3261e;
  font-weight: 500;
  line-height: 1.45;
}
.field-error[hidden] { display: none; }
/* [type] n'est pas décoratif : sans lui, le sélecteur pèse moins lourd que
   la bordure par défaut posée sur .rsvp-field input[type="email"] & co. */
.rsvp-field input[type].is-invalid,
.rsvp-field textarea.is-invalid { border-color: #b3261e; }
.rsvp-field input.is-invalid:focus-visible,
.rsvp-field textarea.is-invalid:focus-visible {
  border-color: #b3261e;
  box-shadow: 0 0 0 4px rgba(179, 38, 30, 0.22);
}

.rsvp-status { font-size: var(--step--1); color: var(--muted); }
.rsvp-status.success { color: #1d6b47; font-weight: 500; }
.rsvp-status.error   { color: #b3261e; font-weight: 500; }

/* ─── RSVP part 2 — conditional reveal ─── */
.rsvp-part2 {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-slow) var(--ease-out),
              opacity var(--dur) ease;
  overflow: hidden;
  opacity: 0;
}
.rsvp-part2.visible { grid-template-rows: 1fr; opacity: 1; }
.rsvp-part2 > * {
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
}
.rsvp-part2 [data-event] {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
}
.rsvp-part2 [data-event][hidden] { display: none; }

/* Everything past the name fields, revealed once the lookup matches. */
.rsvp-answer {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
}
.rsvp-answer[hidden] { display: none; }

.rsvp-lookup-msg,
.rsvp-events-msg {
  font-size: var(--step--1);
  min-height: 1.4em;
  color: var(--muted);
}
.rsvp-lookup-msg.error { color: #b3261e; font-weight: 500; }

/* Shown with that error only: the way out for a guest who is not on the list. */
.rsvp-lookup-help {
  /* Pulls back most of the form's 1.5rem gap: this belongs to the error
     right above it, not to the next field. */
  margin-top: calc(var(--sp-2) - var(--sp-5));
  font-size: var(--step--1);
  color: var(--muted);
}
.rsvp-lookup-help[hidden] { display: none; }
.rsvp-lookup-help a {
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 0.25em;
  /* Room to hit it with a thumb; the negative margin keeps the padding from
     growing the line. */
  padding: 0.4em 0.1em;
  margin: -0.4em 0;
}

/* Spinner while the name is being checked. */
.rsvp-lookup-msg.loading::before {
  content: '';
  display: inline-block;
  width: 0.85em;
  height: 0.85em;
  margin-right: 0.5em;
  vertical-align: -0.12em;
  border: 2px solid var(--line);
  border-top-color: var(--gold);
  border-radius: 50%;
  animation: rsvp-spin 0.7s linear infinite;
}
@keyframes rsvp-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  /* Still a visible marker, just not a spinning one. */
  .rsvp-lookup-msg.loading::before {
    animation: none;
    border-color: var(--gold);
  }
}

/* ── Fields edited but not yet sent ── */
.rsvp-field.field-changed > label::after,
.rsvp-fieldset.field-changed > legend::after {
  content: 'non enregistré';
  margin-left: var(--sp-2);
  padding: 1px 8px;
  border-radius: var(--r-full);
  background: var(--gold-wash);
  color: var(--gold-ink);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: none;
  white-space: nowrap;
}
.field-changed input,
.field-changed textarea { border-color: var(--gold); }
.rsvp-fieldset.field-changed .rsvp-radio:has(input:checked) { border-color: var(--gold); }

.rsvp-changes {
  font-size: var(--step--1);
  color: var(--gold-ink);
  background: var(--gold-wash);
  border-radius: var(--r-sm);
  padding: var(--sp-3) var(--sp-4);
  line-height: 1.5;
}
.rsvp-changes[hidden] { display: none; }

/* Who the invitation covers — shown when it is more than one person. */
.rsvp-party {
  font-size: var(--step--1);
  color: var(--muted);
  background: var(--cream);
  border-left: 2px solid var(--gold);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  padding: var(--sp-3) var(--sp-4);
  line-height: 1.6;
}
.rsvp-party[hidden] { display: none; }
.rsvp-party strong { color: var(--dark); font-weight: 500; }

.rsvp-part2-divider {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
}
.rsvp-part2-divider::before,
.rsvp-part2-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--line);
}
.rsvp-part2-divider span {
  font-family: var(--script);
  font-size: var(--step-2);
  color: var(--gold-ink);
  white-space: nowrap;
}

/* ─── Footer ─── */
.site-footer {
  padding: var(--sp-8) var(--gutter) var(--sp-6);
  text-align: center;
  background: var(--navy-950);
  color: var(--on-navy-soft);
  font-size: var(--step--1);
}
.footer-monogram { margin-bottom: var(--sp-4); }
.footer-logo {
  height: 64px; width: 64px;
  object-fit: contain;
  margin: 0 auto;
  opacity: 0.9;
  /* Sept appuis de suite sur mobile : sans ça, un carré gris clignote à
     chacun (surbrillance tactile) et le long appui propose « copier l'image ». */
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  user-select: none;
}
.footer-links {
  list-style: none;
  display: flex;
  gap: var(--sp-5);
  justify-content: center;
  flex-wrap: wrap;
  margin-bottom: var(--sp-5);
  padding-top: var(--sp-5);
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.footer-links a {
  color: var(--on-navy-soft);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.footer-links a:hover { color: var(--gold-light); }

/* La seule porte d'entrée visible de la chasse aux œufs : « made with love and
   Claude » mène à humans.txt. Souligné en pointillés — assez pour se lire comme
   un lien et donner envie de cliquer, pas assez pour crier « cliquez ici ». */
.footer-credits {
  /* Doré plutôt qu'hérité : dans un pied de page tout en gris-bleu, c'est
     la seule chose qui accroche l'œil sans bouger. */
  color: var(--gold-light);
  text-decoration: underline dotted;
  text-decoration-color: rgba(223, 192, 90, 0.5);
  text-underline-offset: 0.3em;
  /* inline-block pour que `transform` et le halo en ::before prennent : sur
     un inline pur, l'un est ignoré et l'autre n'a pas de boîte à couvrir.
     La marge négative annule la hauteur que le padding ajouterait alors à
     la ligne — la zone cliquable grandit, le pied de page ne bouge pas. */
  display: inline-block;
  position: relative;
  /* Le padding vertical agrandit la zone tactile : 16px de haut, c'est trop
     peu pour un pouce. */
  padding: 0.55em 0.2em;
  margin: -0.55em 0;
}
/* Le halo : une lueur dorée qui enfle derrière le texte pendant le clin
   d'œil. C'est elle qui rend le signal visible du coin de l'œil — la seule
   couleur du texte, elle, ne se remarque que si on la regardait déjà. */
.footer-credits::before {
  content: '';
  position: absolute;
  inset: 0.1em -0.5em;
  border-radius: 999px;
  background: radial-gradient(ellipse at center, rgba(223, 192, 90, 0.38), rgba(223, 192, 90, 0) 72%);
  opacity: 0;
  pointer-events: none;
}
.footer-credits:hover,
.footer-credits:focus-visible {
  color: #fff;
  text-decoration-color: var(--gold);
}

/* Le clin d'œil. Trois battements plutôt qu'une seule lueur : une pulsation
   unique de 1,3 s, testée sur quelqu'un qui ne savait pas quoi chercher, se
   rate tout simplement — le temps de baisser les yeux vers le pied de page,
   c'est déjà fini. Trois passages en 2,4 s laissent le temps d'arriver.

   Rien ne disparaît (le lien reste lisible d'un bout à l'autre), le rythme
   plafonne à 1,25 Hz — loin des 3 Hz au-delà desquels un clignotement
   devient dangereux — et l'intervalle entre deux clins d'œil est tiré au
   sort dans easter-eggs.js, parce qu'un battement régulier devient un motif
   qu'on cesse de voir.

   Il s'arrête tout seul au bout de quelques passages, et définitivement dès
   que le lien est cliqué — un pied de page ne doit pas faire signe
   indéfiniment. */
@keyframes egg-wink {
  0%   { color: var(--gold-light); text-shadow: none; transform: scale(1); }
  10%  { color: #fff; text-shadow: 0 0 12px var(--gold), 0 0 26px rgba(201, 162, 39, 0.5); transform: scale(1.07); }
  26%  { color: var(--gold-light); text-shadow: 0 0 5px rgba(201, 162, 39, 0.3); transform: scale(1); }
  42%  { color: #fff; text-shadow: 0 0 14px var(--gold), 0 0 32px rgba(201, 162, 39, 0.55); transform: scale(1.07); }
  58%  { color: var(--gold-light); text-shadow: 0 0 5px rgba(201, 162, 39, 0.3); transform: scale(1); }
  74%  { color: #fff; text-shadow: 0 0 12px var(--gold), 0 0 26px rgba(201, 162, 39, 0.5); transform: scale(1.06); }
  100% { color: var(--gold-light); text-shadow: none; transform: scale(1); }
}
@keyframes egg-wink-halo {
  0%, 100% { opacity: 0; transform: scale(0.6); }
  10%, 42%, 74% { opacity: 1; transform: scale(1); }
  26%, 58% { opacity: 0.35; transform: scale(0.85); }
}
.footer-credits.is-winking { animation: egg-wink 2.4s var(--ease-out); }
.footer-credits.is-winking::before { animation: egg-wink-halo 2.4s var(--ease-out); }
/* Le lien souligné plein pendant le clin d'œil : au repos le pointillé dit
   « lien discret », ici il faut qu'il dise « celui-là, oui, clique ». */
.footer-credits.is-winking { text-decoration-style: solid; text-decoration-color: var(--gold); }

/* Insistance. Après quelques clins d'œil restés sans réponse, le signal
   monte d'un cran : le halo passe au premier plan et le lien se balance
   légèrement, comme une main qui fait signe. On ne va pas plus loin — c'est
   un pied de page de mariage, pas une bannière publicitaire. */
@keyframes egg-wave {
  0%, 100% { transform: scale(1) rotate(0); }
  15%      { transform: scale(1.1) rotate(-1.6deg); }
  30%      { transform: scale(1.08) rotate(1.6deg); }
  45%      { transform: scale(1.1) rotate(-1.2deg); }
  60%      { transform: scale(1.06) rotate(0.8deg); }
}
.footer-credits.is-winking-strong {
  animation: egg-wink 2.4s var(--ease-out), egg-wave 2.4s var(--ease-out);
  text-decoration-style: solid;
  text-decoration-color: var(--gold);
}
.footer-credits.is-winking-strong::before {
  animation: egg-wink-halo 2.4s var(--ease-out);
  background: radial-gradient(ellipse at center, rgba(223, 192, 90, 0.6), rgba(223, 192, 90, 0) 74%);
}

/* Le signal au repos. Deux cas s'y retrouvent : l'animation est refusée
   (prefers-reduced-motion), ou la série de clins d'œil est épuisée sans que
   personne n'ait cliqué. Dans les deux, il reste à faire voir le lien sans
   bouger : un fond doré très pâle et un soulignement plein suffisent à le
   détacher du reste du pied de page, et le signal se fige au lieu de
   disparaître. */
.footer-credits.is-inviting,
.footer-credits.is-winking-strong {
  background: rgba(223, 192, 90, 0.13);
  border-radius: 999px;
}
@media (prefers-reduced-motion: reduce) {
  .footer-credits {
    background: rgba(223, 192, 90, 0.13);
    border-radius: 999px;
    text-decoration-style: solid;
    text-decoration-color: rgba(223, 192, 90, 0.75);
  }
}

/* ─── Scroll animation ─── */
/* Everything below is scoped to .js (set by an inline script in <head>).
   Without JS there is nothing to add .visible, so the content must never
   start hidden — otherwise a script failure blanks the whole page. */
.js .fade-in {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out);
}
.js .fade-in.visible { opacity: 1; transform: none; }

/* Children of .stagger cascade in once the container is visible */
.js .stagger > * {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out);
}
.js .stagger.visible > * { opacity: 1; transform: none; }
.js .stagger.visible > *:nth-child(1) { transition-delay: 60ms; }
.js .stagger.visible > *:nth-child(2) { transition-delay: 150ms; }
.js .stagger.visible > *:nth-child(3) { transition-delay: 240ms; }
.js .stagger.visible > *:nth-child(4) { transition-delay: 330ms; }
.js .stagger.visible > *:nth-child(5) { transition-delay: 420ms; }
.js .stagger.visible > *:nth-child(6) { transition-delay: 510ms; }

/* ─── Responsive ─── */
/* 1100px, not 900px: below this the 50/50 hero leaves too little room to the
   right of the photo for five French labels, so the row would sit on the
   photo. The drawer avoids the problem entirely.
   ⚠️ script.js watches `(min-width: 1101px)` — change both together. */
@media (max-width: 1100px) {
  .nav-toggle { display: inline-flex; }

  .nav-links {
    position: fixed;
    top: 0; right: 0; bottom: 0;
    z-index: 195;
    width: min(320px, 82vw);
    flex-direction: column;
    align-items: stretch;
    justify-content: center;
    gap: var(--sp-2);
    padding: var(--sp-8) var(--sp-6);
    background: var(--navy-950);
    box-shadow: var(--shadow-xl);
    transform: translateX(100%);
    visibility: hidden;
    transition: transform var(--dur-slow) var(--ease-out),
                visibility var(--dur-slow) ease;
  }
  body.nav-open .nav-links { transform: translateX(0); visibility: visible; }

  .nav-links a {
    display: block;
    padding: var(--sp-4) var(--sp-2);
    font-size: 0.95rem;
    letter-spacing: 0.14em;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  }
  /* Same specificity trap as the desktop rule — keep the colour off `a`. */
  .nav-links a:not(.nav-rsvp) { color: var(--on-navy); }
  .nav-links a:not(.nav-rsvp)::after { display: none; }
  .nav-links a:not(.nav-rsvp):hover,
  .nav-links a:not(.nav-rsvp).active { color: var(--gold-light); }
  .nav-links li:last-child { margin-top: var(--sp-5); }
  .nav-rsvp {
    text-align: center;
    border-bottom: 0;
    background: var(--gold);
    color: var(--navy-950);
  }
  .nav-rsvp:hover,
  .nav-rsvp.active { background: var(--gold-light); color: var(--navy-950); }
}

@media (max-width: 720px) {
  .hero {
    grid-template-columns: 1fr;
    min-height: 0;
  }
  /* Photo first, then text — order matches the visual hierarchy */
  .hero-photo-wrap { aspect-ratio: 4 / 3; }
  .hero-text {
    padding: var(--sp-7) var(--gutter) var(--sp-8);
    text-align: center;
    align-items: center;
  }
  .hero-date::before { left: 50%; transform: translateX(-50%); }
  .hero-actions { justify-content: center; }
  .hero-scroll-hint { display: none; }

  .timeline::before { left: 64px; }
  .timeline-item { grid-template-columns: 64px 1fr; }
  .timeline-time { font-size: var(--step-0); padding-right: var(--sp-3); }
  .timeline-content { padding-left: var(--sp-5); }

  .countdown-box { padding: var(--sp-4); min-width: 74px; }
  .rsvp-row { grid-template-columns: 1fr; }
  .rsvp-radio-group { flex-direction: column; align-items: stretch; }
  .rsvp-radio { justify-content: flex-start; }
}

@media (max-width: 420px) {
  .countdown-boxes { gap: var(--sp-2); }
  .countdown-box { min-width: 66px; padding: var(--sp-3) var(--sp-2); }
  .hero-logo img { height: 64px; width: 64px; }
}

/* ─── Œufs de Pâques ─── */
/* Piloté par easter-eggs.js. Purement décoratif : rien ici n'entre dans le
   flux de la page, et la pluie de cœurs ne se lance pas en reduced-motion. */
/* Ordre d'empilement de la fête, du dessous vers le dessus :
   terminal (10001) < pluie (10002) < bandeau (10003). La pluie passe
   au-dessus du terminal, sinon le Konami tapé au pouce récompenserait
   par des confettis cachés derrière le voile. Elle ne bloque rien :
   pointer-events est à none. */
.egg-canvas {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;   /* on doit pouvoir cliquer à travers la fête */
  z-index: 10002;
  /* Force sa propre couche de composition : sans ça, chaque image repeinte
     entraîne le panneau du terminal avec elle. */
  transform: translateZ(0);
}

.egg-toast {
  position: fixed;
  left: 50%;
  bottom: var(--sp-5);
  transform: translate(-50%, 1rem);
  z-index: 10003;
  max-width: min(30rem, calc(100vw - 2 * var(--gutter)));
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding: var(--sp-4) var(--sp-5);
  background: var(--navy-950);
  color: var(--on-navy);
  border: 1px solid var(--gold);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xl);
  opacity: 0;
  transition: opacity var(--transition), transform var(--transition);
}
.egg-toast.visible { opacity: 1; transform: translate(-50%, 0); }

/* Terminal ouvert, le bandeau passe en haut : en bas il couvrirait la croix
   directionnelle, c'est-à-dire précisément ce qu'on vient de féliciter. */
body.egg-term-open .egg-toast {
  top: var(--sp-5);
  bottom: auto;
  transform: translate(-50%, -1rem);
}
body.egg-term-open .egg-toast.visible { transform: translate(-50%, 0); }
.egg-toast strong {
  font-family: var(--serif);
  font-size: var(--step-2);
  color: var(--gold-light);
  line-height: 1.2;
}
.egg-toast span { font-size: var(--step--1); color: var(--on-navy-soft); }

/* ── Le terminal tactile ──
   L'équivalent de la console pour un téléphone. Construit à la demande par
   easter-eggs.js : tant que personne ne le trouve, ce CSS ne s'applique à
   rien. */
.egg-term {
  position: fixed;
  inset: 0;
  z-index: 10001;         /* au-dessus du bandeau : c'est lui qu'on manipule */
  display: none;
  align-items: center;
  justify-content: center;
  padding: var(--sp-4);
}
.egg-term.visible { display: flex; }
body.egg-term-open { overflow: hidden; }

.egg-term-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(18, 36, 74, 0.55);
  backdrop-filter: blur(2px);
}
/* Un backdrop-filter plein écran se réévalue à chaque image dès que quelque
   chose bouge au-dessus : la pluie tombait à 60 fps toute seule et saccadait
   au-dessus du terminal. Le flou saute le temps de la fête — 2px de moins
   pendant six secondes, personne ne le remarquera. */
body.egg-raining .egg-term-backdrop { backdrop-filter: none; }

.egg-term-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(38rem, 100%);
  max-height: min(80vh, 40rem);
  /* dvh suit la barre d'adresse mobile ; le vh au-dessus reste le repli. */
  max-height: min(80dvh, 40rem);
  background: var(--navy-950);
  border: 1px solid var(--navy-600);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-xl);
  overflow: hidden;
  /* Sur iPhone, la barre système mange le bas du panneau sans ça. */
  margin-bottom: env(safe-area-inset-bottom, 0);
}

.egg-term-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  background: rgba(255, 255, 255, 0.05);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--step--1);
  color: var(--on-navy-soft);
}
.egg-term-close {
  border: 0;
  background: none;
  color: var(--on-navy-soft);
  font-size: var(--step-0);
  line-height: 1;
  padding: var(--sp-2);
  margin: calc(-1 * var(--sp-2));   /* cible tactile large, sans déformer la barre */
  cursor: pointer;
}
.egg-term-close:hover { color: var(--gold-light); }

.egg-term-out {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: var(--sp-3);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.82rem;      /* fixe : c'est du texte préformaté, il ne doit pas fluctuer */
  line-height: 1.6;
  color: var(--on-navy);
}
.egg-term-line { white-space: pre-wrap; word-break: break-word; }
.egg-term-line.is-echo { color: var(--on-navy-soft); }
.egg-term-line.is-dim  { color: var(--muted); }
.egg-term-line.is-hit  { color: var(--gold-light); }

.egg-term-form {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--gold-light);
}
.egg-term-input {
  flex: 1;
  border: 0;
  background: none;
  color: var(--on-navy);
  font: inherit;
  /* 16px minimum, sinon iOS zoome sur le champ à chaque focus. */
  font-size: 16px;
}
.egg-term-input:focus { outline: none; }

.egg-term-pad {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-4) var(--sp-4);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.egg-term-dpad {
  display: grid;
  grid-template-areas: '. u .' 'l . r' '. d .';
  gap: 4px;
}
/* Ces quatre règles étaient des style="grid-area:…" posés dans le HTML injecté
   par easter-eggs.js. La CSP n'autorise pas 'unsafe-inline' pour style-src, et
   un attribut style relève de style-src-attr : le navigateur les jetait, les
   flèches se plaçaient automatiquement et la croix directionnelle sortait en
   ligne. Ici, elles survivent à la CSP. */
.egg-term-dpad [data-key="arrowup"]    { grid-area: u; }
.egg-term-dpad [data-key="arrowleft"]  { grid-area: l; }
.egg-term-dpad [data-key="arrowright"] { grid-area: r; }
.egg-term-dpad [data-key="arrowdown"]  { grid-area: d; }
.egg-term-ab { display: flex; gap: var(--sp-3); }
.egg-term-pad button {
  width: 2.75rem;          /* 44px : la cible tactile minimale */
  height: 2.75rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--navy-600);
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, 0.06);
  color: var(--on-navy);
  font-family: var(--sans);
  font-size: var(--step--1);
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.egg-term-ab button { border-radius: var(--r-full); font-weight: 700; }
.egg-term-pad button.is-hit { animation: egg-key 260ms var(--ease-out); }

@keyframes egg-key {
  from { background: var(--gold); color: var(--navy-950); transform: scale(0.92); }
  to   { background: rgba(255, 255, 255, 0.06); color: var(--on-navy); transform: scale(1); }
}

/* Le compteur d'appuis sous le monogramme, à partir du 3e. */
.egg-dots {
  display: block;
  margin-top: var(--sp-2);
  letter-spacing: 0.35em;
  font-size: var(--step--1);
  color: var(--gold);
  min-height: 1em;         /* réservé : sinon le pied de page sursaute */
}

.footer-logo { transition: transform var(--transition); }
.egg-wobble { animation: egg-wobble 400ms var(--ease-out); }
.egg-spin   { animation: egg-spin 1.6s var(--ease-out); }

@keyframes egg-wobble {
  0%, 100% { transform: rotate(0); }
  30%      { transform: rotate(-9deg) scale(1.06); }
  65%      { transform: rotate(7deg)  scale(1.06); }
}
@keyframes egg-spin {
  from { transform: rotate(0) scale(1); }
  50%  { transform: rotate(360deg) scale(1.25); }
  to   { transform: rotate(720deg) scale(1); }
}

/* La récompense des quatre œufs : un cœur d'or qui reste, d'une visite à
   l'autre, à côté de la signature du pied de page. */
/* Visé nommément, pas par :last-child : la ligne d'indice se glisse après,
   et le cœur doit rester sur la signature. */
.eggs-complete .footer-copy::after {
  content: ' ♥';
  color: var(--gold-light);
}

/* L'indice assumé : sans lui, rien sur la page ne dit qu'il y a quelque
   chose à chercher. Discret et gris — c'est le lien doré au-dessus qui doit
   attirer l'œil, cette ligne ne fait que l'expliquer. */
.footer-hint {
  margin-top: var(--sp-3);
  font-size: var(--step--1);
  font-style: italic;
  /* Pas --muted : sur ce navy il tombe à 3:1, sous le minimum de 4.5:1 pour
     du petit texte. L'italique suffit à le mettre en retrait. */
  color: var(--on-navy-soft);
}
/* Chasse terminée : plus rien à annoncer. */
.eggs-complete .footer-hint { display: none; }

/* Le dernier recours : quand les clins d'œil sont restés sans réponse, on
   arrête de faire signe et on le dit. Caché par défaut — celui qui trouve
   tout seul garde sa découverte intacte ; c'est easter-eggs.js qui pose
   .eggs-nudge sur le pied de page une fois la série épuisée. */
.footer-hint-nudge { display: none; }
.eggs-nudge .footer-hint-nudge {
  display: inline;
  color: var(--gold-light);
  animation: nudge-in 0.6s var(--ease-out) both;
}
@keyframes nudge-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* « œufs de Pâques » pointe vers l'article Wikipédia, pour qui ne connaît pas
   le terme. Volontairement plus discret que le lien doré au-dessus : il garde
   la couleur du texte et ne signale sa nature que par un pointillé, sinon on
   cliquerait dessus en croyant y trouver un œuf. */
.footer-hint-link {
  color: inherit;
  text-decoration: underline dotted;
  text-decoration-color: rgba(255, 255, 255, 0.35);
  text-underline-offset: 0.25em;
  /* Même raison qu'au-dessus : de quoi viser au pouce sans décaler la ligne. */
  padding: 0.4em 0.1em;
}
.footer-hint-link:hover,
.footer-hint-link:focus-visible {
  color: #fff;
  text-decoration-color: rgba(255, 255, 255, 0.7);
}

/* ─── Mode geek ─── */
/* Le Konami Code ne se contente plus de faire pleuvoir des confettis : il
   rallume le site sur un moniteur à phosphore.

   Presque tout tient dans la redéfinition de tokens ci-dessous — c'est le
   bénéfice d'avoir une palette centralisée : le thème entier est un jeu de
   variables. Les règles qui suivent ne rattrapent que deux cas :
     · les couleurs écrites en dur (le voile de la barre, le dégradé du hero) ;
     · les endroits où un token change de rôle — --dark est l'encre, il ne
       peut plus servir de fond au compte à rebours sans virer au vert fluo.

   L'état vit dans localStorage et est réappliqué par le script en <head> de
   chaque page : sans lui, changer de page ferait clignoter le site en blanc
   le temps que easter-eggs.js se charge. */
.geek-mode {
  --mono: ui-monospace, 'SF Mono', 'JetBrains Mono', 'Fira Code', Menlo, Consolas, monospace;

  /* Trois noirs à peine distincts, pour garder l'alternance de sections que
     le thème clair obtient avec blanc / crème. */
  --white:      #080c0a;
  --cream:      #0b1210;
  --card-bg:    #0d1512;
  --navy-950:   #04070a;

  /* Le vert des tubes à phosphore. 12,6:1 sur le fond — le mode geek reste
     plus lisible que le thème clair, ce qui n'était pas gagné d'avance. */
  --dark:       #7ee787;
  --navy-600:   #57c268;
  --muted:      #7fa78a;   /* 7,2:1 */
  --line:       #1d3325;

  /* L'or devient l'ambre du second phosphore. Sur du noir, --gold-ink n'a
     plus besoin d'être assombri (10,5:1) : les deux ors se rejoignent, mais
     on garde les deux variables pour ne toucher à aucune règle existante. */
  --gold:       #ffb000;
  --gold-ink:   #ffb000;
  --gold-light: #ffcf6a;
  --gold-wash:  rgba(255, 176, 0, 0.12);

  --on-navy:      #9ff3a8;
  --on-navy-soft: #7fc78d;

  /* Un terminal n'a qu'une fonte. */
  --serif:  var(--mono);
  --script: var(--mono);
  --sans:   var(--mono);

  /* Ni coins arrondis — 2px sur --r-full plutôt que 0 : les pilules
     redeviennent des rectangles sans que les bords aient l'air cassés. */
  --r-sm: 0; --r-md: 0; --r-lg: 0; --r-xl: 0; --r-full: 2px;

  /* Ni ombres portées : un tube cathodique ne projette pas d'ombre, il
     rayonne. Les quatre niveaux deviennent quatre intensités de lueur. */
  --shadow-sm: 0 0 0 1px rgba(126, 231, 135, 0.14);
  --shadow-md: 0 0 0 1px rgba(126, 231, 135, 0.22), 0 0 18px -8px rgba(126, 231, 135, 0.50);
  --shadow-lg: 0 0 0 1px rgba(126, 231, 135, 0.30), 0 0 28px -8px rgba(126, 231, 135, 0.55);
  --shadow-xl: 0 0 0 1px rgba(126, 231, 135, 0.36), 0 0 44px -10px rgba(126, 231, 135, 0.60);
}

.geek-mode body {
  background: var(--white);
  /* La lueur du phosphore : légère, sinon le texte devient flou à la lecture. */
  text-shadow: 0 0 6px rgba(126, 231, 135, 0.22);
}
/* Vidéo inverse (texte noir sur vert) : la lueur verte y ferait une bavure. */
.geek-mode .btn-primary,
.geek-mode .btn-outline:hover,
.geek-mode .nav-rsvp,
.geek-mode .skip-link { text-shadow: none; }

/* Au survol, le thème clair assombrit le fond (--navy-950) en gardant le
   texte en --white. En mode geek les deux sont noirs : le libellé
   disparaissait dans son propre bouton. Un terminal éclaire ce qu'on
   survole, il ne l'éteint pas — on monte donc d'un cran de phosphore au
   lieu de descendre. */
.geek-mode .btn-primary:hover,
.geek-mode .nav-rsvp:hover {
  background: var(--on-navy);
  color: var(--white);
}

/* Scanlines + vignettage. Un seul élément fixe, au-dessus de tout — œufs
   compris : c'est l'écran entier qui est censé être le moniteur. Il
   n'intercepte rien (pointer-events: none) et ne se repeint pas au défilement
   (position: fixed). */
.geek-mode body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 10010;
  pointer-events: none;
  background:
    repeating-linear-gradient(rgba(0, 0, 0, 0) 0 2px, rgba(0, 0, 0, 0.26) 2px 4px),
    radial-gradient(ellipse at center, rgba(0, 0, 0, 0) 52%, rgba(0, 0, 0, 0.50) 100%);
}

/* La barre : le voile blanc dépoli était écrit en dur. */
.geek-mode .nav::before {
  background: rgba(8, 12, 10, 0.86);
  box-shadow: 0 1px 0 var(--line);
}
/* La mono est plus large que l'Inter : sans resserrer l'interlettrage, la
   rangée de liens déborde sur la photo du hero (voir la note du README). */
.geek-mode .nav-links a { letter-spacing: 0.04em; }

/* Les titres deviennent des lignes de commande, curseur compris. Les
   keyframes finissent sur opacity: 1 pour que reduced-motion — qui coupe
   l'animation après une itération — laisse un curseur visible, pas un blanc. */
.geek-mode .section h1::before,
.geek-mode .section h2::before,
.geek-mode .page-hero h1::before { content: '> '; color: var(--gold); }
.geek-mode .section h1::after,
.geek-mode .section h2::after,
.geek-mode .page-hero h1::after,
.geek-mode .hero-text h1::after {
  content: '_';
  color: var(--gold);
  animation: geek-caret 1.1s step-end infinite;
}
@keyframes geek-caret { 0%, 49%, 100% { opacity: 1; } 50%, 99% { opacity: 0; } }

/* Le petit trait doré des intertitres devient un commentaire. */
.geek-mode .section-label::before {
  content: '//';
  width: auto; height: auto;
  background: none;
}

/* Le hero. Réduit : « ~$ Stéphanie && Maxime_ » en chasse fixe au corps de
   la Great Vibes déborderait la colonne de texte. */
.geek-mode .hero-text h1 {
  font-size: clamp(1.5rem, 3.6vw, 2.4rem);
  letter-spacing: -0.01em;
  line-height: 1.25;
}
.geek-mode .hero-text h1::before { content: '~$ '; color: var(--muted); }
/* La seule blague du thème qui tienne en CSS : l'esperluette du couple
   devient l'opérateur ET. */
.geek-mode .hero-text h1 .ampersand {
  display: inline;
  font-size: 1em;
  font-style: normal;
  padding: 0 0.3em;
}
.geek-mode .hero-text h1 .ampersand::after { content: '&'; }

/* Photos en monochrome vert : grayscale → sepia → hue-rotate, la recette
   classique pour teinter une image sans la retoucher. */
.geek-mode .hero-photo,
.geek-mode .hotel-img-wrap img {
  filter: grayscale(1) sepia(1) hue-rotate(65deg) saturate(1.8) brightness(0.55) contrast(1.2);
}
.geek-mode .hero-photo-wrap { background: var(--navy-950); }
.geek-mode .hero-photo-wrap::after {
  background: linear-gradient(rgba(8, 12, 10, 0.92), rgba(8, 12, 10, 0));
}

/* Le monogramme est un SVG bleu marine : sur du noir, il disparaît. On le
   repeint de bout en bout — noir, gris moyen, sépia saturé, rotation de
   teinte — puis on lui donne le halo du reste. */
.geek-mode .nav-logo,
.geek-mode .hero-logo img,
.geek-mode .footer-logo {
  filter: brightness(0) invert(0.58) sepia(1) saturate(6) hue-rotate(72deg)
          drop-shadow(0 0 6px rgba(126, 231, 135, 0.45));
}

/* Compte à rebours : --dark est l'encre du thème, il ne peut plus servir de
   fond ici sans repeindre la section en vert fluo sur toute sa largeur. */
.geek-mode .section-countdown {
  background: var(--navy-950);
  border-block: 1px solid var(--line);
}
.geek-mode .section-countdown::before {
  background: radial-gradient(circle, rgba(126, 231, 135, 0.10), transparent 65%);
}
.geek-mode .section-countdown h2,
.geek-mode .countdown-box span { color: var(--dark); }
.geek-mode .countdown-box {
  background: rgba(126, 231, 135, 0.05);
  border-color: rgba(126, 231, 135, 0.18);
}

/* La ligne des bases sous le nombre de jours — le même triplet que la
   commande « jours » du terminal. Elle bat `.countdown-box small` (0,1,1) par
   la spécificité (0,2,0) : sans ça elle hériterait des majuscules et de
   l'interlettrage du libellé, et « 0b100000011 » deviendrait illisible. */
.egg-radix { display: none; }
.geek-mode .egg-radix {
  display: block;
  margin-top: var(--sp-1);
  font-size: 0.62rem;
  letter-spacing: 0.02em;
  text-transform: none;
  white-space: nowrap;
  color: var(--gold);
}

/* La barre de progression, glissée sous les boîtes par easter-eggs.js. Elle
   n'existe qu'ici : le thème clair ne la connaît pas, d'où le display: none
   par défaut plutôt qu'une insertion conditionnelle en JS — basculer le mode
   ne touche alors pas au DOM. */
.egg-progress { display: none; }
.geek-mode .egg-progress {
  display: grid;
  justify-items: center;
  gap: var(--sp-2);
  margin-top: var(--sp-6);
  font-size: var(--step--1);
  line-height: 1.5;
}
/* ⚠️ letter-spacing: 0 obligatoire. Le moindre interlettrage écarte les blocs
   et la barre pleine se lit comme des pointillés — or c'est justement à ça
   que doit ressembler la partie vide. */
.geek-mode .egg-progress-bar {
  color: var(--muted);
  letter-spacing: 0;
  white-space: nowrap;
}
.geek-mode .egg-progress-bar .is-done { color: var(--dark); }
.geek-mode .egg-progress-pct  { color: var(--gold); margin-left: 0.6em; }
.geek-mode .egg-progress-note { color: var(--muted); }

/* Formulaires : les seules couleurs en dur du fichier, calculées pour du
   blanc. Sur noir elles tombent sous le seuil, on les remonte. */
.geek-mode .rsvp-field input,
.geek-mode .rsvp-field textarea { caret-color: var(--gold); }
.geek-mode .rsvp-field input::placeholder,
.geek-mode .rsvp-field textarea::placeholder { color: #6f8f78; }
.geek-mode .rsvp-field input:focus-visible,
.geek-mode .rsvp-field textarea:focus-visible {
  box-shadow: 0 0 0 3px rgba(255, 176, 0, 0.30);
}
.geek-mode .field-error { color: #ff7a6b; }
.geek-mode .rsvp-field input[type].is-invalid,
.geek-mode .rsvp-field textarea.is-invalid { border-color: #ff7a6b; }
.geek-mode .rsvp-field input.is-invalid:focus-visible,
.geek-mode .rsvp-field textarea.is-invalid:focus-visible {
  border-color: #ff7a6b;
  box-shadow: 0 0 0 4px rgba(255, 122, 107, 0.24);
}
.geek-mode .rsvp-status.success { color: #5ee38a; }
.geek-mode .rsvp-status.error   { color: #ff7a6b; }

/* Les œufs : les deux voiles plein écran sont en bleu marine écrit en dur,
   calculé pour le thème clair. Devant un écran de phosphore, le bleu est la
   seule couleur qui n'a rien à y faire — on repasse au noir du tube. */
.geek-mode .egg-term-backdrop { background: rgba(4, 8, 6, 0.72); }
.geek-mode .nav-backdrop      { background: rgba(4, 8, 6, 0.62); }

/* Et la ferrure du terminal : ces films blancs à 5 % virent au gris sur du
   vert. Même opacité, teinte du phosphore. */
.geek-mode .egg-term-bar {
  background: rgba(126, 231, 135, 0.06);
  border-bottom-color: rgba(126, 231, 135, 0.16);
}
.geek-mode .egg-term-form { border-top-color: rgba(126, 231, 135, 0.16); }
.geek-mode .egg-term-pad button { background: rgba(126, 231, 135, 0.06); }

/* L'allumage et l'extinction du tube : le voile s'ouvre depuis une ligne
   horizontale, ou s'y referme. Posé et retiré par easter-eggs.js, qui ne le
   crée pas du tout en reduced-motion. Au-dessus des scanlines. */
.geek-boot {
  position: fixed;
  inset: 0;
  z-index: 10011;
  pointer-events: none;
  transform-origin: center;
  background: radial-gradient(ellipse at center,
              rgba(210, 255, 216, 0.95), rgba(126, 231, 135, 0.18) 68%, transparent);
}
.geek-boot.is-on  { animation: geek-power-on  900ms var(--ease-out) forwards; }
.geek-boot.is-off { animation: geek-power-off 620ms var(--ease-out) forwards; }
@keyframes geek-power-on {
  0%   { opacity: 0;    transform: scaleY(0.004); }
  14%  { opacity: 1;    transform: scaleY(0.004); }
  50%  { opacity: 0.85; transform: scaleY(1); }
  100% { opacity: 0;    transform: scaleY(1); }
}
@keyframes geek-power-off {
  0%   { opacity: 0.7; transform: scaleY(1); }
  55%  { opacity: 1;   transform: scaleY(0.004); }
  100% { opacity: 0;   transform: scaleY(0.004) scaleX(0.02); }
}

/* ─── Reduced motion ─── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }
  .js .fade-in,
  .js .stagger > * { opacity: 1 !important; transform: none !important; }
  .hero-photo { animation: none; }
}
