/* Event purchases and the personal beneficiary address book. */
.event-purchase {max-width: 960px; margin: 0 auto; color: #333; min-width: 0;}
.event-purchase * {box-sizing: border-box;}
.event-purchase .purchase-intro {margin: 0 0 24px;}
.event-purchase .purchase-links, .event-purchase .purchase-actions {display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 16px 0;}
.event-purchase .purchase-section {border: 1px solid #ddd; border-radius: 10px; padding: 24px; margin: 0 0 24px; background: #fff; min-width: 0;}
.event-purchase .purchase-section h3 {margin: 0 0 16px; color: #224574; font-size: 20px;}
/* Le fond vient de .bg-info, posé sur le fieldset : la saisie se distingue du carnet sans
   cadre ni aplat gris. Le rayon reste, c'est lui qui donne sa forme à l'aplat. */
.event-purchase .purchase-entry {border-radius: 8px; padding: 16px; margin-bottom: 16px; min-width: 0;}
.event-purchase .purchase-saved {max-height: 280px; overflow-y: auto; padding: 4px 12px; border: 1px solid #ddd; border-radius: 6px; margin-bottom: 16px;}
.event-purchase .purchase-total {background: #eef4fa; padding: 20px; border-radius: 8px; margin: 16px 0;}
.event-purchase .purchase-error {border-left: 4px solid #ad3024; background: #fff0ef; padding: 16px; margin-bottom: 20px;}
.event-purchase .btn {min-height: 44px; white-space: normal; padding: 10px 16px;}
.event-purchase a:focus-visible, .event-purchase button:focus-visible, .event-purchase input:focus-visible, .event-purchase select:focus-visible {outline: 3px solid #224574; outline-offset: 3px;}
.event-purchase .purchase-actions-center {justify-content: center;}
/* Carnet vide : la saisie est seule sur la page, sans cadre, à la largeur de la modale
   pour que les deux présentations du même formulaire se ressemblent. */
.event-purchase .beneficiary-inline-form {max-width: 600px; margin: 0 auto;}
/* Actions de ligne du carnet : mêmes gabarits que les tableaux CRM. La cible tactile
   confortable posée plus haut sur .btn vaut pour le tunnel d'achat, pas pour une
   colonne d'icônes, et l'emporterait sur .btn-sm sans ce rappel plus spécifique. */
.event-purchase .btn.btn-sm {min-height: 0; padding: 5px 10px;}
.event-purchase table td form {display: inline; margin: 0;}
@media (max-width: 767px) {
    .event-purchase .purchase-section {padding: 16px;}
    .event-purchase .purchase-actions > .btn {flex: 1 1 auto; text-align: center;}
}

#group-purchase, #purchase-total-title {scroll-margin-top: 160px;}
@media (max-width: 767px) {#group-purchase, #purchase-total-title {scroll-margin-top: 24px;}}

#eventGroupPurchaseModal .modal-dialog {width: calc(100% - 24px); max-width: 960px; margin: 24px auto;}
#eventGroupPurchaseModal .modal-content {max-height: calc(100dvh - 48px); display: flex; flex-direction: column;}
#eventGroupPurchaseModal .modal-body {overflow-y: auto; min-height: 0; padding: 20px;}
#eventGroupPurchaseModal .modal-header, #eventGroupPurchaseModal .modal-footer {flex-shrink: 0;}
#eventGroupPurchaseModal .modal-title {font-size: 24px;}
#eventGroupPurchaseModal .modal-header p {margin: 8px 0 0; opacity: .85;}
#eventGroupPurchaseModal #group-purchase, #eventGroupPurchaseModal #purchase-total-title {scroll-margin-top: 16px;}
@media (max-width: 767px) {
    #eventGroupPurchaseModal .modal-dialog {margin: 8px auto; width: calc(100% - 16px);}
    #eventGroupPurchaseModal .modal-content {max-height: calc(100dvh - 16px);}
    #eventGroupPurchaseModal .modal-body {padding: 10px;}
}

/* bootstrap_3_horizontal_layout pose form-horizontal sur chaque form_start, ce qui fait de
   .form-group une ligne Bootstrap à gouttières négatives. Les champs d'_inputGroup — ceux du
   carnet comme ceux de la commande — déborderaient sinon du corps de la modale. */
#eventGroupPurchaseModal .form-group {margin-left: 0; margin-right: 0;}

/* Prénom et nom sur une même ligne, partout où _beneficiaryFields est inclus. */
.beneficiary-name-row {display: grid; grid-template-columns: 1fr 1fr; gap: 16px;}
.beneficiary-name-row .form-group {margin-left: 0; margin-right: 0;}
@media (max-width: 767px) {.beneficiary-name-row {grid-template-columns: 1fr; gap: 0;}}

/* Casse de l'identité montrée pendant la frappe. text-transform n'est qu'un vernis : la valeur
   enregistrée est normalisée par App\Model\PersonName, côté entité. */
input[name$="[nom]"] {text-transform: uppercase;}
input[name$="[prenom]"] {text-transform: capitalize;}
input[name$="[email]"] {text-transform: lowercase;}

/* Dans la modale, le cadre des sections fait doublon avec celui de la modale elle-même. */
#eventGroupPurchaseModal .purchase-section {border: 0; border-radius: 0; padding: 0; background: transparent;}

/* Carnet en tableau : case, identité, email, tarif, pour que les colonnes s'alignent d'une ligne à
   l'autre. Ligne atténuée tant qu'elle n'est pas retenue — la classe porte l'état initial,
   :has suit la case à cocher sans JavaScript. */
.event-purchase .purchase-saved-table {width: 100%; margin: 0;}
/* Hauteur minimale commune à toutes les cellules : celle d'une ligne portant un select, pour
   qu'une ligne verrouillée — qui n'en a plus — ne soit pas plus basse que ses voisines. 46 =
   34 du select + 2 × 6 de remplissage, les cellules étant en border-box (Bootstrap). Sur une
   cellule de tableau, height vaut minimum : un email qui passe à la ligne fait grandir la ligne. */
.event-purchase .purchase-saved-table > tbody > tr > td {padding: 6px 8px; vertical-align: middle; border: 0; height: 46px;}
.event-purchase .purchase-contact-box {width: 1px; padding-left: 0;}
.event-purchase .purchase-contact-box input {margin: 0; display: block;}
.event-purchase .purchase-contact-name {white-space: nowrap;}
.event-purchase .purchase-contact-name label {margin: 0; font-weight: normal; cursor: pointer;}
.event-purchase .purchase-contact td, .event-purchase .purchase-contact label {color: #777;}
.event-purchase .purchase-contact.is-selected td, .event-purchase .purchase-contact.is-selected label {color: #000;}
.event-purchase .purchase-contact:has(input:checked) td, .event-purchase .purchase-contact:has(input:checked) label {color: #000;}
.event-purchase .purchase-contact b {font-weight: 700;}
.event-purchase .purchase-contact-email {font-size: 13px; overflow-wrap: anywhere; width: 100%;}
.event-purchase .purchase-tariff {margin: 8px 0;}
.event-purchase .purchase-tariff label {display: block; width: auto; text-align: left; font-size: 13px; font-weight: 700; margin-bottom: 4px;}
/* Le tarif retenu se lit d'un coup d'œil : contour marqué, angles arrondis comme le reste de la
   modale, et le vert de succès déjà employé par la pastille du code de réduction (#3c763d, celui
   de .text-success). Mêmes règles dans le tableau et dans la saisie dépliée : c'est le même
   champ, il n'a pas à changer d'allure selon l'endroit. */
.event-purchase .purchase-tariff select {width: 100%; min-width: 0; border-radius: .75rem; border: 2px solid #000; color: #3c763d;}
/* Une liste déroulante s'ouvre au clic : le curseur le dit, comme sur les lignes du carnet. La
   règle vaut pour toute la modale, il n'y a pas de select à y traiter autrement. */
.event-purchase select {cursor: pointer;}
/* Colonne du tarif : largeur fixée ici, celle de l'email absorbant tout le reste (width: 100%).
   min-width autant que width, pour que la colonne garde sa place même quand aucune ligne n'affiche
   de select — toutes déjà prises, par exemple — au lieu de se réduire au pictogramme. */
.event-purchase .purchase-contact-tariff {width: 280px; min-width: 280px; text-align: center;}
/* Centrage posé sur l'enveloppe et pas seulement hérité de la cellule : le select est en
   largeur de contenu, il flotterait à gauche dès qu'une règle d'alignement passerait entre les
   deux. */
.event-purchase .purchase-contact-tariff .purchase-tariff {margin: 0; text-align: center;}
/* Le select d'une ligne échappe au gabarit .form-large-fields que porte le formulaire, qui lui
   imposerait 5rem de haut (main.css) : c'est la taille d'un champ principal, pas d'une commande
   répétée à chaque ligne. Largeur au contenu, bornée par la cellule — les lignes partagent la
   même liste de tarifs, elles gardent donc la même largeur. */
/* display: block pour que les marges automatiques de .mx-auto opèrent : sur un élément en ligne
   elles ne font rien. Un select en bloc garde sa largeur de contenu, il ne s'étire pas. */
.event-purchase .purchase-contact-tariff select {height: 34px; font-size: 13px; padding: 4px 8px; width: auto; max-width: 100%; display: block;}
@media (max-width: 600px) {
    .event-purchase .purchase-saved-table .purchase-contact {display: grid; grid-template-columns: 24px minmax(0, 1fr);}
    .event-purchase .purchase-contact .purchase-contact-box {width: auto; grid-column: 1;}
    .event-purchase .purchase-contact .purchase-contact-name {grid-column: 2; white-space: normal;}
    .event-purchase .purchase-contact .purchase-contact-email {grid-column: 1 / -1;}
    /* Plus de colonne à droite sur mobile : le tarif passe sous l'email, pleine largeur. */
    .event-purchase .purchase-contact .purchase-contact-tariff {width: auto; grid-column: 1 / -1;}
}
.event-purchase .purchase-entry-actions {gap: 12px; margin-top: 8px; flex-wrap: wrap;}
/* Conteneur ajusté à son contenu : sa largeur est celle de son plus large enfant, la rangée de
   boutons, et le select la remplit (width: 100%). Si un libellé de tarif venait à dépasser les
   boutons, c'est lui qui donnerait la mesure — personne n'est tronqué dans un cas comme dans
   l'autre. */
.event-purchase .purchase-entry-footer {width: -webkit-fit-content; width: fit-content; max-width: 100%; margin-left: auto; margin-right: auto;}
.event-purchase .purchase-total-detail {font-size: 14px; margin: 0;}

.event-purchase .purchase-total-count {margin-bottom: 4px;}
/* Toute la ligne du carnet est cliquable : chaque cellule porte un label de la même case. */
.event-purchase .purchase-contact-email label {display: block; margin: 0; font-weight: normal; cursor: pointer;}

/* « Calculer le total » n'a rien à calculer tant qu'aucune personne n'est retenue : ni case
   cochée dans le carnet, ni saisie ouverte. Règle en :has pour qu'elle suive la case cochée
   sans aller-retour serveur ; un navigateur sans :has laisse simplement le bouton visible. */
.event-purchase .purchase-section:not(:has(.purchase-saved input:checked)):not(:has(.purchase-entry)) .purchase-preview {display: none;}

/* Action d'une cellule cliquable de la liste des inscrits : c'est la cellule qui porte la
   couleur et l'icône, le bouton n'est là que pour poster le formulaire. */
.btn-cellAction {background: none; border: 0; padding: 0; width: 100%; color: inherit; cursor: pointer; line-height: 1;}
.btn-cellAction:focus-visible {outline: 2px solid #224574; outline-offset: 2px;}
td.clicable:hover .btn-cellAction {opacity: .75;}

/* Bénéficiaire déjà inscrit ou déjà réservé : ligne inerte. La case porte l'attribut disabled,
   la couleur ne fait que le rendre lisible. */
.event-purchase .purchase-contact.is-taken td,
.event-purchase .purchase-contact.is-taken label {color: #999;}
.event-purchase .purchase-contact.is-taken label {cursor: not-allowed;}
.event-purchase .purchase-contact.is-taken .purchase-contact-box input {cursor: not-allowed;}
/* Déjà inscrit : un pictogramme plutôt qu'une étiquette, l'état se lit d'un coup d'œil sur une
   liste. Le sens interdit, et non un utilisateur barré : celui-ci se lisait comme un bouton de
   retrait, l'action que la ligne refuse précisément. Le texte reste pour les lecteurs d'écran
   et en infobulle. Il occupe la colonne du tarif, à la place du select qu'il remplace. */
.event-purchase .purchase-contact-taken {font-size: 14px; cursor: not-allowed;}

/* Plafond de places atteint, ou grille sans tarif public : information d'état, pas une erreur
   de saisie. Même traitement visuel, deux classes, parce que ce sont deux motifs distincts. */
.event-purchase .purchase-full-notice,
.event-purchase .purchase-no-tariff-notice {border-left: 4px solid #8a6d3b; background: #fcf8e3; padding: 16px; margin-bottom: 20px;}
/* d-flex-absCenter pose display:flex sur le bouton « Acheter » : une feuille d'auteur bat la
   règle [hidden] du navigateur, et l'élément resterait visible une fois masqué. */
.event-purchase [hidden] {display: none !important;}

/* Les deux actions de l'étape 1 — déplier une saisie, calculer le total — sont empilées et
   centrées : une différence de largeur se voit tout de suite. La largeur vient du conteneur et
   non du libellé, pour ne pas dépendre de la longueur du texte. */
.event-purchase .purchase-cta {max-width: 320px; margin-left: auto; margin-right: auto;}
.event-purchase .purchase-cta > .btn {width: 100%;}

/* Le titre de l'étape 1 vit en légende du tableau : caption est gris et aligné à gauche par
   défaut dans Bootstrap, on reprend la main sur la graisse et l'espacement. */
.event-purchase .purchase-saved-table > caption {padding: 0 0 8px; font-size: 18px; font-weight: 700;}

/* Styles auparavant en ligne. Le décor de la modale reste, lui, dans son gabarit : il est
   recopié tel quel de crm/_modal_shell.html.twig, et l'extraire masquerait toute divergence
   future entre les deux modales. */
.event-purchase .purchase-total-amount {margin-top: 0; font-size: 50px;}
.event-purchase .purchase-row-actions {white-space: nowrap;}
.beneficiary-modal-fields {padding: 0 2rem;}
/* Bouton « en creux » : ouvre une saisie ou la modale, par opposition aux boutons pleins qui
   valident. Hors .event-purchase aussi, le bloc d'appel vivant sur la page événement. */
.purchase-btn-outline {border: 1px dotted; white-space: normal;}
/* L'encadré ferme la colonne, sous l'inscription individuelle : la marge le détache de ce qui
   le précède, comme le style en ligne des autres .tarifsHolder de la page. */
#groupPurchaseTeaser {margin-top: 20px;}
