/*
 * Styles propres à PumaQR, par-dessus le thème Zephyr (#40).
 *
 * Deux règles tenues ici :
 *
 * 1. Aucune couleur en dur. Tout passe par les variables de Bootstrap 5.3
 *    (--bs-border-color, --bs-tertiary-bg, --bs-secondary-color…), qui changent de valeur
 *    selon data-bs-theme. C'est ce qui rend le mode sombre gratuit ; un #eee écrit en clair
 *    resterait clair sur fond noir.
 *
 * 2. Les noms de classes existants sont conservés à l'identique. Ils datent d'avant
 *    l'habillage, les tests s'y accrochent (219 appels au crawler), et les renommer
 *    reviendrait à masquer une régression derrière une correction de test.
 */

/* ---------------------------------------------------------------- Police */

/*
 * Inter, auto-hébergée : le CSS de Zephyr importait fonts.googleapis.com, cet appel a été
 * retiré. « font-display: swap » affiche le texte dans la police de repli en attendant.
 */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/inter-latin-400-normal-poxsSdI.woff2") format('woff2');
}

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("../fonts/inter-latin-500-normal-Uwgfwtt.woff2") format('woff2');
}

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("../fonts/inter-latin-700-normal-_eucScQ.woff2") format('woff2');
}

/* ---------------------------------------------------------------- Coquille */

body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

main {
    flex: 1 0 auto;
}

/*
 * Les entrées de navigation ne se coupent pas en deux : « Mes QR codes » sur trois lignes
 * hache la barre. Quand la largeur manque, Bootstrap replie la barre derrière son bouton.
 */
.navbar .nav-link {
    white-space: nowrap;
}

/*
 * Langue et thème sont deux réglages, pas deux destinations : leur bouton se réduit à un
 * drapeau et à une icône (#72). Sans libellé, la zone cliquable tomberait à la taille du
 * dessin — d'où une largeur minimale, celle du seuil tactile de 44 px déjà retenu plus bas
 * pour les boutons sur petit écran.
 */
.navbar .nav-reglage {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.75rem;
}

/*
 * 1.25 rem plutôt que le 1 em par défaut d'ux_icons : à la taille du texte, un drapeau se
 * lit mal, et l'icône de thème pèse moins que le nom qu'elle remplace.
 */
.nav-icone {
    width: 1.25rem;
    height: 1.25rem;
}

/*
 * Le rapport est déclaré plutôt que déduit : « width: auto » sur un SVG retombe sur son
 * attribut width, que ux_icons fixe à 1 em, et le drapeau sortait carré. Il suit le format
 * du jeu importé — les icônes flag:*-4x3.
 *
 * Le drapeau est une image, pas un glyphe : il ne prend pas la couleur du texte, et son
 * rectangle a besoin d'un contour pour ne pas se dissoudre dans la barre — le blanc du
 * drapeau français touche sinon le fond clair, et celui de l'allemand le fond sombre.
 */
.nav-drapeau {
    width: auto;
    height: 1.25rem;
    aspect-ratio: 4 / 3;
    border: 1px solid var(--bs-border-color);
    border-radius: 2px;
}

/* ---------------------------------------------------------------- Doigt et clavier */

/*
 * Au doigt, un bouton de 31 px de haut se rate. La contrainte ne vaut que sous 768 px :
 * sur un écran de bureau, la densité actuelle est correcte, et 44 px partout alourdiraient
 * les tableaux de membres et d'organisations où ces boutons finissent la ligne (#43).
 */
@media (max-width: 767.98px) {
    .btn,
    .page-link,
    /* Ces deux-là viennent de perdre leur libellé (#72) : sans lui, plus rien ne tenait la
       cible au doigt en largeur comme en hauteur. */
    .navbar .nav-reglage {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
}

/*
 * Cases et boutons radio : 16 px de côté par défaut, sous le seuil de 24 px de la
 * WCAG 2.5.8. Le libellé reste cliquable, mais viser la case elle-même ne doit pas
 * relever de l'adresse.
 */
.form-check-input {
    width: 1.5rem;
    height: 1.5rem;
    margin-top: 0.05rem;
}

.form-check {
    padding-left: 2rem;
}

.form-check .form-check-input {
    margin-left: -2rem;
}

/* ---------------------------------------------------------------- Éléments communs */

/* Mentions secondaires : dates, décomptes, explications sous un champ. */
.qr-meta {
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
}

/* État vide d'une liste : ce n'est pas une erreur, seulement rien à montrer. */
.qr-vide {
    padding: 2rem;
    text-align: center;
    background: var(--bs-tertiary-bg);
    border-radius: var(--bs-border-radius);
}

.qr-badge {
    display: inline-block;
    padding: 0.1rem 0.4rem;
    border-radius: var(--bs-border-radius-sm);
    background: var(--bs-secondary-bg);
    font-size: 0.75rem;
}

.qr-badge.partage {
    background: var(--bs-success-bg-subtle);
    color: var(--bs-success-text-emphasis);
}

.qr-badge.etiquette {
    background: var(--bs-info-bg-subtle);
    color: var(--bs-info-text-emphasis);
}

.qr-badge.admin {
    background: var(--bs-primary);
    color: #fff;
}

.qr-badge.inactif {
    background: var(--bs-danger-bg-subtle);
    color: var(--bs-danger-text-emphasis);
}

/*
 * Tout rendu de QR garde un fond blanc, y compris en thème sombre : ces dessins sont foncés
 * sur transparent, et un QR clair sur fond sombre ne se scanne pas — le bulletin normé, lui,
 * deviendrait carrément illisible.
 */
.qr-liste svg,
.qr-apercu svg,
.qr-presets svg,
.qr-design .apercu svg,
.labo-grille svg,
.qr-bulletin svg {
    background: #fff;
}

/*
 * Zephyr écrit en dur `.btn-outline-secondary { color: #212529 }` — son bouton secondaire
 * est pensé pour une page claire. En thème sombre, cette encre est exactement la couleur du
 * fond : le bouton s'affiche vide, texte compris. On lui rend l'encre du corps de page ;
 * au survol, le fond redevient clair et l'encre sombre reprend ses droits.
 */
[data-bs-theme='dark'] .btn-outline-secondary {
    color: var(--bs-body-color);
    border-color: var(--bs-border-color);
}

[data-bs-theme='dark'] .btn-outline-secondary:hover,
[data-bs-theme='dark'] .btn-outline-secondary:active {
    color: #212529;
}

/* Message d'erreur des pages publiques, qui n'ont pas de messages flash. */
p.error {
    color: var(--bs-danger-text-emphasis);
}

/*
 * .qr-formulaire et .qr-reglages ne portent plus de largeur (#59).
 *
 * Elles la déclaraient — 40 rem — sans marge automatique, d'où des formulaires bornés mais
 * collés au bord gauche d'un écran large. La largeur d'une page se déclare désormais dans
 * son gabarit, « {% set largeur_max = '40rem' %} », et c'est le layout global/card_content
 * qui la pose et centre la carte. Une seule décision, au même endroit que le titre et le
 * contenu, plutôt qu'une règle de feuille de style qui s'appliquait aussi là où le bloc
 * n'était pas seul sur la page.
 *
 * Les deux classes restent : elles marquent les blocs de formulaire pour les tests de
 * crawler et pour le contrôleur Stimulus du sélecteur géographique.
 */

/*
 * Carte de choix du point géographique. Leaflet dimensionne ses tuiles d'après la hauteur de
 * son conteneur : sans hauteur explicite, il n'affiche rien du tout.
 */
.geo-picker-carte {
    height: 22rem;
    border-radius: var(--bs-border-radius);
}

/*
 * Pages publiques — connexion, mot de passe oublié. Sans navigation ni contenu autour, une
 * colonne étroite et centrée vaut mieux qu'un formulaire perdu en haut à gauche d'un écran
 * large.
 */
.qr-public {
    max-width: 26rem;
    margin: 2rem auto;
}

/*
 * Écran de connexion : photo à gauche, formulaire à droite (#76).
 *
 * Plus large que .qr-public, qui borne les autres pages publiques à une colonne : ici il y
 * en a deux, et 26 rem n'y suffiraient pas.
 */
.qr-connexion {
    max-width: 56rem;
    margin: 2rem auto;
}

/*
 * La colonne d'illustration porte un dégradé, qui reste seul quand la photo manque — pas de
 * clé d'API, pas de réseau, réponse inattendue. Un fond plein plutôt qu'un trou : la carte
 * garde ses deux colonnes, et rien ne signale l'absence.
 */
.qr-connexion-illustration {
    position: relative;
    min-height: 30rem;
    background: linear-gradient(160deg, var(--bs-primary) 0%, var(--bs-body-bg) 140%);
}

/*
 * La photo remplit sa colonne quel que soit son format : c'est un ornement, il vaut mieux la
 * rogner que la déformer ou laisser des bandes.
 */
.qr-connexion-photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/*
 * Le crédit est une obligation des guidelines Unsplash, pas une mention discrète qu'on peut
 * laisser illisible : voile sombre sous le texte, pour qu'il tienne sur n'importe quelle
 * photo.
 */
.qr-connexion-credit {
    position: absolute;
    inset: auto 0 0 0;
    padding: 0.5rem 0.75rem;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    font-size: 0.75rem;
    line-height: 1.4;
}

.qr-connexion-credit a {
    color: #fff;
    text-decoration: underline;
}

/* ---------------------------------------------------------------- Tableau de bord */

.qr-liste {
    margin: 0;
    padding: 0;
    list-style: none;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}

.qr-liste li {
    display: grid;
    grid-template-columns: 4rem minmax(0, 1fr) auto;
    gap: 1rem;
    align-items: center;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--bs-border-color);
}

.qr-liste li:last-child {
    border-bottom: 0;
}

.qr-liste li:hover {
    background: var(--bs-tertiary-bg);
}

.qr-liste svg {
    display: block;
    width: 4rem;
    height: auto;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-sm);
}

/*
 * Un nom de QR ne coupe pas la mise en page : sans cette limite, une chaîne sans espace
 * pousserait la colonne des actions hors de l'écran.
 */
.qr-liste li > div {
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Dans une liste, le soulignement de chaque titre fait du bruit ; il revient au survol. */
.qr-liste a {
    text-decoration: none;
}

.qr-liste a:hover,
.qr-liste a:focus-visible {
    text-decoration: underline;
}

/* La barre de recherche est une carte Bootstrap : sa mise en page vient de la grille. */
.qr-recherche .form-label {
    margin-bottom: 0.25rem;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

/* ---------------------------------------------------------------- Types et détail */

.qr-types {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
    gap: 1rem;
    padding: 0;
    list-style: none;
}

.qr-types a {
    display: block;
    height: 100%;
    padding: 1rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    text-decoration: none;
    color: inherit;
    transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}

.qr-types a:hover,
.qr-types a:focus-visible {
    border-color: var(--bs-primary);
    box-shadow: var(--bs-box-shadow-sm);
}

.qr-types strong {
    display: block;
    margin-bottom: 0.25rem;
}

.qr-apercu svg {
    display: block;
    width: 100%;
    max-width: 20rem;
    height: auto;
    margin: 0 auto;
}

/*
 * Le bulletin de sprain porte ses propres dimensions : rien ne doit les contraindre.
 *
 * `overflow-x: auto` seul ne suffisait pas. Le bulletin est un <table> dont sprain fixe les
 * cellules à 62 mm (récépissé) et 148 mm (section paiement) — la largeur normée de 210 mm.
 * Sans largeur sur la table elle-même, ces valeurs ne sont qu'une préférence : dans une
 * colonne étroite, le navigateur retombe sur la largeur minimale du contenu, les cellules
 * se compriment et le texte se casse. La barre de défilement n'apparaissait donc jamais,
 * puisque rien ne dépassait — le bulletin s'était écrasé pour tenir.
 *
 * On lui rend ses dimensions exactes, et c'est le cadre qui défile. Les 210 mm ne sont pas
 * un réglage : c'est la largeur normée du bulletin, celle que sprain répartit entre ses
 * cellules et applique à sa sortie PDF (bouton « section paiement, 210 × 105 mm »).
 *
 * La hauteur est bornée à 115 mm : les 105 mm de la norme, plus les 5 mm de la ligne « à
 * détacher » et le trait qui la souligne. Un bulletin ordinaire tient dedans sans jamais
 * montrer d'ascenseur vertical (mesuré : 398 px de contenu pour 434 px de cadre) ; celui
 * dont les informations supplémentaires débordent défile au lieu de pousser la carte.
 */
.qr-bulletin {
    overflow: auto;
    max-height: 115mm;
}

.qr-bulletin table {
    width: 210mm;
}

.qr-payload {
    padding: 0.5rem;
    background: var(--bs-tertiary-bg);
    border-radius: var(--bs-border-radius-sm);
    overflow-wrap: anywhere;
    white-space: pre-wrap;
}

/*
 * Bootstrap dimensionne les <legend> comme des titres de section. Dans un formulaire, une
 * légende ne pèse pas plus qu'un libellé de champ : « Étiquettes » n'est pas un chapitre.
 */
legend.form-label {
    float: none;
    width: auto;
    margin-bottom: 0.5rem;
    font-size: inherit;
    line-height: inherit;
}

.qr-etiquettes {
    margin: 0.25rem 0 0;
    padding: 0;
    list-style: none;
    columns: 3;
}

/* Une case à cocher ne se coupe pas entre deux colonnes. */
.qr-etiquettes li {
    break-inside: avoid;
}

.qr-etiquettes label {
    font-weight: normal;
}

/* ---------------------------------------------------------------- Apparence */

/*
 * Une seule colonne par défaut, deux à partir de 62em. Les deux colonnes réclamaient au
 * minimum 18 + 14 rem plus la gouttière, soit 556 px : la page d'apparence était le seul
 * écran de l'application à déborder d'un téléphone (relevé de #43).
 */
.qr-design {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 2rem;
    align-items: start;
}

/* En une colonne, l'aperçu passe devant : on règle en voyant ce qu'on règle. */
.qr-design .apercu {
    order: -1;
}

@media (min-width: 62em) {
    .qr-design {
        grid-template-columns: minmax(18rem, 1fr) minmax(14rem, 20rem);
    }

    /* Deux colonnes : l'aperçu retrouve sa place à droite, et suit le défilement. */
    .qr-design .apercu {
        order: 0;
        position: sticky;
        top: 1rem;
    }
}

.qr-design .apercu svg {
    display: block;
    width: 100%;
    height: auto;
}

/*
 * Avertissement de lisibilité : un encadré qui dit « lis-moi avant de continuer », sans être
 * une erreur.
 */
.qr-avertissements {
    padding: 0.75rem;
    background: var(--bs-warning-bg-subtle);
    border-left: 3px solid var(--bs-warning-border-subtle);
}

/*
 * Un sélecteur de couleur rendu en `form-control` est une pastille écrasée : Bootstrap le
 * dimensionne par `.form-control-color`, que le thème de formulaire de Symfony n'applique
 * pas. La règle vaut ici plutôt qu'en attribut de formulaire — #41 ne touche pas au PHP.
 */
input[type='color'].form-control {
    width: 4rem;
    height: calc(1.5em + 0.75rem + 2px);
    padding: 0.25rem;
}

/* Choix du logo, sur la page d'apparence : des vignettes, pas une grille de bibliothèque. */
.qr-design .qr-logos {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin: 0;
    padding: 0;
    border: 0;
}

/*
 * Enfant direct seulement : le thème Bootstrap laisse à l'intérieur un `<label>` vide
 * (masqué juste en dessous), que cette règle habillerait sinon comme une seconde vignette.
 */
.qr-design .qr-logos > label {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    width: 6rem;
    padding: 0.5rem;
    border: 1px solid var(--bs-border-color);
    text-align: center;
    word-break: break-word;
}

/*
 * Le thème Bootstrap enveloppe chaque bouton radio dans un `.form-check` qui réserve la
 * place d'un libellé à gauche. Ici le libellé est la vignette elle-même : sans cette remise
 * à zéro, le bouton flotte hors de sa case et laisse un rectangle vide au-dessus.
 */
.qr-design .qr-logos .form-check {
    min-height: 0;
    margin: 0;
    padding: 0;
}

.qr-design .qr-logos .form-check-input {
    float: none;
    margin: 0;
}

/* Le libellé du thème est vide — la vignette et son nom le remplacent — et il n'a rien à
   occuper comme place. */
.qr-design .qr-logos .form-check-label {
    display: none;
}

.qr-design .qr-logos img {
    width: 4rem;
    height: 4rem;
    object-fit: contain;
}

.qr-design .qr-logos .aucun {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 4rem;
    height: 4rem;
    color: var(--bs-secondary-color);
}

/* ---------------------------------------------------------------- Bibliothèque de logos */

.qr-logos {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
    gap: 1rem;
    padding: 0;
    list-style: none;
}

.qr-logos li {
    padding: 0.75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}

/* Fond damier : un logo blanc sur fond blanc resterait invisible. */
.qr-logos img {
    display: block;
    width: 100%;
    height: 8rem;
    object-fit: contain;
    background: repeating-conic-gradient(#f3f3f3 0% 25%, #ffffff 0% 50%) 50% / 1rem 1rem;
}

.qr-logos figcaption {
    margin-top: 0.5rem;
    overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------- Presets */

.qr-presets {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
    gap: 1rem;
    padding: 0;
    list-style: none;
}

.qr-presets li {
    padding: 0.75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}

.qr-presets svg {
    display: block;
    width: 100%;
    height: auto;
}

.qr-presets h3 {
    margin: 0.5rem 0 0;
    overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------- Dossiers, étiquettes, corbeille */

.qr-classement,
.qr-corbeille {
    margin: 0;
    padding: 0;
    list-style: none;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}

.qr-classement li,
.qr-corbeille li {
    display: grid;
    gap: 1rem;
    align-items: center;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--bs-border-color);
}

.qr-classement li:last-child,
.qr-corbeille li:last-child {
    border-bottom: 0;
}

.qr-classement li {
    grid-template-columns: 1fr auto;
}

.qr-corbeille li {
    grid-template-columns: 1fr auto auto;
}

/*
 * Le champ de renommage occupe la place disponible sans la dévorer : la ligne porte aussi
 * son bouton, et une largeur fixe le repousserait hors du cadre sur un écran étroit.
 */
.qr-classement input[type='text'] {
    flex: 1 1 12rem;
    max-width: 24rem;
}

/* ---------------------------------------------------------------- Membres et organisations */

.qr-membres,
.qr-organisations {
    width: 100%;
    border-collapse: collapse;
}

.qr-membres th,
.qr-membres td,
.qr-organisations th,
.qr-organisations td {
    padding: 0.5rem;
    border-bottom: 1px solid var(--bs-border-color);
    text-align: left;
    vertical-align: top;
}

/* ---------------------------------------------------------------- Laboratoire de rendu */

.labo-grille {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
    gap: 1.5rem;
    margin: 0 0 2.5rem;
    padding: 0;
    list-style: none;
}

.labo-grille figure {
    margin: 0;
}

.labo-grille svg {
    display: block;
    width: 100%;
    height: auto;
    border: 1px solid var(--bs-border-color);
}

.labo-grille figcaption {
    margin-top: 0.5rem;
    font-size: 0.875rem;
    line-height: 1.4;
}

.labo-correction {
    color: var(--bs-secondary-color);
}

/* ---------------------------------------------------------------- Vitrine */

/*
 * Pages publiques (#97, #98). Elles sont les seules du projet à être vues avant toute
 * connexion, souvent depuis un téléphone : les tailles se déclarent en unités relatives et
 * les grilles se replient d'elles-mêmes plutôt que par points de rupture.
 */

.qr-vitrine-accroche {
    padding: 3rem 0 2rem;
}

/*
 * Le texte d'introduction d'une section ne dépasse pas la longueur de ligne confortable,
 * même sur un grand écran : au-delà, l'œil perd le début de la ligne suivante.
 */
.qr-vitrine-chapeau {
    max-width: 46rem;
    color: var(--bs-secondary-color);
}

/*
 * Le chapeau ne se centre que dans une section centrée. Centré sous un titre aligné à
 * gauche, il donnerait un texte décalé sans raison apparente.
 */
.text-center .qr-vitrine-chapeau,
.text-center .qr-vitrine-atouts {
    margin-inline: auto;
}

.qr-vitrine-section {
    padding: 2.5rem 0;
    border-top: 1px solid var(--bs-border-color);
}

.qr-vitrine-section h2 {
    margin-bottom: 0.75rem;
}

/*
 * Duo texte / illustration.
 *
 * Une colonne par défaut — sur un téléphone, deux colonnes ne tiennent pas. À partir de
 * `lg`, le même point de rupture que la navigation Bootstrap, la capture passe à côté de son
 * texte : empilée, elle repoussait l'explication suivante d'un écran entier.
 *
 * La modale d'agrandissement est bien un enfant de la grille, et pourtant elle n'y occupe
 * aucune colonne : masquée elle est en `display: none`, ouverte elle passe en
 * `position: fixed` — dans les deux cas, hors du flux de la grille.
 */
.qr-vitrine-duo {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.5rem 2.5rem;
    align-items: center;
}

@media (min-width: 992px) {
    .qr-vitrine-duo {
        grid-template-columns: 1fr 1fr;
    }

    /*
     * Une section sur deux place sa capture à gauche. C'est un échange d'ordre visuel et
     * non de document : le texte reste écrit avant son illustration, donc l'empilement
     * mobile et la lecture au lecteur d'écran ne changent pas.
     */
    .qr-vitrine-duo-inverse > .qr-vitrine-duo-texte {
        order: 2;
    }

    .qr-vitrine-duo-inverse > .qr-vitrine-capture {
        order: 1;
    }
}

/* Dans un duo, la capture remplit sa colonne : la brider à 32 rem y laisserait un trou. */
.qr-vitrine-duo .qr-vitrine-capture {
    max-width: none;
    margin-top: 0;
}

/*
 * Encarts colorés.
 *
 * La couleur désigne, elle ne décore pas : le début et la fin de la page, qui l'encadrent ;
 * le dynamique, qui justifie l'écart de prix ; la confidentialité, qui est l'argument nLPD.
 * Les autres sections restent sur le fond du corps — si tout est mis en avant, plus rien ne
 * l'est.
 *
 * Les teintes viennent des variables `-bg-subtle` et `-border-subtle` de Bootstrap 5.3, qui
 * sont définies dans les deux thèmes de Zephyr : le mode sombre suit sans une ligne de plus,
 * et aucune couleur n'est écrite ici.
 */
.qr-vitrine-encart {
    margin: 2rem 0;
    padding: 2rem;
    border: 1px solid transparent;
    border-radius: var(--bs-border-radius-xl);
}

.qr-vitrine-encart h2 {
    margin-bottom: 0.75rem;
}

.qr-vitrine-encart-neutre {
    background-color: var(--bs-secondary-bg);
    border-color: var(--bs-border-color);
}

.qr-vitrine-encart-primaire {
    background-color: var(--bs-primary-bg-subtle);
    border-color: var(--bs-primary-border-subtle);
}

.qr-vitrine-encart-confiance {
    background-color: var(--bs-success-bg-subtle);
    border-color: var(--bs-success-border-subtle);
}

/*
 * Dans un encart teinté, les blocs qui se détachaient du corps de page en `--bs-tertiary-bg`
 * deviendraient du gris posé sur de la couleur. Ils prennent le fond du corps, qui redevient
 * la teinte claire du lot.
 */
.qr-vitrine-encart .qr-vitrine-etapes li,
.qr-vitrine-encart .qr-vitrine-capture-declencheur {
    background-color: var(--bs-body-bg);
}

/*
 * Même raison pour le bouton secondaire, qui est transparent : posé sur l'encart gris, il
 * disparaissait dedans à côté du bouton vert. On lui donne le fond du corps de page — blanc
 * en thème clair, sombre en thème sombre, dans les deux cas détaché de l'encart.
 *
 * L'exclusion des états interactifs n'est pas une coquetterie : cette règle vient après
 * Bootstrap dans la feuille et l'emporterait, à égalité de spécificité, sur le remplissage
 * que `.btn-outline-secondary:hover` applique au survol.
 */
.qr-vitrine-encart .btn-outline-secondary:not(:hover, :focus-visible, :active) {
    background-color: var(--bs-body-bg);
}

/* Les dix types : autant de colonnes que la largeur en autorise, sans media query. */
.qr-vitrine-types {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: 1rem;
    margin-top: 1.5rem;
}

/*
 * Le liseré coloré sur la tranche remplace le cadre uniforme : dix cartes grises se lisaient
 * comme un tableau, la couleur leur rend une entrée. Elle n'est posée que d'un côté —
 * cerner chaque carte de bleu en ferait dix boutons.
 */
.qr-vitrine-types li {
    padding: 0.875rem 1rem;
    border: 1px solid var(--bs-border-color);
    border-inline-start: 3px solid var(--bs-primary);
    border-radius: var(--bs-border-radius);
    background-color: var(--bs-body-bg);
}

.qr-vitrine-etapes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: 1rem;
    margin: 1.5rem 0;
    padding: 0;
    list-style-position: inside;
}

.qr-vitrine-etapes li {
    padding: 1rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    background-color: var(--bs-tertiary-bg);
}

.qr-vitrine-etapes li span {
    margin-top: 0.35rem;
    color: var(--bs-secondary-color);
}

/*
 * Numéros et puces à la couleur primaire : c'est la touche de couleur la moins coûteuse du
 * lot — elle ne change ni la forme ni l'espacement, et rend les listes lisibles d'un coup
 * d'œil. `::marker` n'accepte qu'une poignée de propriétés, dont la couleur : c'est
 * exactement ce dont on a besoin ici.
 */
.qr-vitrine-etapes li::marker,
.qr-vitrine-atouts li::marker {
    color: var(--bs-primary);
    font-weight: 700;
}

.qr-vitrine-atouts {
    max-width: 46rem;
    padding-left: 1.25rem;
}

.qr-vitrine-atouts li {
    margin-bottom: 0.4rem;
}

/*
 * Captures d'écran de la vitrine.
 *
 * Servies pleine largeur, elles mangeaient la section entière : il fallait défiler pour
 * revenir à l'explication qu'elles étaient censées illustrer. La vignette se borne donc à
 * une largeur de lecture, et le détail s'obtient au clic — la modale Bootstrap est déjà
 * chargée, aucune visionneuse tierce n'est ajoutée.
 */
.qr-vitrine-capture {
    max-width: 32rem;
    margin: 1.5rem 0 0;
}

/*
 * Sur un fond de la couleur du corps de page, l'image se confondait avec le texte qui la
 * précède. Le passe-partout — retrait, fond tertiaire, ombre portée sous l'image — la pose
 * comme un objet distinct, sans introduire la moindre couleur en dur.
 */
.qr-vitrine-capture-declencheur {
    display: block;
    position: relative;
    width: 100%;
    padding: 0.5rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-lg);
    background-color: var(--bs-tertiary-bg);
    cursor: zoom-in;
    transition: border-color 0.15s ease-in-out;
}

.qr-vitrine-capture-declencheur:hover,
.qr-vitrine-capture-declencheur:focus-visible {
    border-color: var(--bs-primary);
}

.qr-vitrine-capture-declencheur img {
    display: block;
    width: 100%;
    height: auto;
    border-radius: var(--bs-border-radius);
    box-shadow: var(--bs-box-shadow-sm);
}

/*
 * L'étiquette reste visible en permanence plutôt que d'apparaître au survol : sur un écran
 * tactile, où il n'y a pas de survol, rien n'indiquerait sinon que l'image s'ouvre.
 *
 * Elle ne suit pas le thème, contrairement à tout le reste du fichier, et c'est voulu : elle
 * est posée sur la capture, qui est toujours un écran clair. En `--bs-emphasis-color` sur
 * `--bs-body-bg`, elle devenait une pastille blanche sur une capture blanche en thème
 * sombre — invisible. `--bs-dark` et `--bs-light` viennent de la palette Bootstrap, que le
 * thème ne redéfinit pas (vérifié : absentes du bloc `[data-bs-theme=dark]` de Zephyr).
 */
.qr-vitrine-capture-loupe {
    position: absolute;
    right: 1rem;
    bottom: 1rem;
    padding: 0.15rem 0.6rem;
    border-radius: var(--bs-border-radius-pill);
    background-color: var(--bs-dark);
    color: var(--bs-light);
    font-size: 0.8125rem;
}

/* Dans la modale, la capture reprend sa taille : c'est tout l'objet du clic. */
.qr-vitrine-capture-agrandie img {
    display: block;
    width: 100%;
    height: auto;
}

.qr-vitrine-offres {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
    gap: 1.5rem;
    margin: 2rem 0;
}

.qr-vitrine-offre .qr-vitrine-atouts {
    margin-top: 1rem;
}

.qr-vitrine-prix {
    margin-bottom: 0.25rem;
    color: var(--bs-primary);
    font-size: 1.75rem;
    font-weight: 500;
}

/* L'offre du haut se distingue par sa bordure, jamais par une couleur inventée. */
.qr-vitrine-offre-mise-en-avant {
    border-color: var(--bs-primary);
    border-width: 2px;
}

.qr-inscription {
    max-width: 34rem;
    margin-inline: auto;
    padding-bottom: 3rem;
}

/*
 * Champ piège du formulaire d'inscription (#99) : invisible à l'écran, absent du parcours
 * clavier, et pourtant présent dans le document — un robot qui remplit tout ce qu'il trouve
 * s'y prend, un humain ne le voit jamais.
 *
 * `display: none` ferait fuir les robots qui le testent ; on le sort de la vue sans le
 * retirer du flux logique.
 */
.qr-piege {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/* ---------------------------------------------------------------- Impression */

/*
 * Ce qu'on imprime d'une page de détail, c'est le QR et son nom — pas la navigation, pas
 * les boutons de téléchargement, pas le pied de page. Le thème sombre ne s'imprime jamais :
 * il viderait une cartouche pour un fond que le papier ne rend pas.
 */
@media print {
    :root {
        color-scheme: light;
    }

    body {
        background: #fff;
        color: #000;
    }

    .navbar,
    footer,
    .btn,
    .qr-recherche,
    .qr-pagination,
    form {
        display: none !important;
    }

    /* Les cartes deviennent de simples blocs : ni ombre, ni cadre, ni fond gris. */
    .card,
    .card-body,
    .card-footer,
    .card-header {
        background: transparent !important;
        border: 0 !important;
        box-shadow: none !important;
        padding-left: 0;
        padding-right: 0;
    }

    .qr-apercu svg,
    .qr-bulletin svg {
        max-width: 100mm;
    }

    /* Le cadre qui défile à l'écran n'a pas de sens sur papier : une barre de défilement ne
       s'y actionne pas, et ce qu'elle cachait serait perdu. */
    .qr-bulletin {
        overflow: visible;
        max-height: none;
    }

    /* Une adresse imprimée doit rester joignable : le lien perd son URL sinon. */
    main a[href^='http']::after {
        content: ' (' attr(href) ')';
        font-size: 0.75em;
        word-break: break-all;
    }
}
