﻿/* =====================================================================
   Ulalu — système de design « heure dorée »
   ---------------------------------------------------------------------
   Idée directrice : Ulalu est un palindrome. Le dégradé de marque l'est
   aussi (ambre → braise → ambre) ; on le retrouve sur les traits, les
   boutons ; le logo relie deux personnes en « u ». Fond papier chaud, encre nuit, photos mises en
   scène comme des tirages posés sur une table.

   Polices auto-hébergées (SIL OFL, aucun appel à un tiers, RGPD) :
   Fraunces pour les titres (axe WONK, chaleur éditoriale), Inter pour
   l'interface.

   Sommaire : 1 polices · 2 jetons · 3 base · 4 typographie · 5 mise en
   page · 6 en-tête · 7 boutons · 8 cartes · 9 formulaires · 10 pastilles
   · 11 galerie · 12 dépôt de fichiers · 13 médias · 14 marketing
   · 15 pied de page · 16 utilitaires · 17 mouvement · 18 vitrine
   ===================================================================== */

/* ---------- 1. Polices ---------- */
@font-face {
    font-family: "Fraunces";
    src: url("../fonts/fraunces-var-latin.woff2") format("woff2-variations");
    font-weight: 300 900;
    font-style: normal;
    font-display: swap;
    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: "Inter";
    src: url("../fonts/inter-var-latin.woff2") format("woff2-variations");
    font-weight: 300 800;
    font-style: normal;
    font-display: swap;
    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;
}

/* Emojis de secours, deux sous-ensembles de Noto Color Emoji (--font-emoji). Segoe UI Emoji de Windows 10 s'arrête à
   Emoji 12 : 🥲 🫶 🥹 🫠 y sortaient en carré. Et Windows écrit « FR » pour 🇫🇷. Chaque fichier n'est téléchargé que
   pour un caractère de sa plage qu'aucune police placée avant ne dessine ; plages réécrites par tools/emoji-font/build.py.
   Les drapeaux (717 Ko, tous les blasons) prennent d'abord le Noto du système : Android les dessine sans rien charger. */
@font-face {
    font-family: "Ulalu Flags";
    src: local("Noto Color Emoji"), local("NotoColorEmoji"), url("../fonts/noto-emoji-flags.woff2") format("woff2");
    font-display: swap;
    unicode-range: U+1F1E6-1F1FF, U+1F3F4, U+E0030-E0039, U+E0061-E007A, U+E007F;
}

@font-face {
    font-family: "Ulalu Emoji";
    src: url("../fonts/noto-emoji-recent.woff2") format("woff2");
    font-display: swap;
    unicode-range: U+200D, U+1F3FB-1F3FF, U+1F468-1F469, U+1F6D6-1F6D9, U+1F6DC-1F6DF, U+1F6FB-1F6FC, U+1F7F0, U+1F90C, U+1F972, U+1F977-1F979, U+1F9A3-1F9A4, U+1F9AB-1F9AD, U+1F9CB-1F9CC, U+1F9D1, U+1FA74-1FA77, U+1FA7B-1FA7C, U+1FA83-1FA8F, U+1FA96-1FAC6, U+1FAC8, U+1FACC-1FADD, U+1FADF-1FAEB, U+1FAEF-1FAFA;
}

/* ---------- 2. Jetons ---------- */
:root {
    /* Couleurs de marque */
    --ember: #e8502f;
    --ember-deep: #c23a1e;
    --amber: #f5a623;
    --plum: #5b3a8e;
    --jade: #14866a;
    --danger: #c02a2a;

    /* L'accent à taille de texte. --ember ne donne que 3,8:1 sur le papier et 3,3:1 sur le crème : sous les
       4,5:1 qu'AA demande à un texte normal, alors que la règle 3 de docs/08 promet AA. --ember garde les
       surfaces, les filets, le dégradé de marque et les grands titres ; tout ce qui se lit en petit passe
       par --ember-text (5,2:1 sur le papier). Mesures dans docs/critiques/2026-09-21-critique-ihm-ux.md. */
    --ember-text: var(--ember-deep);
    --ember-text-hover: #8f2913;

    /* Une action pleine : son encre est le papier de la page, ce qui tient dans les deux thèmes — crème sur
       braise profonde en clair, nuit sur braise claire en sombre. Le blanc sur --ember ne donnait que
       3,7:1 en clair et 2,8:1 en sombre. */
    --btn-solid: var(--ember-deep);
    --btn-sheen: color-mix(in srgb, var(--ember-deep) 90%, var(--ember));
    --btn-ink: var(--paper);

    /* Neutres chauds */
    --ink: #1a1420;
    --ink-2: #4a4152;
    /* #78707f tombait à 4,2:1 sur --surface-2, où ce gris sert le plus. Valeur reprise du pied de page des
       e-mails, arbitrée le 2026-09-21 pour la même raison : 5,7:1 sur le crème, 6,5:1 sur blanc. */
    --muted-ink: #635a6b;
    --paper: #fdfaf6;
    --surface: #ffffff;
    --surface-2: #f6f1ea;
    --line: #e7ded3;
    --line-strong: #d5c8b9;

    /* Dégradé palindrome : lisible dans les deux sens */
    --mirror: linear-gradient(90deg, var(--amber), var(--ember), var(--amber));
    --mirror-soft: linear-gradient(90deg, #fde8cf, #fbd9cc, #fde8cf);

    /* Rayons et ombres (teintées chaud, jamais grises) */
    --r-sm: 10px;
    --r: 14px;
    --r-lg: 22px;
    --r-xl: 30px;
    --shadow-1: 0 1px 2px rgba(70, 40, 20, .06), 0 2px 8px rgba(70, 40, 20, .04);
    --shadow-2: 0 2px 6px rgba(70, 40, 20, .07), 0 12px 28px rgba(70, 40, 20, .08);
    --shadow-3: 0 8px 20px rgba(70, 40, 20, .10), 0 30px 60px rgba(70, 40, 20, .12);

    /* Typographie */
    /* Les emojis du système d'abord ; les drapeaux de Noto avant Segoe UI Emoji, qui n'a que des lettres pour eux. */
    --font-emoji: "Apple Color Emoji", "Noto Color Emoji", "Ulalu Flags", "Segoe UI Emoji", "Ulalu Emoji";
    --font-display: "Fraunces", "Iowan Old Style", Georgia, serif, var(--font-emoji);
    --font-ui: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif, var(--font-emoji);

    /* Échelle fluide */
    --t-xs: .8125rem;
    --t-sm: .9063rem;
    --t-md: 1rem;
    --t-lg: clamp(1.06rem, .99rem + .3vw, 1.19rem);
    --t-xl: clamp(1.3rem, 1.18rem + .5vw, 1.6rem);
    --t-2xl: clamp(1.65rem, 1.4rem + 1.1vw, 2.35rem);
    --t-3xl: clamp(2.1rem, 1.6rem + 2.2vw, 3.6rem);
    --t-4xl: clamp(2.6rem, 1.75rem + 3.6vw, 5rem);

    /* Rythme */
    --gap: 1rem;
    --pad: clamp(1rem, .7rem + 1.2vw, 1.6rem);
    --section: clamp(3rem, 2rem + 5vw, 6.5rem);
    --measure: 64ch;

    /* L'anneau seul ne donnait que 1,5:1 contre le papier, là où WCAG 1.4.11 demande 3:1 d'un indicateur de
       focus — et les règles qui le posaient supprimaient au passage l'outline de la ligne 163, qui, lui,
       tenait. Le trait porte l'obligation, le halo ne fait que l'adoucir. */
    --focus-line: var(--ember-text);
    --focus: 0 0 0 3px color-mix(in srgb, var(--ember-text) 40%, transparent);
    color-scheme: light;
}

/* Mode sombre : mêmes rôles, encre et papier échangés, marque inchangée */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --ink: #f7f1ea;
        --ink-2: #c9bfd2;
        --muted-ink: #9b90a6;
        --paper: #14101a;
        --surface: #1d1826;
        --surface-2: #262032;
        --line: #332b41;
        --line-strong: #453a56;
        --ember: #ff6a45;
        --amber: #ffbe5c;
        /* Sur fond nuit, « profond » veut dire plus clair que le fond : #c23a1e ne donnait que 2,5:1 sur le
           brun de --mirror-soft, où ce jeton écrit les numéros d'étape et les pictogrammes. */
        --ember-deep: #ff9377;
        --ember-text-hover: #ffbda8;
        --btn-solid: var(--ember);
        --btn-sheen: color-mix(in srgb, var(--ember) 92%, #fff);
        /* Le rouge d'erreur aussi : #c02a2a ne donnait que 2,98:1 sur la carte — « Révoquer ce lien » et les
           messages d'erreur de formulaire. La valeur est celle que le studio se donne déjà pour son chrome
           sombre (studio.css). La supervision avait rustiné le cas chez elle ; ce n'est plus utile. */
        --danger: #ff8b82;
        --mirror-soft: linear-gradient(90deg, #3a2a1e, #3d2622, #3a2a1e);
        --shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
        --shadow-2: 0 2px 6px rgba(0, 0, 0, .45), 0 12px 28px rgba(0, 0, 0, .35);
        --shadow-3: 0 8px 20px rgba(0, 0, 0, .5), 0 30px 60px rgba(0, 0, 0, .45);
        color-scheme: dark;
    }
}

:root[data-theme="dark"] {
    --ink: #f7f1ea;
    --ink-2: #c9bfd2;
    --muted-ink: #9b90a6;
    --paper: #14101a;
    --surface: #1d1826;
    --surface-2: #262032;
    --line: #332b41;
    --line-strong: #453a56;
    --ember: #ff6a45;
    --amber: #ffbe5c;
    --ember-deep: #ff9377;
    --ember-text-hover: #ffbda8;
    --btn-solid: var(--ember);
    --btn-sheen: color-mix(in srgb, var(--ember) 92%, #fff);
    --danger: #ff8b82;
    --mirror-soft: linear-gradient(90deg, #3a2a1e, #3d2622, #3a2a1e);
    --shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-2: 0 2px 6px rgba(0, 0, 0, .45), 0 12px 28px rgba(0, 0, 0, .35);
    --shadow-3: 0 8px 20px rgba(0, 0, 0, .5), 0 30px 60px rgba(0, 0, 0, .45);
    color-scheme: dark;
}

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

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

body {
    margin: 0;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    font-family: var(--font-ui);
    font-size: var(--t-md);
    line-height: 1.6;
    color: var(--ink);
    background-color: var(--paper);
    /* Halos d'heure dorée, très discrets, fixes derrière le contenu */
    background-image:
        radial-gradient(60rem 30rem at 12% -8%, rgba(245, 166, 35, .13), transparent 60%),
        radial-gradient(50rem 26rem at 92% 4%, rgba(232, 80, 47, .10), transparent 62%);
    background-attachment: fixed;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

::selection { background: rgba(232, 80, 47, .22); }

a { color: var(--ember-text); text-underline-offset: .18em; text-decoration-thickness: .08em; }
a:hover { color: var(--ember-text-hover); }

:focus-visible { outline: 2px solid var(--focus-line); outline-offset: 2px; border-radius: 4px; }

hr { border: 0; border-top: 1px solid var(--line); margin: 2rem 0; }

img, video, canvas, svg { max-width: 100%; }

code, kbd, samp {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
    font-size: .9em;
    background: var(--surface-2);
    padding: .15em .4em;
    border-radius: 6px;
}

.skip {
    position: absolute;
    left: -9999px;
    top: .5rem;
    background: var(--ink);
    color: var(--paper);
    padding: .6rem 1rem;
    border-radius: var(--r-sm);
    z-index: 100;
}
.skip:focus { left: .5rem; }

/* ---------- 4. Typographie ---------- */
h1, h2, h3, h4 {
    font-family: var(--font-display);
    font-variation-settings: "SOFT" 28, "WONK" 1, "opsz" 96;
    font-weight: 620;
    line-height: 1.08;
    letter-spacing: -.018em;
    margin: 0 0 .5em;
    text-wrap: balance;
}
h1 { font-size: var(--t-3xl); }
h2 { font-size: var(--t-2xl); margin-top: 1.6em; }
h3 { font-size: var(--t-xl); margin-top: 1.4em; }
h4 { font-size: var(--t-lg); font-variation-settings: "SOFT" 20, "WONK" 0, "opsz" 30; }

p { margin: 0 0 1em; max-width: var(--measure); text-wrap: pretty; }

.lead { font-size: var(--t-lg); color: var(--ink-2); max-width: 54ch; }

.muted { color: var(--muted-ink); font-size: var(--t-sm); }

.eyebrow {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--ember-text);
    margin-bottom: .9rem;
}
.eyebrow::before {
    content: "";
    width: 1.6rem;
    height: 3px;
    border-radius: 2px;
    background: var(--mirror);
}

/* Mot souligné par le dégradé palindrome */
.glow {
    background: var(--mirror);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}
.underline-mirror {
    background: var(--mirror) bottom / 100% .28em no-repeat;
    background-position-y: 92%;
    padding: 0 .08em;
    border-radius: 2px;
}

/* ---------- 5. Mise en page ---------- */
.page, .container {
    width: min(100% - 2rem, 76rem);
    margin-inline: auto;
    /* En paysage, l'encoche mange un bord : le texte s'en écarte, les fonds pleine largeur restent pleins. */
    padding-inline: env(safe-area-inset-left, 0px) env(safe-area-inset-right, 0px);
}
.page { flex: 1; padding-block: clamp(1.5rem, 1rem + 2vw, 3rem) clamp(3rem, 2rem + 4vw, 5rem); }
.container--narrow { width: min(100% - 2rem, 48rem); }
.container--wide { width: min(100% - 2rem, 88rem); }

.section { padding-block: var(--section); }
.section--tint { background: var(--surface-2); }

.stack > * + * { margin-top: var(--gap); }
.stack--lg > * + * { margin-top: 2rem; }

.cluster { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; }
.cluster--between { justify-content: space-between; }

.grid { display: grid; gap: clamp(1rem, .6rem + 1.4vw, 1.8rem); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); }

.split { display: grid; gap: clamp(1.5rem, 1rem + 3vw, 4rem); align-items: center; }
@media (min-width: 62rem) { .split { grid-template-columns: 1.05fr .95fr; } }

/* ---------- 6. En-tête ---------- */
.top {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    gap: 1rem;
    /* L'encoche et les coins arrondis d'un téléphone : la barre se pose dessous, jamais dessous le verre. */
    padding: calc(.7rem + env(safe-area-inset-top, 0px)) max(clamp(1rem, .5rem + 2vw, 2rem), env(safe-area-inset-right, 0px))
             .7rem max(clamp(1rem, .5rem + 2vw, 2rem), env(safe-area-inset-left, 0px));
    background: var(--paper);
    background: color-mix(in srgb, var(--paper) 82%, transparent);
    backdrop-filter: saturate(1.4) blur(14px);
    -webkit-backdrop-filter: saturate(1.4) blur(14px);
    border-bottom: 1px solid transparent;
    transition: border-color .25s, box-shadow .25s;
}
.top.is-stuck { border-bottom-color: var(--line); box-shadow: var(--shadow-1); }

.brand {
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    font-family: var(--font-display);
    flex-shrink: 0;
    font-weight: 700;
    font-size: 1.45rem;
    letter-spacing: -.02em;
    color: var(--ink);
    text-decoration: none;
    margin-right: auto;
}
.brand:hover { color: var(--ink); }
.brand .brand-logo { display: block; height: 2rem; width: auto; overflow: visible; }
/* Le rapport est dit : sans lui, Safari donne à un SVG en hauteur fixe une largeur qui ne suit pas, dans une boîte
   flexible comme l'en-tête. Et le symbole du logo, posé une fois dans la page, ne doit rien occuper. */
.brand-logo { aspect-ratio: 172 / 44; }
.brand-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.top nav { display: flex; gap: .3rem; align-items: center; }
.top nav a {
    padding: .5rem .75rem;
    border-radius: 999px;
    color: var(--ink-2);
    font-size: var(--t-sm);
    font-weight: 500;
    text-decoration: none;
    transition: background .18s, color .18s;
}
.top nav a:hover { background: var(--surface-2); color: var(--ink); }
.top nav a.is-current { color: var(--ink); background: var(--surface-2); }
/* hide-lg, hide-md : les liens qui cèdent leur place, l'un après l'autre, avant que les libellés ne passent sur deux
   lignes (« Pour qui ? » au sprint 21, « Appareil jetable » au sprint 18). */
@media (max-width: 66rem) {
    .top nav a.hide-lg { display: none; }
}
@media (max-width: 60rem) {
    .top nav a.hide-md { display: none; }
}
@media (max-width: 46rem) {
    .top nav a.hide-sm { display: none; }
}
@media (max-width: 26rem) {
    .top { gap: .5rem; }
    .top .brand-logo { height: 1.65rem; }
    .top nav { gap: .15rem; }
    .top nav a { padding: .5rem; font-size: .8125rem; }
}
@media (max-width: 22rem) {
    .top .brand-logo { height: 1.35rem; }
}

/* Menu du téléphone (ulalu.js pose .has-menu et révèle le bouton) : sous 52rem, tous les liens de l'en-tête passent dans
   un panneau qui s'ouvre sous lui — y compris ceux que les largeurs moyennes cachent. Sans script, l'en-tête passe à la
   ligne plutôt que de déborder : connecté, « Déconnexion » sortait de l'écran (2026-09-19).

   52rem (832 px) et non 46rem (736 px) : mesuré le 2026-09-21, entre 737 et ~810 px la barre horizontale ne tenait plus
   sur une ligne et le bouton du menu n'était pas encore là — l'en-tête passait de 63 à 86 px, navigation sur deux
   lignes. L'iPad en portrait fait 768 px et tombait en plein dedans, connecté comme déconnecté ; et « Appareil
   jetable », caché par hide-md dès 60rem, n'avait alors aucun autre chemin. Le panneau les rend tous (plus bas). */
.top__toggle { display: none; }
@media (max-width: 52rem) {
    .top:not(.has-menu) { flex-wrap: wrap; }
    .top:not(.has-menu) nav { flex-wrap: wrap; justify-content: flex-end; }

    .top.has-menu .top__cta { order: 2; }
    .top.has-menu .top__toggle {
        order: 3;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        flex-shrink: 0;
        width: 2.75rem;
        height: 2.75rem;
        padding: 0;
        border: 1px solid var(--line);
        border-radius: 999px;
        background: transparent;
        color: var(--ink);
        cursor: pointer;
    }
    .top.has-menu .top__toggle:hover { background: var(--surface-2); }
    .top.has-menu nav {
        display: none;
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        flex-direction: column;
        align-items: stretch;
        gap: .15rem;
        max-height: calc(100dvh - 4.5rem);
        overflow-y: auto;
        padding: .5rem clamp(1rem, .5rem + 2vw, 2rem) 1rem;
        background: var(--paper);
        border-bottom: 1px solid var(--line);
        box-shadow: var(--shadow-2);
    }
    .top.has-menu.is-open nav { display: flex; }
    .top.has-menu nav a,
    .top.has-menu nav a.hide-sm,
    .top.has-menu nav a.hide-md,
    .top.has-menu nav a.hide-lg { display: block; padding: .8rem 1rem; border-radius: .75rem; font-size: var(--t-md); }
    .top.has-menu nav .inline { display: block; }
    .top.has-menu nav button.link { width: 100%; text-align: left; padding: .8rem 1rem; border-radius: .75rem; font-size: var(--t-md); }
}
.top__bars,
.top__bars::before,
.top__bars::after {
    display: block;
    width: 1.15rem;
    height: 2px;
    border-radius: 2px;
    background: currentColor;
    transition: transform .2s, background-color .2s;
}
.top__bars { position: relative; }
.top__bars::before,
.top__bars::after { content: ""; position: absolute; left: 0; }
.top__bars::before { top: -6px; }
.top__bars::after { top: 6px; }
.top__toggle[aria-expanded="true"] .top__bars { background: transparent; }
.top__toggle[aria-expanded="true"] .top__bars::before { transform: translateY(6px) rotate(45deg); }
.top__toggle[aria-expanded="true"] .top__bars::after { transform: translateY(-6px) rotate(-45deg); }

.inline { display: inline; }
button.link {
    background: none;
    border: 0;
    padding: .5rem .75rem;
    color: var(--ink-2);
    font: inherit;
    font-size: var(--t-sm);
    font-weight: 500;
    cursor: pointer;
    border-radius: 999px;
}
button.link:hover { background: var(--surface-2); color: var(--ink); }

/* ---------- 7. Boutons ---------- */
.button, button.primary, button.secondary, button.danger, .btn {
    --btn-bg: var(--ink);
    --btn-fg: var(--paper);
    --btn-line: transparent;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    padding: .72rem 1.25rem;
    border: 1px solid var(--btn-line);
    border-radius: 999px;
    background: var(--btn-bg);
    color: var(--btn-fg);
    font: inherit;
    font-weight: 600;
    font-size: var(--t-sm);
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
    transition: transform .16s cubic-bezier(.2, .8, .2, 1), box-shadow .2s, background .2s, color .2s;
}
.button:hover, button.primary:hover, button.secondary:hover, button.danger:hover, .btn:hover {
    transform: translateY(-1px);
    box-shadow: var(--shadow-2);
    color: var(--btn-fg);
}
.button:active, button.primary:active, .btn:active { transform: translateY(0); box-shadow: var(--shadow-1); }
.button:focus-visible, button:focus-visible {
    outline: 2px solid var(--focus-line);
    outline-offset: 2px;
    box-shadow: var(--focus);
}
.button[disabled], button[disabled] { opacity: .5; cursor: not-allowed; transform: none; box-shadow: none; }
/* Envoyé, en attente de la réponse (data-submit-once dans ulalu.js) : l'appui a été pris. */
button[aria-busy="true"] { opacity: .7; cursor: progress; transform: none; box-shadow: none; }

.button, button.primary, .btn--primary {
    --btn-bg: var(--btn-solid);
    --btn-fg: var(--btn-ink);
    background-image: linear-gradient(180deg, var(--btn-sheen), var(--btn-solid));
}

button.secondary, .btn--ghost {
    --btn-bg: var(--surface);
    --btn-fg: var(--ink);
    --btn-line: var(--line-strong);
    background-image: none;
}

button.danger, .btn--danger {
    --btn-bg: var(--surface);
    --btn-fg: var(--danger);
    --btn-line: color-mix(in srgb, var(--danger) 35%, var(--line));
    background-image: none;
}

.btn--lg { padding: .95rem 1.7rem; font-size: var(--t-md); }
.btn--sm { padding: .42rem .8rem; font-size: var(--t-xs); }
/* Une commande se vise au doigt. Le site posait déjà 44 px à trois endroits — la pellicule, la vue agrandie, le tri —
   et nulle part ailleurs : les puces de la FAQ tombaient à 31 px, le retrait de la mesure aussi. Posé ici une fois,
   pour tous. La petite taille garde sa densité à la souris et retrouve le pouce sur un écran tactile. */
.button, button.primary, button.secondary, button.danger, .btn { min-height: 44px; }
.btn--sm { min-height: 34px; }
@media (pointer: coarse) {
    .btn--sm { min-height: 44px; }
}
.btn--block { width: 100%; }

/* Un bouton d'une seule icône, pour un geste répété sur chaque élément d'une liste (les vignettes). Son nom est dans
   aria-label, et data-tip l'affiche en info-bulle au survol comme au clavier. L'info-bulle se place dans le premier
   parent positionné : c'est lui qui décide où elle tombe. */
.iconbtn {
    display: inline-grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--surface);
    color: var(--ink-2);
    cursor: pointer;
    transition: background .16s, color .16s, border-color .16s;
}
.iconbtn svg { display: block; }
.iconbtn:hover { background: var(--surface-2); border-color: var(--line-strong); color: var(--ink); }
.iconbtn--danger:hover { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 35%, var(--line)); }
.iconbtn.is-on { color: var(--ember-text); border-color: color-mix(in srgb, var(--ember) 45%, var(--line)); background: color-mix(in srgb, var(--ember) 10%, var(--surface)); }
.iconbtn.is-on svg { fill: currentColor; }
.iconbtn[data-tip]::after {
    content: attr(data-tip);
    position: absolute;
    right: 0;
    bottom: calc(100% + .35rem);
    z-index: 2;
    width: max-content;
    max-width: 8.5rem;
    padding: .3rem .5rem;
    border-radius: 8px;
    background: var(--ink);
    color: var(--paper);
    font-size: .75rem;
    font-weight: 500;
    line-height: 1.3;
    text-align: left;
    white-space: normal;
    pointer-events: none;
    opacity: 0;
    transform: translateY(3px);
    transition: opacity .12s, transform .12s;
}
.iconbtn[data-tip]:hover::after, .iconbtn[data-tip]:focus-visible::after { opacity: 1; transform: none; transition-delay: .12s; }
@media (pointer: coarse), (max-width: 48rem) {
    .iconbtn { width: 44px; height: 44px; }
}

/* Un bouton par palier de la Pellicule (D-186) : côte à côte quand chacun tient sur une ligne (l'essai), l'un sous
   l'autre sinon (une carte, une colonne du tableau). Posé ici et non dans site.css : l'essai ne charge pas site.css. */
.tier-buttons { display: grid; gap: .45rem; width: 100%; }
.tier-buttons__legend { margin: 0; font-size: var(--t-sm); font-weight: 600; color: var(--ink-2); text-align: center; }
.tier-buttons__list { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 12.5rem), 1fr)); gap: .5rem; }
.tier-buttons__list .button { text-align: center; }
.button.tier-buttons__short { flex-direction: column; gap: 0; padding-inline: .45rem; line-height: 1.15; }
.tier-buttons__short span { white-space: nowrap; }
.tier-buttons__short span + span { font-weight: 500; }
/* Le bloc des paliers dans une carte ou une cellule dont les actions sont centrées : toute la largeur. */
.tier-choice { width: 100%; }

/* ---------- 8. Cartes ---------- */
.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: var(--pad);
    margin-block: 1.1rem;
    box-shadow: var(--shadow-1);
}
.card > :first-child { margin-top: 0; }
.card > :last-child { margin-bottom: 0; }
.card h2, .card h3 { margin-top: 0; }

.card--flat { box-shadow: none; background: transparent; }
.card--tint { background: var(--surface-2); border-color: transparent; }
.card--error { border-color: color-mix(in srgb, var(--danger) 40%, var(--line)); background: color-mix(in srgb, var(--danger) 6%, var(--surface)); }
.card--ok { border-color: color-mix(in srgb, var(--jade) 40%, var(--line)); background: color-mix(in srgb, var(--jade) 6%, var(--surface)); }
/* Un bandeau de confirmation ou d'erreur dit une phrase : elle court sur toute la largeur du bandeau, au lieu de revenir
   à la ligne à la mesure de lecture des paragraphes (p { max-width: var(--measure) }) en laissant un vide à droite. */
.card--ok > p, .card--error > p { max-width: none; }

/* Carte cliquable qui se soulève */
.card--link { display: block; color: inherit; text-decoration: none; transition: transform .2s cubic-bezier(.2, .8, .2, 1), box-shadow .25s, border-color .2s; }
.card--link:hover { transform: translateY(-3px); box-shadow: var(--shadow-2); border-color: var(--line-strong); color: inherit; }

/* Trait de marque en haut d'une carte mise en avant */
/* Un avertissement, pas une erreur : rien n'est cassé, il manque seulement quelque chose. */
.card--warn { border-color: color-mix(in srgb, var(--amber) 55%, var(--line)); background: color-mix(in srgb, var(--amber) 8%, var(--surface)); }

.card--featured { position: relative; overflow: hidden; }
.card--featured::before {
    content: "";
    position: absolute;
    inset: 0 0 auto;
    height: 4px;
    background: var(--mirror);
}

/* ---------- 9. Formulaires ---------- */
label { display: block; font-size: var(--t-sm); font-weight: 550; margin: .9rem 0 .35rem; color: var(--ink); }

input[type=text], input[type=email], input[type=password], input[type=date], input[type=number],
input[type=search], input[type=tel], input[type=url], select, textarea {
    width: 100%;
    padding: .72rem .9rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--r);
    font: inherit;
    color: var(--ink);
    background: var(--surface);
    transition: border-color .18s, box-shadow .18s;
}
input:focus, select:focus, textarea:focus { border-color: var(--ember-text); box-shadow: var(--focus); outline: none; }
input:focus-visible, select:focus-visible, textarea:focus-visible {
    outline: 2px solid var(--focus-line);
    outline-offset: 1px;
}
input::placeholder, textarea::placeholder { color: var(--muted-ink); }

/* L'œil d'un champ mot de passe (D-148), posé par ulalu.js : dans le champ, à droite, une cible de 44 px. Le texte
   s'arrête avant lui. L'œil natif d'Edge est retiré, sans quoi le champ en porterait deux. */
.pw { position: relative; display: block; }
.pw > input { padding-right: 3.2rem; }
.pw > input::-ms-reveal, .pw > input::-ms-clear { display: none; }
.pw__toggle {
    position: absolute;
    top: 50%;
    right: .2rem;
    transform: translateY(-50%);
    display: grid;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    border: 0;
    border-radius: var(--r-sm);
    background: transparent;
    color: var(--muted-ink);
    cursor: pointer;
}
.pw__toggle:hover, .pw__toggle.is-shown { color: var(--ink); }
.pw__toggle:hover { background: var(--surface-2); }
.pw__toggle:focus-visible { outline: 2px solid var(--focus-line); outline-offset: -2px; box-shadow: none; }
.pw__toggle svg { width: 1.3rem; height: 1.3rem; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.pw__toggle .pw__eye-off, .pw__toggle.is-shown .pw__eye { display: none; }
.pw__toggle.is-shown .pw__eye-off { display: block; }
textarea { min-height: 6rem; resize: vertical; }

input[type=file] {
    font: inherit;
    font-size: var(--t-sm);
    color: var(--ink-2);
    max-width: 100%;
}
input[type=file]::file-selector-button {
    font: inherit;
    font-weight: 600;
    font-size: var(--t-xs);
    margin-right: .8rem;
    padding: .5rem .9rem;
    border: 1px solid var(--line-strong);
    border-radius: 999px;
    background: var(--surface);
    color: var(--ink);
    cursor: pointer;
}

/* Cases et boutons radio : étiquette cliquable, cible confortable */
label:has(> input[type=checkbox]), label:has(> input[type=radio]) {
    display: flex;
    gap: .6rem;
    align-items: start;
    font-weight: 400;
    line-height: 1.45;
    cursor: pointer;
}
input[type=checkbox], input[type=radio] {
    accent-color: var(--ember);
    width: 1.1rem;
    height: 1.1rem;
    margin: .18rem 0 0;
    flex: none;
}

.field-help { font-size: var(--t-xs); color: var(--muted-ink); margin-top: .3rem; }
.error { color: var(--danger); font-size: var(--t-sm); margin-top: .5rem; }

/* Un formulaire refusé par le serveur : le message sous le champ à corriger se lit d'un coup d'œil, encadré plutôt
   qu'une ligne rouge en petit, et le champ se voit. ulalu.js amène la page à eux ([data-form-error]). */
.error--box {
    font-size: var(--t-md);
    font-weight: 550;
    padding: .7rem .9rem;
    border: 1px solid color-mix(in srgb, var(--danger) 40%, var(--line));
    border-left-width: 4px;
    border-radius: var(--r-sm);
    background: color-mix(in srgb, var(--danger) 7%, var(--surface));
}
.error--box:focus { outline: none; }
.error--box:focus-visible { outline: 2px solid var(--focus-line); outline-offset: 2px; }
input[aria-invalid=true], select[aria-invalid=true], textarea[aria-invalid=true] { border-color: var(--danger); }

fieldset { border: 1px solid var(--line); border-radius: var(--r); padding: var(--pad); margin: 1rem 0; }
legend { font-weight: 650; padding-inline: .4rem; }

/* ---------- 10. Pastilles et états ---------- */
.pill, .status {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .25rem .7rem;
    border-radius: 999px;
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: .01em;
    background: var(--surface-2);
    color: var(--ink-2);
    vertical-align: middle;
}
.status::before { content: ""; width: .45rem; height: .45rem; border-radius: 50%; background: currentColor; }
/* L'encre d'une pastille se mélange à --ink : le jeton de marque seul reste trop clair sur son propre fond
   teinté (le jade donnait 3,64 à 3,77:1, la braise 4,49:1, mesuré le 2026-09-21). Le mélange corrige les deux
   thèmes d'un coup, puisque --ink s'inverse avec eux — c'est l'idiome que ReviewReady et Draft utilisaient
   déjà dans app.css. L'ambre garde son brun écrit en dur : il passe déjà à 5,1:1, et un mélange l'assombrit
   trop pour rester de l'ambre. */
.status.Collecting { background: color-mix(in srgb, var(--jade) 14%, transparent); color: color-mix(in srgb, var(--jade) 75%, var(--ink)); }
.status.Closed, .status.Producing { background: color-mix(in srgb, var(--amber) 20%, transparent); color: #8a5a04; }
.status.PreviewReady { background: color-mix(in srgb, var(--ember) 14%, transparent); color: color-mix(in srgb, var(--ember-deep) 85%, var(--ink)); }
.status.Delivered { background: color-mix(in srgb, var(--plum) 14%, transparent); color: var(--plum); }
.status.Failed { background: color-mix(in srgb, var(--danger) 12%, transparent); color: var(--danger); }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .status.Closed, :root:not([data-theme="light"]) .status.Producing { color: var(--amber); }
    :root:not([data-theme="light"]) .status.PreviewReady { color: var(--ember); }
    :root:not([data-theme="light"]) .status.Delivered { color: #c6a6f0; }
}

/* ---------- 11. Galerie ---------- */
.gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); gap: .7rem; }

.tile {
    position: relative;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r);
    padding: .4rem;
    font-size: var(--t-xs);
    overflow: hidden;
    transition: border-color .18s, box-shadow .2s, transform .2s;
}
.tile:hover { box-shadow: var(--shadow-2); transform: translateY(-2px); }
.tile img {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border-radius: 9px;
    background: var(--surface-2);
    display: block;
}
/* Une photo qui s'ouvre en grand (espace organisateur) : un bouton qui n'a que l'image pour habit. Le contour du clavier
   passe dedans, la vignette coupant ce qui dépasse. */
.tile__open {
    display: block;
    width: 100%;
    padding: 0;
    border: 0;
    border-radius: 9px;
    background: none;
    cursor: zoom-in;
}
.tile__open:focus-visible { outline-offset: -2px; }
@media print {
    /* ulalu.css masque tous les boutons à l'impression : celui-ci est la photo. */
    .tile__open { display: block !important; }
}
.tile .ph {
    width: 100%;
    aspect-ratio: 4 / 3;
    border-radius: 9px;
    background: var(--surface-2);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--muted-ink);
}
.tile > div:not(.actions) {
    margin-top: .35rem;
    color: var(--muted-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.tile.removed { opacity: .42; }
.tile.essential { border-color: var(--ember); box-shadow: 0 0 0 2px color-mix(in srgb, var(--ember) 30%, transparent) inset; }
.tile.essential::after {
    content: "★";
    position: absolute;
    top: .55rem;
    right: .6rem;
    color: var(--ember);
    font-size: .85rem;
    text-shadow: 0 1px 3px rgba(0, 0, 0, .4);
}
.tile .actions { display: flex; gap: .35rem; margin-top: .4rem; flex-wrap: wrap; }
.tile .actions button { font-size: var(--t-xs); padding: .3rem .6rem; }
.tile .actions form { display: contents; }

/* Le nom du fichier, et au bout de sa ligne les gestes en icônes (espace organisateur). L'info-bulle monte au-dessus
   des icônes, calée à droite, sur la photo : la vignette coupe ce qui dépasse. */
.tile > div.tile__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .35rem;
    overflow: visible;
    white-space: normal;
}
/* Au doigt, les icônes font 44 px : quand il ne reste plus 4 rem au nom, elles passent dessous, calées à droite. */
.tile__name { flex: 1 1 4rem; min-width: 4rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tile .tile__tools { position: relative; flex: none; flex-wrap: nowrap; gap: .25rem; margin: 0 0 0 auto; }
.tile .tile__tools .iconbtn { flex: none; padding: 0; min-height: 0; }
/* L'info-bulle prend la largeur de la vignette, pas une borne faite pour la plus étroite. */
.tile--tools { container-type: inline-size; }
.tile--tools .iconbtn[data-tip]::after { max-width: calc(100cqi - 1rem); }
/* Retirée, la vignette pâlit, pas le geste qui la remet. */
.tile--tools.removed { opacity: 1; }
.tile--tools.removed > :not(.tile__foot), .tile--tools.removed .tile__name { opacity: .42; }

/* ---------- 12. Dépôt de fichiers ---------- */
.drop {
    border: 2px dashed var(--line-strong);
    border-radius: var(--r-xl);
    padding: clamp(1.5rem, 1rem + 3vw, 3rem);
    text-align: center;
    background: var(--surface);
    transition: border-color .2s, background .2s, transform .2s;
}
.drop.is-over { border-color: var(--ember); background: color-mix(in srgb, var(--ember) 5%, var(--surface)); transform: scale(1.01); }
.drop input[type=file] { display: none; }
.drop .button { font-size: var(--t-md); padding: .9rem 1.6rem; }

.files { list-style: none; padding: 0; margin: 1rem 0; display: grid; gap: .45rem; }
.files li {
    background: var(--surface);
    border: 1px solid var(--line);
    border-left: 3px solid var(--line-strong);
    border-radius: var(--r-sm);
    padding: .6rem .8rem;
    font-size: var(--t-sm);
}
.files li.ok { border-left-color: var(--jade); }
.files li.bad { border-left-color: var(--danger); }
.files li.dup { border-left-color: var(--amber); }

.bar { height: 5px; background: var(--surface-2); border-radius: 3px; overflow: hidden; margin-top: .4rem; }
.bar i { display: block; height: 100%; width: 0; background: var(--mirror); background-size: 200% 100%; transition: width .25s ease-out; }

/* ---------- 13. Médias ---------- */
video {
    width: 100%;
    max-height: 72vh;
    background: #000;
    border-radius: var(--r-lg);
    display: block;
    box-shadow: var(--shadow-2);
}
audio { width: 100%; max-width: 30rem; height: 2.2rem; }

.linkbox {
    display: flex;
    gap: .7rem;
    align-items: center;
    flex-wrap: wrap;
    padding: .6rem .8rem;
    background: var(--surface-2);
    border-radius: var(--r);
    margin-block: .5rem;
}
.linkbox code { background: transparent; padding: 0; word-break: break-all; font-size: var(--t-sm); }

.qr {
    width: 10rem;
    height: 10rem;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: #fff;
    padding: .4rem;
}

.events { list-style: none; padding: 0; margin: 0; }
.events li {
    display: flex;
    justify-content: space-between;
    gap: .8rem;
    align-items: center;
    padding: .9rem 0;
    border-bottom: 1px solid var(--line);
}
.events li:last-child { border-bottom: 0; }

table { width: 100%; border-collapse: collapse; font-size: var(--t-sm); }
th, td { text-align: left; padding: .6rem .5rem; border-bottom: 1px solid var(--line); }
th { font-weight: 650; color: var(--ink-2); }

/* ---------- 14. Marketing ---------- */
.hero { position: relative; padding-block: clamp(2.5rem, 1.5rem + 5vw, 6rem) var(--section); }
.hero h1 { font-size: var(--t-4xl); font-variation-settings: "SOFT" 34, "WONK" 1, "opsz" 144; }
.hero .lead { font-size: clamp(1.08rem, 1rem + .5vw, 1.35rem); margin-bottom: 1.8rem; }

/* Tirages photo posés en désordre, comme sur une table */
.photo-stack { position: relative; aspect-ratio: 5 / 4; }
.photo-stack figure {
    position: absolute;
    margin: 0;
    width: 62%;
    border-radius: var(--r);
    overflow: hidden;
    background: var(--surface);
    padding: .5rem .5rem 1.6rem;
    box-shadow: var(--shadow-3);
    transition: transform .4s cubic-bezier(.2, .8, .2, 1);
}
/* height: auto est obligatoire, pas cosmétique : sans lui, l'attribut height="800" de <img> s'applique comme
   indice de présentation — la vignette fait 800 px de haut, déborde du .photo-stack qui n'en fait que 200,
   recouvre le texte du héros et pousse une barre de défilement horizontale sur téléphone. */
.photo-stack figure img { width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 8px; display: block; }
.photo-stack figure:nth-child(1) { left: 0; top: 6%; transform: rotate(-6deg); z-index: 2; }
.photo-stack figure:nth-child(2) { right: 0; top: 0; transform: rotate(5deg); z-index: 1; }
.photo-stack figure:nth-child(3) { left: 18%; bottom: 0; transform: rotate(2deg); z-index: 3; }
.photo-stack:hover figure:nth-child(1) { transform: rotate(-9deg) translateY(-6px); }
.photo-stack:hover figure:nth-child(2) { transform: rotate(8deg) translateY(-4px); }
.photo-stack:hover figure:nth-child(3) { transform: rotate(1deg) translateY(-8px); }

.steps { counter-reset: step; display: grid; gap: 1.2rem; padding: 0; list-style: none; }
.steps li {
    counter-increment: step;
    position: relative;
    padding-left: 3.4rem;
}
.steps li::before {
    content: counter(step);
    position: absolute;
    left: 0;
    top: -.15rem;
    width: 2.4rem;
    height: 2.4rem;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--mirror-soft);
    color: var(--ember-deep);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.05rem;
}
.steps li h3 { margin: 0 0 .25rem; font-size: var(--t-lg); }
.steps li p { margin: 0; color: var(--ink-2); }

.feature-icon {
    width: 2.8rem;
    height: 2.8rem;
    display: grid;
    place-items: center;
    border-radius: var(--r);
    background: var(--mirror-soft);
    color: var(--ember-deep);
    font-size: 1.3rem;
    margin-bottom: .8rem;
}

.price { font-family: var(--font-display); font-size: var(--t-3xl); font-weight: 700; line-height: 1; }
.price small { font-family: var(--font-ui); font-size: var(--t-sm); font-weight: 500; color: var(--muted-ink); }

/* L'offre de lancement (D-208) : sous un grand prix, « Prix de lancement jusqu'au 8 novembre, au lieu de 49 € », le
   prix habituel barré ; au-dessus de l'en-tête, une ligne qui l'annonce. « Au lieu de » dit le barré en mots, à l'œil
   comme aux lecteurs d'écran ; ni compte à rebours, ni pastille, ni couleur seule. */
.intro-price {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .15rem .3em;
    margin: .35rem 0 0;
    font-size: var(--t-sm);
    color: var(--ember-text);
    font-weight: 600;
}
/* « au lieu de » et le prix barré restent ensemble : un seul élément de la ligne, qui passe à la ligne d'un bloc. */
.intro-price__instead { color: var(--muted-ink); font-weight: 500; white-space: nowrap; }
.intro-price__was { color: inherit; text-decoration-thickness: 1px; }
.intro-band {
    max-width: none;
    margin: 0;
    background: var(--btn-solid);
    color: var(--btn-ink);
    font-size: var(--t-sm);
    font-weight: 600;
    line-height: 1.35;
    text-align: center;
}
/* Toute la ligne est le lien : une cible pleine largeur, et un seul arrêt du clavier. */
.intro-band a {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .15rem .8rem;
    padding: .55rem 1rem;
    color: inherit;
    text-decoration: none;
}
.intro-band a:hover, .intro-band a:focus-visible { color: inherit; }
.intro-band a:focus-visible { outline: 2px solid currentColor; outline-offset: -4px; }
.intro-band__more { text-decoration: underline; text-underline-offset: .2em; }
.intro-band a:hover .intro-band__more { text-decoration-thickness: 2px; }
.intro-band__narrow { display: none; }
@media (max-width: 40rem) {
    .intro-band__wide, .intro-band__more { display: none; }
    .intro-band__narrow { display: inline; text-decoration: underline; text-underline-offset: .2em; }
    /* Le prix de l'offre de la page (D-214), sur sa propre ligne : une ligne de plus, la seule du premier écran qui
       dise ce que le lancement change. */
    .intro-band__offer { flex-basis: 100%; }
}

.check-list { list-style: none; padding: 0; margin: 1rem 0; display: grid; gap: .55rem; }
.check-list li { display: flex; gap: .6rem; align-items: start; font-size: var(--t-sm); }
.check-list li::before { content: "✓"; color: var(--jade); font-weight: 700; flex: none; }
.check-list li.no::before { content: "—"; color: var(--muted-ink); }

details.faq {
    border-bottom: 1px solid var(--line);
    padding: .3rem 0;
}
details.faq summary {
    cursor: pointer;
    padding: .95rem .5rem .95rem 0;
    font-weight: 600;
    list-style: none;
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    align-items: center;
}
details.faq summary::-webkit-details-marker { display: none; }
details.faq summary::after { content: "+"; color: var(--ember); font-size: 1.4rem; line-height: 1; transition: transform .2s; }
details.faq[open] summary::after { transform: rotate(45deg); }
details.faq p { padding: 0 0 1rem; color: var(--ink-2); margin: 0; }
/* Un repli qui cache un bloc entier — une liste, une grille de cartes — et non un seul paragraphe (sprint 23) :
   même pastille « + » que la FAQ, avec l'espace qu'un bloc demande sous son résumé. */
details.faq > ul,
details.faq > .grid { margin: 0 0 1.2rem; }

.quote {
    font-family: var(--font-display);
    font-size: var(--t-xl);
    font-variation-settings: "SOFT" 40, "WONK" 1, "opsz" 60;
    line-height: 1.32;
    margin: 0;
}
.quote footer { font-family: var(--font-ui); font-size: var(--t-sm); color: var(--muted-ink); margin-top: .8rem; }

/* Bande sombre pour les sections à fort contraste */
.band {
    background: linear-gradient(160deg, #1c1526, #241a2e 55%, #2b1d2a);
    color: #f7f1ea;
    border-radius: var(--r-xl);
    padding: clamp(1.8rem, 1.2rem + 3vw, 3.5rem);

    /* Un îlot de nuit dans une page claire : son bouton prend les jetons du mode sombre, braise vive et encre de
       nuit. Avec ceux du thème clair, le libellé passait bien (crème sur braise profonde, 5,2:1) mais la forme se
       détachait mal du fond de l'îlot (2,9:1). Ici les deux passent : 4,9:1 pour le texte, 4,2:1 pour la forme —
       et c'est le bouton de la page de partage, celle que le couple envoie à tous ses invités. */
    --btn-solid: var(--ember);
    --btn-sheen: color-mix(in srgb, var(--ember) 92%, #fff);
    --btn-ink: #14101a;
}
.band h2, .band h3 { color: #fff; }
.band p { color: #d8cfdb; }
.band .muted { color: #a99fb0; }

/* ---------- 15. Pied de page ---------- */
.foot {
    border-top: 1px solid var(--line);
    background: var(--surface);
    padding-block: 2.5rem calc(2rem + env(safe-area-inset-bottom, 0px));
    margin-top: auto;
}
.foot .container { display: grid; gap: 1.6rem; }
/* Quatre colonnes de liens (le service, pour qui, informations, contact) : la présentation passe au-dessus sur une
   tablette, à côté sur un grand écran (sprint 21). */
@media (min-width: 48rem) {
    .foot .container { grid-template-columns: repeat(4, 1fr); }
    .foot .container > div:first-child { grid-column: 1 / -1; }
}
@media (min-width: 62rem) {
    .foot .container { grid-template-columns: 1.2fr repeat(4, 1fr); }
    .foot .container > div:first-child { grid-column: auto; }
}
/* Les titres de colonne sont des h2 : en h4 sous le h2 de la page, chaque page du site sautait un niveau dans son
   plan (mesuré le 2026-09-21). Ils gardent leur apparence de petite capitale. */
.foot h2 { font-family: var(--font-ui); font-size: var(--t-xs); font-weight: 600; line-height: 1.6; letter-spacing: .1em; text-transform: uppercase; color: var(--muted-ink); margin: 0 0 .7rem; }
.foot ul { list-style: none; padding: 0; margin: 0; display: grid; gap: .45rem; }
.foot a { color: var(--ink-2); text-decoration: none; font-size: var(--t-sm); }
.foot a:hover { color: var(--ember-text); }
/* Au doigt, ces liens faisaient 17 px de haut pour 33 px d'écartement : conformes à WCAG 2.2 par l'espacement,
   mais loin des 44 px que docs/08 promet. Le lien prend toute la ligne et la ligne fait 44 px. À la souris, rien
   ne bouge : le pied de page resterait deux fois trop long pour ce qu'il contient. */
@media (pointer: coarse) {
    .foot ul { gap: 0; }
    .foot li > a { display: flex; align-items: center; min-height: 44px; }
}
.foot .legal { max-width: none; grid-column: 1 / -1; border-top: 1px solid var(--line); padding-top: 1.2rem; font-size: var(--t-xs); color: var(--muted-ink); display: flex; flex-wrap: wrap; gap: .8rem; justify-content: space-between; }

/* ---------- 16. Utilitaires ---------- */
.center { text-align: center; }
.center p, .center .lead { margin-inline: auto; }
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }
.mt-2 { margin-top: 1.2rem; }
.hide { 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;
}
.rule { height: 3px; width: 4rem; border-radius: 2px; background: var(--mirror); margin: 1.2rem 0; }
.center .rule { margin-inline: auto; }

/* ---------- 17. Mouvement ---------- */
[data-reveal] { opacity: 0; transform: translateY(14px); }
[data-reveal].is-in { opacity: 1; transform: none; transition: opacity .6s ease, transform .6s cubic-bezier(.2, .8, .2, 1); }
/* Ce qui est déjà à l'écran au premier rendu n'entre pas dans le champ : il y est. Le faire apparaître en
   fondu retardait de six dixièmes de seconde le premier contact avec la page — le héros compris. L'animation
   reste pour ce qui entre ensuite, au défilement, ce que la règle 2 de docs/08 appelle guider. */
[data-reveal].is-now { transition: none; }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
    [data-reveal] { opacity: 1; transform: none; }
    .photo-stack figure, .photo-stack:hover figure { transition: none; }
}

@media print {
    .top, .foot, .button, button { display: none !important; }
    body { background: #fff; }
}

/* ---------- 18. Vitrine (D-153) ---------- */
/* Le lien « Livre d'or » de l'en-tête et sa règle hide-xl ont disparu avec le menu « Offres » (D-166) : le livre d'or y a
   sa ligne, comme les autres offres. */

/* ---------- 19. Le menu « Offres » de l'en-tête (D-166) ---------- */
/* Un <details> : son résumé a l'allure d'un lien de l'en-tête, avec un chevron ; son panneau tombe sous lui, centré. */
.navmenu { position: relative; }
.navmenu__toggle {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .5rem .6rem .5rem .75rem;
    border-radius: 999px;
    color: var(--ink-2);
    font-size: var(--t-sm);
    font-weight: 500;
    cursor: pointer;
    list-style: none;
    user-select: none;
    transition: background .18s, color .18s;
}
.navmenu__toggle::-webkit-details-marker { display: none; }
.navmenu__toggle:hover,
.navmenu[open] > .navmenu__toggle,
.navmenu__toggle.is-current { background: var(--surface-2); color: var(--ink); }
.navmenu__chev { width: 1rem; height: 1rem; transition: transform .2s; }
.navmenu[open] .navmenu__chev { transform: rotate(180deg); }
.navmenu__panel {
    position: absolute;
    top: calc(100% + .55rem);
    left: 50%;
    z-index: 60;
    width: min(23rem, calc(100vw - 2rem));
    translate: -50% 0;
    padding: .5rem;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-3);
}
.navmenu__list { list-style: none; margin: 0; padding: 0; display: grid; gap: .15rem; }
/* .top nav a pose la pilule des liens de l'en-tête : les lignes du menu la défont. */
.top nav .navmenu__item {
    display: grid;
    gap: .15rem;
    padding: .65rem .8rem;
    border-radius: var(--r);
    color: var(--ink);
    font-size: var(--t-sm);
}
.top nav .navmenu__item:hover,
.top nav .navmenu__item[aria-current="page"] { background: var(--surface-2); }
.navmenu__head { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; }
.navmenu__name { font-weight: 650; }
.navmenu__price { font-size: var(--t-xs); font-weight: 600; color: var(--ink-2); white-space: nowrap; font-variant-numeric: tabular-nums; }
.navmenu__what { color: var(--muted-ink); font-size: var(--t-xs); line-height: 1.35; }
.navmenu__foot {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: .25rem;
    margin: .35rem 0 0;
    padding: .45rem .3rem 0;
    border-top: 1px solid var(--line);
}
.top nav .navmenu__foot a { padding: .45rem .5rem; font-weight: 600; color: var(--ember-text); }
.top nav .navmenu__foot a:hover { color: var(--ember-text-hover); }

/* Dans le panneau du téléphone : le menu s'ouvre avec lui (ulalu.js), et ses lignes y sont des lignes du panneau, sans
   carte flottante. Même spécificité que les règles du panneau plus haut, pour les défaire. */
@media (max-width: 52rem) {
    .top.has-menu nav .navmenu { display: block; }
    .top.has-menu nav .navmenu__toggle { display: flex; padding: .8rem 1rem; border-radius: .75rem; font-size: var(--t-md); }
    .top.has-menu nav .navmenu__panel {
        position: static;
        width: auto;
        translate: none;
        padding: 0 0 .3rem .6rem;
        border: 0;
        border-radius: 0;
        box-shadow: none;
        background: transparent;
    }
    .top.has-menu nav a.navmenu__item { display: grid; padding: .6rem 1rem; font-size: var(--t-sm); }
    .top.has-menu nav .navmenu__foot { border-top: 0; margin: 0; padding: 0 .5rem; }
    /* 44 px au doigt, comme les autres lignes du panneau : « Comparer les offres » en faisait 39 (mesuré le 2026-09-27). */
    .top.has-menu nav .navmenu__foot a { display: inline-flex; align-items: center; min-height: 44px; padding: .5rem .5rem; font-size: var(--t-sm); }
}

/* ---------- Google Analytics : la question, posée une fois (D-202) ----------
   Une carte au bas de l'écran, qui ne bloque rien : la page reste utilisable sans répondre, et sans réponse Google ne se
   charge pas. Elle passe sous l'en-tête (50), les menus et les dialogues, et sous le viseur de l'appareil photo (1000) ;
   la barre d'envoi collante de la page invité monte au-dessus d'elle (guest.css, --consent-offset, mesuré par
   analytics.js), et la page s'allonge d'autant pour que rien ne reste caché derrière. */
.consent {
    position: fixed;
    left: max(.75rem, env(safe-area-inset-left));
    right: max(.75rem, env(safe-area-inset-right));
    bottom: max(.75rem, env(safe-area-inset-bottom));
    z-index: 45;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .6rem 1rem;
    max-width: 44rem;
    margin-inline: auto;
    padding: .75rem .9rem;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--line-strong);
    border-radius: var(--r);
    box-shadow: var(--shadow-3);
    font-size: var(--t-sm);
    line-height: 1.45;
}
.consent[hidden] { display: none; }
.consent p { flex: 1 1 18rem; margin: 0; }
.consent a { color: var(--ember-text); font-weight: 600; }
.consent__actions { display: flex; flex: 0 0 auto; gap: .5rem; margin-left: auto; }
/* « Accepter » en vert (Rachid, 2026-09-29) : le jade assombri, pour un texte blanc à 5,5:1 ; un fond simple d'abord,
   pour les navigateurs sans color-mix. « Refuser » garde la même taille, à côté. */
.consent .consent__accept { background: #12765d; background: color-mix(in srgb, var(--jade) 88%, #000); border-color: transparent; color: #fff; }
.consent .consent__accept:hover { background: #0f624d; background: color-mix(in srgb, var(--jade) 74%, #000); color: #fff; }
html.has-consent body { padding-bottom: var(--consent-offset, 0px); }
/* Sur un téléphone (D-214), la carte prenait 142 px sur 812 : plus serrée, le texte un cran plus petit, les deux boutons
   toujours de la même taille et côte à côte. */
@media (max-width: 40rem) {
    .consent { gap: .45rem .75rem; padding: .6rem .75rem; font-size: var(--t-xs); line-height: 1.4; }
    .consent p { flex-basis: 100%; }
}
