/* =====================================================================
   Ulalu — parcours invité (/c/{token}) et page de partage (/s/{token})
   ---------------------------------------------------------------------
   Complément de ulalu.css, chargé uniquement par ces deux pages. Rien
   n'est redéfini globalement : tout est préfixé .g- (guest) ou .s-
   (share), et toutes les couleurs viennent des jetons du système de
   design, donc le mode sombre suit sans une seule règle en plus.

   Conçu pour 380 px de large d'abord : une colonne, cibles tactiles de
   44 px minimum, barre d'envoi collée en bas de l'écran. Sur téléphone,
   l'essentiel (titre, zone de dépôt, progression globale, bouton) tient
   sans défilement.

   La page d'import de l'organisateur charge aussi cette feuille : elle
   utilise le même téléverseur, donc les mêmes composants .g-progress,
   .g-details, .g-item et .g-report.

   Sommaire : 1 base · 2 coquille · 3 zone de dépôt · 4 progression globale
   · 5 dépliant de détail · 6 liste de fichiers · 7 envoi · 8 résumé de fin
   · 9 confiance et pied · 10 page de partage · 11 téléphone · 12 mouvement
   ===================================================================== */

/* ---------- 1. Base ---------- */
[hidden] { display: none !important; }

/* ---------- 2. Coquille ---------- */
.g-shell {
    width: min(100%, 44rem);
    margin-inline: auto;
    display: flex;
    flex-direction: column;
    gap: clamp(1.1rem, .8rem + 1.2vw, 1.8rem);
}

.g-shell--center {
    min-height: min(70vh, 32rem);
    justify-content: center;
}

.g-shell--film { width: min(100%, 58rem); }

.g-hero { text-align: center; }
.g-hero .eyebrow { margin-bottom: .7rem; }
.g-hero h1 { font-size: var(--t-2xl); margin-bottom: .4rem; }
.g-hero .lead { margin-inline: auto; margin-bottom: 0; }

.g-empty { text-align: center; padding-block: clamp(1.6rem, 1rem + 3vw, 2.6rem); }
.g-empty .eyebrow { justify-content: center; }
.g-empty .lead { margin-inline: auto; }

.g-uploader {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* ---------- 3. Zone de dépôt ---------- */
.g-drop {
    margin: 0;
    display: grid;
    justify-items: center;
    gap: .35rem;
    position: relative;
}
.g-drop h2 { font-size: var(--t-xl); margin: .2rem 0 0; }
.g-drop__hint { max-width: 34ch; margin: 0; }

/* L'entrée reste focalisable au clavier : masquée à l'œil, pas au clavier.
   (ulalu.css met display:none sur .drop input[type=file], on le reprend.)
   Partout où .g-input paraît, et non dans la seule zone .drop : le repli du message vocal et la photo qui
   l'accompagne (D-141) portent la même classe et le même couple entrée + étiquette, et laissaient voir
   « Choisir un fichier · Aucun fichier choisi » à côté du bouton dessiné. */
input[type=file].g-input {
    display: block;
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    margin: 0;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
}
input[type=file].g-input:focus-visible + label {
    box-shadow: var(--focus);
    outline: 2px solid var(--ember);
    outline-offset: 2px;
}

.g-drop__art {
    width: 4.2rem;
    height: 4.2rem;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--mirror-soft);
    color: var(--ember-deep);
    margin-bottom: .3rem;
}
.g-drop__art svg { width: 2.1rem; height: 2.1rem; display: block; }

.g-drop__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .6rem;
    margin-top: .9rem;
    width: 100%;
}
.g-drop__actions .button { min-height: 44px; flex: 1 1 14rem; max-width: 22rem; }

/* Le gabarit donne une marge verticale à tout <label> de formulaire. Sur les
   boutons d'une zone de dépôt (qui sont des <label>), elle ajoutait 40 px de
   vide sous le pouce, pour rien. Vaut aussi pour la page d'import. */
.drop label.button { margin: 0; }

/* Sur un écran tactile, « glissez vos fichiers dans ce cadre » ne veut rien
   dire : on rend la hauteur au reste. */
@media (pointer: coarse) {
    .g-drop__hint { display: none; }
}

/* Le bouton « appareil photo » n'a de sens qu'au doigt. */
.g-touch-only { display: none; }
@media (pointer: coarse) {
    .g-touch-only { display: inline-flex; }
}

.g-limits { margin: .9rem 0 0; font-size: var(--t-xs); }

.g-net {
    margin: 0;
    padding: .7rem .9rem;
    border-radius: var(--r);
    background: color-mix(in srgb, var(--amber) 18%, var(--surface));
    border: 1px solid color-mix(in srgb, var(--amber) 45%, var(--line));
    color: var(--ink);
    font-size: var(--t-sm);
}

/* ---------- 4. Progression globale ---------- */
/* Une seule barre en tête, lisible de loin : le pourcentage en grand, le
   compte de fichiers à droite, et sous la barre le volume, le débit observé
   et le temps restant. Chiffres tabulaires pour que rien ne tressaute. */
.g-progress {
    display: grid;
    gap: .3rem;
    padding: .55rem .7rem .5rem;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: var(--surface);
}
.g-progress .bar { height: 10px; border-radius: 5px; margin: 0; }

.g-progress__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .6rem;
}
.g-progress__pct {
    font-family: var(--font-display);
    font-variation-settings: "SOFT" 28, "WONK" 1, "opsz" 40;
    font-size: var(--t-xl);
    font-weight: 640;
    line-height: 1.05;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
}
.g-progress__count {
    font-size: var(--t-sm);
    color: var(--muted-ink);
    font-variant-numeric: tabular-nums;
    text-align: right;
}
.g-progress__foot {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: .1rem .8rem;
    margin: 0;
    font-size: var(--t-xs);
    font-variant-numeric: tabular-nums;
    min-height: 1.2em;              /* la ligne est réservée : l'arrivée du débit ne pousse rien */
}
.g-progress__foot span:empty { display: none; }

/* Pendant un envoi long, la barre suit le défilement : sur soixante photos,
   on doit pouvoir lire le reste de la page sans perdre l'avancement de vue.
   Elle se cale sous l'en-tête collant du gabarit. */
.g-progress.is-live {
    position: sticky;
    top: 3.4rem;
    z-index: 11;
    box-shadow: var(--shadow-2);
    /* Un fond simple d'abord : color-mix date d'iOS 16.2, et sans lui la barre flottante n'aurait aucun fond. */
    background: var(--surface);
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: saturate(1.4) blur(12px);
    -webkit-backdrop-filter: saturate(1.4) blur(12px);
}

/* ---------- 5. Dépliant de détail ---------- */
/* <details> natif : l'état plié et son annonce viennent du navigateur, on ne
   redessine que le chevron. Fermé par défaut au-delà d'une poignée de
   fichiers, ouvert par le script dès qu'un envoi échoue. */
.g-details { margin: 0; }
.g-details__summary {
    display: flex;
    align-items: center;
    gap: .55rem;
    min-height: 44px;
    padding: .3rem .55rem;
    border-radius: var(--r-sm);
    color: var(--ink-2);
    font-size: var(--t-sm);
    font-weight: 550;
    cursor: pointer;
    list-style: none;
    transition: background .18s, color .18s;
}
.g-details__summary::-webkit-details-marker { display: none; }
.g-details__summary::before {
    content: "";
    width: .45rem;
    height: .45rem;
    flex: 0 0 auto;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: translateY(-2px) rotate(-45deg);
    transition: transform .18s;
}
.g-details[open] > .g-details__summary::before { transform: translateY(-2px) rotate(45deg); }
.g-details__summary:hover { background: var(--surface-2); color: var(--ink); }
.g-details__summary:focus-visible { outline: 2px solid var(--ember); outline-offset: 2px; }
.g-details .g-files { margin-top: .3rem; }

/* ---------- 6. Liste de fichiers ---------- */
.g-files { margin: 0; gap: .5rem; }

.g-files .g-item { padding: .55rem .6rem .6rem; }

.g-item__row {
    display: grid;
    grid-template-columns: 3.4rem minmax(0, 1fr) 2.75rem;
    align-items: center;
    gap: .7rem;
}

.g-item__thumb {
    width: 3.4rem;
    height: 3.4rem;
    border-radius: var(--r-sm);
    overflow: hidden;
    background: var(--surface-2);
    display: grid;
    place-items: center;
    color: var(--muted-ink);
}
.g-item__thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.g-item__thumb.is-blank::after { font-size: 1.1rem; line-height: 1; }
.g-item__thumb.is-video::after { content: "\25B6"; }
.g-item__thumb.is-photo::after { content: "\25A6"; }

.g-item__meta { display: grid; gap: .1rem; min-width: 0; }

/* Nom tronqué proprement : la tête est rognée, la fin (et donc l'extension)
   reste toujours lisible. Le point de coupure suit la largeur réelle, sans
   qu'aucun script n'ait à mesurer quoi que ce soit. */
.g-item__name {
    display: flex;
    min-width: 0;
    font-weight: 550;
}
.g-item__name-head {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.g-item__name-tail { flex: 0 0 auto; white-space: nowrap; }
.g-item__sub { font-size: var(--t-xs); line-height: 1.35; }

.g-item__actions { display: flex; justify-content: flex-end; margin-top: .45rem; }
.g-item__retry { min-height: 44px; padding-inline: 1.1rem; }

.g-item__remove {
    width: 44px;
    height: 44px;
    justify-self: end;
    display: grid;
    place-items: center;
    border: 1px solid transparent;
    border-radius: 50%;
    background: none;
    color: var(--muted-ink);
    font: inherit;
    font-size: 1.4rem;
    line-height: 1;
    cursor: pointer;
    transition: background .18s, color .18s;
}
.g-item__remove:hover { background: var(--surface-2); color: var(--ink); }
.g-item__remove[disabled] { opacity: .35; cursor: not-allowed; }

.g-files .g-item .bar { margin-top: .5rem; }
.g-files .g-item.is-idle .bar { display: none; }
.g-files .g-item.ok .g-item__sub { color: var(--jade); }
.g-files .g-item.bad .g-item__sub { color: var(--danger); }
.g-files .g-item.dup .g-item__sub { color: #8a5a04; }
.g-files .g-item.ok .bar i,
.g-files .g-item.dup .bar i { background: none; background-color: var(--jade); }
.g-files .g-item.bad .bar i { background: none; background-color: var(--danger); }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .g-files .g-item.dup .g-item__sub { color: var(--amber); }
}
:root[data-theme="dark"] .g-files .g-item.dup .g-item__sub { color: var(--amber); }

/* ---------- 7. Envoi ---------- */
.g-who { margin: 0; }
.g-who__title { font-size: var(--t-lg); margin-bottom: .2rem; }
.g-who .field-help { margin-bottom: .2rem; }
/* Le champ ne doit pas finir collé au bas de la fenêtre quand le navigateur
   le fait défiler à l'ouverture du clavier. */
.g-who input, .g-who textarea { scroll-margin-bottom: 6rem; }

/* Sur téléphone, la barre d'envoi se colle en bas dès qu'il y a des fichiers :
   le geste principal reste sous le pouce. Sur écran large, rien à coller,
   et un bouton désactivé flottant sur une page vide n'aiderait personne. */
@media (max-width: 46rem) {
    .g-uploader:has(#filelist li) .g-send {
        position: sticky;
        /* Au-dessus de la question sur Google Analytics tant qu'elle est ouverte (D-202, analytics.js) : le geste
           principal n'est jamais caché par elle. */
        bottom: var(--consent-offset, 0px);
        z-index: 10;
        padding-bottom: max(.8rem, env(safe-area-inset-bottom));
        background: var(--paper);
        background: color-mix(in srgb, var(--paper) 88%, transparent);
        backdrop-filter: saturate(1.4) blur(12px);
        -webkit-backdrop-filter: saturate(1.4) blur(12px);
    }

    /* Clavier ouvert : iOS ne réduit pas la fenêtre de mise en page, un élément
       collé en bas passerait donc SOUS le clavier. Dès qu'un champ du bloc
       « qui envoie » a le focus, la barre reprend sa place dans le flux, juste
       sous le champ, où le navigateur la fait défiler avec lui. */
    .g-uploader:has(#filelist li):has(.g-who:focus-within) .g-send {
        position: static;
        background: none;
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
    }
}

.g-send {
    display: grid;
    gap: .45rem;
    padding: .8rem 0;
    margin-top: .2rem;
}
.g-send #send { min-height: 52px; }
.g-send__summary { margin: 0; text-align: center; min-height: 1.3em; }

/* Page d'import : même mécanique, mais c'est un outil, pas une cérémonie. */
.g-uploader--tool { margin-top: 1rem; }
.g-send--tool { justify-items: start; }
.g-send--tool .g-send__summary { text-align: left; }

/* ---------- 8. Résumé de fin ---------- */
/* Il énumère : reçus, doublons, refusés avec leurs motifs, échecs et reprise.
   Le ton de la carte suit le résultat (card--ok, card--error ou neutre), mais
   le texte dit la même vérité dans les trois cas. */
.g-report { margin: 0; }
.g-report:focus { outline: none; }
.g-report:focus-visible { outline: 2px solid var(--ember); outline-offset: 3px; }
.g-report__title {
    font-family: var(--font-display);
    font-variation-settings: "SOFT" 28, "WONK" 1, "opsz" 48;
    font-size: var(--t-xl);
    margin-bottom: .5rem;
}
.g-report__lines {
    list-style: none;
    padding: 0;
    margin: 0 0 .8rem;
    display: grid;
    gap: .35rem;
}
.g-report__lines li {
    position: relative;
    padding-left: 1.05rem;
    font-size: var(--t-sm);
    line-height: 1.5;
}
.g-report__lines li::before {
    content: "";
    position: absolute;
    left: 0;
    top: .58em;
    width: .38rem;
    height: .38rem;
    border-radius: 50%;
    background: var(--line-strong);
}
.g-report__resume { font-size: var(--t-sm); color: var(--ink-2); }
.g-report .button { min-height: 44px; }

/* ---------- 9. Confiance et pied ---------- */
.g-trust { margin: .6rem 0 0; }
.g-trust h2 { font-size: var(--t-lg); }
.g-trust .check-list { margin-bottom: .9rem; }
.g-trust .check-list li { font-size: var(--t-sm); line-height: 1.5; }

.g-foot {
    text-align: center;
    font-size: var(--t-xs);
    padding-block: .5rem 1rem;
}

/* « Et pour votre prochaine fête ? » (D-228) : ce qu'Ulalu fait, une fois que l'invité a donné. Comme la fin d'une page
   de partage : ni fond, ni ombre, ni bouton plein — la page reste celle de l'événement. */
.g-loop {
    display: grid;
    justify-items: center;
    gap: .45rem;
    text-align: center;
    padding-block: .4rem 1.1rem;
}
.g-loop[hidden] { display: none; }
.g-loop__title { font-size: var(--t-lg); margin: 0; }
.g-loop .g-loop__pitch { font-size: var(--t-sm); line-height: 1.5; margin: 0; max-width: 46ch; }

/* ---------- 10. Page de partage ---------- */
.s-stage {
    display: grid;
    gap: 1.2rem;
    justify-items: center;
    /* Moins de marge que .band par défaut : sur un téléphone, le film prime. */
    padding: clamp(1.1rem, .8rem + 2vw, 3rem);
    box-shadow: var(--shadow-3);
}
.s-stage__head { text-align: center; max-width: 46ch; }
.s-stage__head .eyebrow { color: var(--amber); justify-content: center; }
.s-stage__head .eyebrow::before { background: linear-gradient(90deg, var(--amber), #fff); }

.s-title {
    font-size: var(--t-3xl);
    font-variation-settings: "SOFT" 34, "WONK" 1, "opsz" 120;
    margin-bottom: .35rem;
    color: #fff;
}
.s-intro { margin: 0; font-size: var(--t-lg); }

.s-video {
    width: 100%;
    aspect-ratio: 16 / 9;
    max-height: 70vh;
    object-fit: contain;
    border-radius: var(--r);
    box-shadow: 0 18px 48px rgba(0, 0, 0, .45);
}

.s-actions {
    display: grid;
    justify-items: center;
    gap: .4rem;
    width: 100%;
}
.s-actions .button { min-height: 48px; }
.s-actions__hint { font-size: var(--t-xs); text-align: center; }

.s-music {
    margin: 0;
    font-size: var(--t-xs);
    text-align: center;
    max-width: 46ch;
}

.s-private {
    text-align: center;
    font-size: var(--t-xs);
    /* Centrée : un paragraphe a une largeur de lecture, et la ligne tombait à gauche du film sur un écran large. */
    margin: 0 auto;
}

.s-foot { text-align: center; padding-block: .5rem 1.5rem; }
.s-foot .rule { margin-inline: auto; }
.s-foot p { max-width: 46ch; margin-inline: auto; font-size: var(--t-xs); }

/* La fin d'une page de partage (D-163) : ce qu'Ulalu fait, et le chemin vers le site. Plus lisible que l'ancienne ligne
   seule, jamais à la hauteur du film : ni fond, ni ombre, ni bouton en grand. */
.s-invite { display: grid; justify-items: center; gap: .5rem; padding-block: .25rem 2rem; }
.s-invite .rule { margin-block: 0 .6rem; }
.s-invite p { margin-block: 0; }
.s-invite__title { font-size: var(--t-xl); margin: 0; }
.s-invite .s-invite__pitch { font-size: var(--t-sm); line-height: 1.5; }
.s-invite .s-invite__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .5rem;
    max-width: none;
    margin-top: .5rem;
}

/* ---------- 10 ter. La porte du livre (docs/09 § 44) ----------
   Une carte au-dessus de la vidéo du livre d'or, avec une petite couverture dessinée en CSS. Les deux seules couleurs en
   dur de la page sont celles du livre lui-même — son papier crème et sa reliure prune —, qui ne suivent pas le thème. */
.livre-door { display: flex; align-items: center; gap: 1rem; width: 100%; margin-block: 0; text-align: left; }
.livre-door__cover {
    flex: none;
    width: 3.4rem;
    height: 4.6rem;
    border-radius: 2px 6px 6px 2px;
    background: linear-gradient(90deg, #6e3d55 0 16%, #fcfaf7 16%);
    box-shadow: inset 0 0 0 1px #e4dad8, 0 6px 14px rgba(0, 0, 0, .25);
}
.livre-door__text { display: grid; gap: .15rem; min-width: 0; }
.livre-door__text .eyebrow { margin-bottom: .2rem; }
.livre-door__title { font-size: var(--t-lg); }
.livre-door__lead { font-size: var(--t-sm); color: var(--ink-2); }
.livre-door__counts { font-size: var(--t-xs); color: var(--ink-2); }

/* ---------- 10 bis. Accord promotionnel (festival, D-078) ----------
   Avant tout envoi : une case, son texte, et le rappel quand on l'oublie. */
.g-consent { margin: 0; border-color: color-mix(in srgb, var(--amber) 45%, var(--line)); }
.g-consent__title { font-size: var(--t-lg); margin-bottom: .5rem; }
.g-consent__label { font-weight: 550; margin: 0; }
.g-consent__label input[type=checkbox] { width: 1.35rem; height: 1.35rem; margin-top: .05rem; }
.g-consent .field-help { margin: .45rem 0 0; }
.g-consent__error { margin: .5rem 0 0; color: var(--danger); font-size: var(--t-sm); font-weight: 550; }

@media (min-width: 40rem) {
    .g-hero h1 { font-size: var(--t-3xl); }
    .g-item__row { grid-template-columns: 4rem minmax(0, 1fr) 2.75rem; }
    .g-item__thumb { width: 4rem; height: 4rem; }
    .s-stage { gap: 1.5rem; }
}

/* ---------- 11. Téléphone ---------- */
/* À 380 px, l'essentiel doit tenir sans défiler : le titre, la zone de dépôt,
   la progression globale et le bouton (collé en bas). On resserre donc le
   héros et le cadre de dépôt, sans jamais descendre sous 44 px de cible. */
@media (max-width: 30rem) {
    .g-shell { gap: .8rem; }
    .g-uploader { gap: .8rem; }
    .g-hero .eyebrow { margin-bottom: .45rem; }
    .g-hero h1 { font-size: var(--t-xl); }
    .g-hero .lead { font-size: var(--t-sm); line-height: 1.45; }

    .g-drop { padding: .9rem .85rem 1rem; border-radius: var(--r-lg); }
    .g-drop h2 { font-size: var(--t-lg); }
    .g-drop__hint { font-size: var(--t-sm); }
    .g-drop__art { width: 2.6rem; height: 2.6rem; margin-bottom: .1rem; }
    .g-drop__art svg { width: 1.35rem; height: 1.35rem; }
    .g-drop__actions { margin-top: .65rem; gap: .45rem; }
    .g-drop__actions .button { padding-block: .62rem; font-size: var(--t-sm); }
    .g-limits { margin-top: .55rem; font-size: var(--t-xs); line-height: 1.35; }

    .g-progress { padding: .5rem .6rem .45rem; }
    .g-progress__count { font-size: var(--t-xs); }

    .g-send { padding: .6rem 0; margin-top: 0; }
}

/* Écran court (vieil iPhone, navigateur avec barres d'outils) : on rend au
   contenu utile ce que prenait la décoration, pour que la barre globale et le
   bouton restent visibles sans défiler. Aucune cible ne passe sous 44 px. */
@media (max-width: 30rem) and (max-height: 44rem) {
    .g-shell { gap: .6rem; }
    .g-uploader { gap: .6rem; }
    .g-hero h1 { font-size: var(--t-lg); }
    .g-hero .lead { font-size: var(--t-xs); line-height: 1.4; }
    .g-drop__art { display: none; }
    .g-drop { padding: .75rem .8rem .85rem; }
    .g-drop h2 { font-size: var(--t-md); }
    .g-drop__actions { margin-top: .5rem; }
    .g-limits { margin-top: .45rem; }
    .g-send { padding: .45rem 0; }
}

/* ---------- 11 bis. Message vocal ----------
   Le bloc vit à côté du dépôt de fichiers, avec les mêmes cartes et les mêmes boutons :
   la voix est une contribution comme une autre, pas une option cachée. */
.g-voice__title { margin: 0 0 .2rem; font-size: var(--t-lg); }

.g-voice__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
    margin-top: .8rem;
}

/* Le micro du bouton d'enregistrement : la même famille de dessin que la tuile du hall. */
.g-voice__rec {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
}

.g-voice__mic {
    display: grid;
    place-items: center;
}

.g-voice__mic svg { width: 1.25rem; height: 1.25rem; }

.g-voice__timer {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-size: var(--t-md);
    color: var(--ink-2);
}

.g-voice__player { width: 100%; margin-top: .8rem; }

.g-voice__status { margin: .6rem 0 0; min-height: 1.2em; }
.g-voice__status--error { color: var(--danger); }
.g-voice__status--ok { color: var(--jade); }

/* Le point qui bat pendant l'enregistrement : le seul signal qu'on capte bien la voix. */
.g-voice__status--live::before {
    content: "";
    display: inline-block;
    width: .55rem;
    height: .55rem;
    margin-right: .45rem;
    border-radius: 50%;
    background: var(--danger);
    animation: g-pulse 1.4s ease-in-out infinite;
}

@keyframes g-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: .25; }
}

/* La page personnelle d'un invité (D-142) : une liste d'événements, pas une grille. */
.space__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* « Être prévenu » (D-142) : un bloc discret dans l'écran de ce qu'on a donné, jamais une étape. */
.g-follow input[type=email] { width: 100%; }

.g-follow__status { margin: .6rem 0 0; min-height: 1.2em; }
.g-follow__status--error { color: var(--danger); }
.g-follow__status--ok { color: var(--jade); }

/*
 * La photo qui accompagne le message (D-141). Elle n'apparaît qu'une fois le message enregistré :
 * avant, elle encombrerait un écran dont la seule action est de parler.
 */
.g-voice__photo {
    margin-top: .9rem;
    padding-top: .9rem;
    border-top: 1px solid var(--line);
}

.g-voice__photo-title { margin: 0 0 .15rem; font-weight: 600; }

.g-voice__photo-actions {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin: .6rem 0 0;
}

.g-voice__thumb {
    display: flex;
    align-items: center;
    gap: .7rem;
    margin: .7rem 0 0;
}

.g-voice__thumb-img {
    width: 4.5rem;
    height: 4.5rem;
    object-fit: cover;
    border-radius: var(--r-sm);
    border: 1px solid var(--line);
}

.g-voice__fallback { margin: .8rem 0 0; }

@media (prefers-reduced-motion: reduce) {
    .g-voice__status--live::before { animation: none; }
}

/* ---------- 11 ter. Vos photos ----------
   Les vignettes de l'invité ; celles qui sont dans le film sortent du lot. */
.mine__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(5rem, 1fr));
    gap: .4rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.mine__cell { position: relative; }

.mine__cell img {
    display: block;
    width: 100%;
    aspect-ratio: 1;
    object-fit: cover;
    border-radius: var(--r-sm);
    opacity: .72;
}

.mine__cell--in img {
    opacity: 1;
    outline: 2px solid var(--ember);
    outline-offset: -2px;
}

.mine__tag {
    position: absolute;
    left: 0;
    bottom: 0;
    margin: .25rem;
    padding: .05rem .35rem;
    border-radius: 999px;
    background: var(--ember);
    color: #fff;
    font-size: .7rem;
    line-height: 1.5;
}

/* Retrait par l'invité : une cible de 44 px au doigt, lisible sur une vignette claire comme sur une sombre. */
.mine__withdraw {
    position: absolute;
    top: 0;
    right: 0;
    min-width: 44px;
    min-height: 44px;
    padding: .15rem .4rem;
    border: 0;
    border-radius: var(--r-sm);
    background: rgba(20, 16, 26, .72);
    color: #fff;
    font-size: .72rem;
    line-height: 1.4;
    cursor: pointer;
}

.mine__withdraw:hover,
.mine__withdraw:focus-visible { background: rgba(20, 16, 26, .9); }

.mine__withdraw[disabled] { opacity: .5; cursor: default; }

/* ---------- 11 quater. Le livre d'or (docs/09 § 35) ----------
   Un écran, trois façons de laisser son message, une seule à la fois. Tout
   tient à 360 px : des rangées qui passent à la ligne, des cibles de 44 px,
   aucune largeur fixe. Les couleurs viennent des jetons, le mode sombre suit. */
.gb__title { margin: 0 0 .2rem; font-size: var(--t-lg); }

/* L'accord : une ligne juste au-dessus du bouton d'envoi (guestbook.js l'y pose), sans cadre ni paragraphe d'aide. */
.gb__consent { margin: 1rem 0 0; }

.gb__consent .g-consent__label { display: flex; gap: .6rem; align-items: flex-start; }
.gb__consent .g-consent__label a { font-weight: 400; white-space: nowrap; }

.gb__kinds { margin: 1rem 0 0; padding: 0; border: 0; min-width: 0; }
.gb__legend { padding: 0; margin: 0 0 .5rem; font-weight: 600; }

.gb__kinds-row {
    display: flex;
    flex-wrap: wrap;
    gap: .45rem;
}

.gb__kind {
    flex: 1 1 6.5rem;
    min-height: 44px;
    padding: .55rem .8rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: transparent;
    color: var(--ink);
    font: inherit;
    font-weight: 550;
    cursor: pointer;
}

.gb__kind[aria-pressed="true"] {
    border-color: var(--ember);
    background: color-mix(in srgb, var(--ember) 14%, transparent);
    color: var(--ink);
}

.gb__kind:focus-visible { outline: 2px solid var(--ember); outline-offset: 2px; }

.gb__form { margin: 1rem 0 0; display: flex; flex-direction: column; gap: .8rem; }
.gb__form > * { margin-block: 0; }
.gb__form textarea { width: 100%; min-height: 8rem; resize: vertical; }
.gb__count { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }

.gb__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
}

.gb__actions button,
.gb__photo-actions .button,
.gb__fallback .button,
.gb__send { min-height: 44px; }

.gb__timer {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-size: var(--t-md);
    color: var(--ink-2);
}

.gb__player { width: 100%; }

/* L'aperçu face caméra : comme un miroir pendant qu'on se filme, à l'endroit quand on se revoit. */
.gb__stage { position: relative; margin: 0; }

.gb__video {
    display: block;
    width: 100%;
    max-height: 60vh;
    border-radius: var(--r-lg);
    background: #000;
    object-fit: contain;
}

.gb__video.is-mirror { transform: scaleX(-1); }

.gb__timer--over {
    position: absolute;
    right: .6rem;
    top: .6rem;
    margin: 0;
    padding: .1rem .5rem;
    border-radius: 999px;
    background: rgba(20, 16, 26, .72);
    color: #fff;
    font-size: var(--t-sm);
}

.gb__timer--over:empty { display: none; }

.gb__fallback .muted { margin: 0 0 .4rem; }

.gb__photo {
    padding-top: .8rem;
    border-top: 1px solid var(--line);
}

.gb__photo-title { margin: 0 0 .15rem; font-weight: 600; }
.gb__photo .field-help { margin: 0; }

.gb__photo-actions {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin: .6rem 0 0;
}

.gb__thumb {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .7rem;
    margin: .7rem 0 0;
}

.gb__thumb-img {
    width: 5rem;
    height: 5rem;
    object-fit: cover;
    border-radius: var(--r-sm);
    border: 1px solid var(--line);
}

.gb__status { margin: .8rem 0 0; min-height: 1.2em; }
.gb__status:focus { outline: none; }
.gb__status--error { color: var(--danger); }
.gb__status--ok { color: var(--jade); }

.gb__status--live::before {
    content: "";
    display: inline-block;
    width: .55rem;
    height: .55rem;
    margin-right: .45rem;
    border-radius: 50%;
    background: var(--danger);
    animation: g-pulse 1.4s ease-in-out infinite;
}

/* La surprise (D-158) : qui la prépare, pour qui, et le secret à garder. */
.gb-surprise { margin: 0; text-align: center; border-color: color-mix(in srgb, var(--ember) 40%, var(--line)); }
.gb-surprise__title { margin: 0 0 .35rem; font-size: var(--t-lg); overflow-wrap: anywhere; }
.gb-surprise p { overflow-wrap: anywhere; }

.gb-closed { margin: 0; text-align: center; }

/* Vos messages : les siens seulement, une liste, pas un mur. */
.gb-mine__title { margin: 0 0 .6rem; font-size: var(--t-lg); }

.gb-mine__list {
    display: flex;
    flex-direction: column;
    gap: .9rem;
    margin: 0 0 .6rem;
    padding: 0;
    list-style: none;
}

.gb-mine__item {
    padding-bottom: .8rem;
    border-bottom: 1px solid var(--line);
    overflow-wrap: anywhere;
}

.gb-mine__item:last-child { border-bottom: 0; padding-bottom: 0; }
.gb-mine__head { margin: 0 0 .35rem; }
.gb-mine__state { margin: 0 0 .35rem; font-size: var(--t-sm); color: var(--ink-2); }
.gb-mine__state--failed { color: var(--danger); }

.gb-mine__body {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: .7rem;
}

.gb-mine__photo {
    width: 4.5rem;
    height: 4.5rem;
    object-fit: cover;
    border-radius: var(--r-sm);
    border: 1px solid var(--line);
}

.gb-mine__text { flex: 1 1 12rem; margin: 0; white-space: pre-line; }
.gb-mine__player { width: 100%; }
.gb-mine__video { width: 100%; max-height: 50vh; border-radius: var(--r-sm); background: #000; }
.gb-mine__withdraw { margin-top: .5rem; min-height: 44px; }

@media (prefers-reduced-motion: reduce) {
    .gb__status--live::before { animation: none; }
}

/* ---------- 12. Mouvement ---------- */
.g-report:not([hidden]) { animation: g-rise .45s cubic-bezier(.2, .8, .2, 1) both; }

@keyframes g-rise {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .g-report:not([hidden]) { animation: none; }
    .g-details__summary::before { transition: none; }
}
