/* ---------------------------------------------------------------------------
 * Complément Symfony du design V28.
 *
 * Le design lui-même vit dans assets/styles/v28.css, GÉNÉRÉ verbatim depuis
 * _source/Sedam-Valentin-V28-Actions-Tabulaires-Comite.html
 * (php scripts/extract-design-v28.php). Ce fichier est chargé APRÈS et ne
 * contient que ce que la maquette ne pouvait pas prévoir : rendu serveur
 * (thème de formulaire, flashs, pagination), Turbo (frames, modales <dialog>),
 * et les contrôleurs Stimulus (dropzone, tri).
 *
 * Règle : ne jamais redéfinir ici un composant déjà stylé par v28.css. Si le
 * rendu diverge de la maquette, c'est le DOM du gabarit Twig qu'il faut
 * corriger, pas le CSS.
 * ------------------------------------------------------------------------- */

/* ---------- Turbo ---------- */

turbo-frame { display: block; min-width: 0; }
turbo-frame[busy] { opacity: .6; transition: opacity .12s ease; }

/* ---------- Modales CRUD : <dialog> portant le style .modal de la maquette ---------- */

dialog.modal {
    border: 1px solid var(--line);
    padding: 0;
    color: var(--ink);
    /* .modal de la maquette est centré par son .modal-bg ; <dialog> se centre seul. */
    margin: auto;
}
dialog.modal::backdrop { background: rgba(0, 9, 18, .68); backdrop-filter: blur(5px); }
dialog.modal .mh h3 { font-size: 16px; }
dialog.modal .mh .x { margin-left: auto; border: 0; background: none; color: var(--muted); font-size: 22px; cursor: pointer; line-height: 1; }
dialog.modal .mb .field:last-child { margin-bottom: 0; }
dialog.modal form { margin: 0; }

/* ---------- Thème de formulaire : erreurs et aides ---------- */

.field .errors {
    list-style: none;
    margin: 6px 0 0;
    padding: 0;
    color: var(--err);
    font-size: 12px;
}
.field .help { display: block; margin-top: 5px; color: var(--muted); font-size: 11px; }
.field.field-checkbox { display: flex; align-items: center; gap: 8px; }
.field.field-checkbox input { width: auto; }
.field.field-checkbox label { margin: 0; }
.field-row { display: flex; gap: 12px; flex-wrap: wrap; }
.field-row > .field { flex: 1 1 200px; margin-bottom: 14px; }

/* ---------- Flashs (la maquette n'avait que le toast client) ---------- */

.flash {
    border-radius: 12px;
    padding: 11px 15px;
    margin-bottom: 14px;
    border: 1px solid var(--line);
    background: var(--panel);
    color: var(--ink);
    font-size: 13px;
}
.flash-success { border-color: color-mix(in srgb, var(--ok) 45%, var(--line)); color: var(--ok); }
.flash-error { border-color: color-mix(in srgb, var(--err) 45%, var(--line)); color: var(--err); }

/* ---------- Pagination bornée (absente de la maquette : listes non paginées) ---------- */

.pagination {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-top: 18px;
    color: var(--muted);
    font-size: 12px;
}
.pagination a, .pagination span {
    padding: 7px 12px;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--panel);
}
.pagination a:hover { background: var(--hover); text-decoration: none; }
.pagination .current { background: var(--brand); color: #fff; border-color: transparent; }

/* ---------- Accès de démonstration : rangées cliquables en vrais <button> ---------- */

.cred-bubble form { margin: 0; }
.cred-bubble button.cb-row {
    width: 100%;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
}

/* ---------- Contrôleurs Stimulus ---------- */

.dropzone-input {
    border: 2px dashed var(--line);
    border-radius: 10px;
    padding: 12px;
    width: 100%;
    background: var(--field);
    color: var(--ink);
}
.dropzone-input.dragover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
[data-sortable-handle] { cursor: grab; user-select: none; }
[data-sortable-handle]:active { cursor: grabbing; }
.sortable-ghost { opacity: .45; }

/* ---------- Modules interactifs : bac à sable visuel du HTML/CSS assaini ---------- */

.module-frame {
    border: 1px solid var(--line);
    border-radius: 12px;
    overflow: hidden;
    background: #fff;
    color: #111;
    padding: 14px;
}

/* ---------- Accessibilité ---------- */

.visually-hidden {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ---------------------------------------------------------------------------
 * Ponts <button> → <a>
 *
 * La maquette naviguait en JavaScript : ses actions étaient des <button
 * onclick>. Ici la navigation est faite de liens (Turbo Drive), et deux
 * sélecteurs de la maquette sont écrits pour `button`. On les rejoue à
 * l'identique pour `a` — mêmes valeurs, aucune invention. À resynchroniser si
 * ces règles changent dans v28.css.
 * ------------------------------------------------------------------------- */

/* v28.css : .v19-page-actions button */
.v19-page-actions a {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 39px;
    padding: 0 14px;
    border-radius: 9px;
    border: 1px solid var(--line);
    background: var(--field);
    color: var(--ink);
    font-size: 9px;
    font-weight: 900;
}
.v19-page-actions a.primary { border-color: var(--accent); background: var(--accent); color: #fff; }
.v19-page-actions a:hover { text-decoration: none; }
.v19-page-actions a svg { width: 14px; height: 14px; }

/* v28.css : .sv28-inline-ops button */
.sv28-inline-ops a {
    display: inline-flex;
    align-items: center;
    height: 36px;
    padding: 0 11px;
    border: 1px solid var(--line);
    border-radius: 9px;
    background: var(--field);
    color: var(--ink);
    font-size: 10px;
    font-weight: 850;
}
.sv28-inline-ops a:hover { text-decoration: none; }

/* v28.css : .sv28-tab est écrit pour <button>, qui centre son texte verticalement. */
a.sv28-tab { display: inline-flex; align-items: center; justify-content: center; }

/* Un formulaire d'action (POST + CSRF) ne doit pas casser l'alignement du rail. */
.sv28-action-host form, .v19-page-actions form { display: contents; }

/* Déconnexion : formulaire POST (CSRF) transparent pour que le <button> reste
   l'élément de grille de `.sidebar .foot` ; remise à zéro des styles natifs. */
.logout-form { display: contents; }
.logout-btn { border: 0; padding: 0; }

/* Les liens qui portent un composant ne doivent pas hériter du style de lien. */
a:where(.v19-entity-card, .v20-premium-card, .sv28-tab, .sv28-action, .sv28-doc-item, .v4-ai-doc, .cb-row) {
    color: inherit;
    text-decoration: none;
}
a:where(.v19-entity-card, .v20-premium-card, .sv28-tab, .sv28-action, .sv28-doc-item, .v4-ai-doc, .cb-row):hover {
    text-decoration: none;
}
a.sv28-doc-item, a.v4-ai-doc { display: block; }
a.v4-ai-doc { display: flex; }
.sv28-doc-item[aria-current="page"], .v4-ai-doc[aria-current="page"] {
    background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.qr-box img { width: 100%; height: auto; display: block; }

/* ---------------------------------------------------------------------------
 * Écrans qui n'existaient pas dans la maquette
 *
 * Trois écrans du portage n'ont pas d'équivalent V28 : titres de section du
 * centre de contrôle, extrait de recherche plein texte, empilement de modules
 * d'une machine. Réglages d'espacement uniquement, jamais de nouvelle identité.
 * ------------------------------------------------------------------------- */

.sv28-section-title { margin: 26px 0 10px; font-size: 15px; font-weight: 850; color: var(--ink); }
.sv28-section-title:first-child { margin-top: 0; }
.search-extract { grid-column: span 3; }
.module-block { margin-bottom: 22px; }

/* Aperçu documentaire d'une machine : le volet droit est une frame Turbo, sa
   tête réutilise le vocabulaire `.sv28-doc-item` (titre + méta) sans le lien. */
.sv28-doc-preview-pane { min-height: 360px; }
.sv28-doc-preview-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 10px;
    border-bottom: 1px solid color-mix(in srgb, var(--line) 58%, transparent);
}
.sv28-doc-preview-head strong { display: block; color: var(--ink); font-size: 14px; }
.sv28-doc-preview-head small { color: var(--muted); font-size: 10px; }

/* Nos fiches portent plus d'actions que celles de la maquette : sur petit écran,
   le rail doit passer à la ligne au lieu de déborder hors du cadre. */
@media (max-width: 1100px) {
    .sv28-action-host { flex-wrap: wrap; }
}

/* ---------------------------------------------------------------------------
 * Logo de l'écran de connexion : déclinaison blanche en thème nuit
 *
 * Le logo est un bleu plein (#0048a8 à #0060a8) sur fond transparent. Sur le
 * héros sombre de `#login`, le mot « VALENTIN » tombait à **1,90:1** de contraste
 * — sous le seuil de 3:1 attendu pour un élément graphique.
 *
 * Réponse retenue : une **déclinaison monochrome blanche**, comme le fait toute
 * charte pour un fond sombre. `brightness(0)` écrase les pixels opaques en noir
 * en préservant la transparence, `invert(1)` les passe en blanc : silhouette
 * exacte du logo, aucun halo, aucun fichier supplémentaire. Le soulignement
 * rouge passe lui aussi en blanc — c'est le propre d'un logo monochrome.
 *
 * `filter` remplace la propriété héritée : l'ombre portée de la maquette
 * (`drop-shadow`) est donc reconduite ici, après la mise en blanc.
 *
 * En thème jour, le logo reste dans ses couleurs de marque sur le héros clair.
 * ------------------------------------------------------------------------- */

html[data-theme="night"] #login .login-logo {
    filter: brightness(0) invert(1) drop-shadow(0 14px 28px rgba(0, 0, 0, .35));
}

/* Même famille de défaut, thème inverse : la baseline sous le logo est un bleu
 * clair (#63beff) que la maquette n'a jamais décliné en thème jour — 1,97:1 sur
 * le héros clair. On reprend le bleu jour que le design utilise déjà juste à
 * côté, pour `.login-security b` : 5,73:1, sans introduire de teinte nouvelle. */
html[data-theme="day"] #login .brand-tag { color: #0b67ad; }

/* ---------------------------------------------------------------------------
 * Écran de connexion : proportions demandées en revue
 *
 * Le logo et sa baseline sont agrandis par rapport à la maquette. Le logo garde
 * `object-fit: contain` : c'est la hauteur de la boîte qui commande la taille
 * rendue, la largeur ne fait que lui laisser la place (ratio 383/122).
 * ------------------------------------------------------------------------- */

/* `!important` obligatoire : la couche de la maquette fixe déjà ces dimensions
   en `!important`, un simple ordre de chargement ne suffirait pas à passer. */
#login .login-logo {
    width: min(560px, 82%) !important;
    height: 158px !important;
    margin-bottom: 22px !important;
}

#login .brand-tag {
    font-size: 13px;
    letter-spacing: .2em;
}

@media (max-width: 1280px) {
    #login .login-logo { height: 136px !important; }
}

/* Titre et chapeau partagent exactement la largeur utile du panneau : ils
   s'alignent par construction, sans largeur magique à maintenir. La colonne est
   élargie vers la droite pour que « machines SEDAM VALENTIN » tienne sur une
   ligne — il lui fallait 941 px à la taille d'origine, contre 748 disponibles.
   `!important` partout : la maquette verrouille ces quatre propriétés au même
   niveau (`#login h1`, `#login p.lead`, `#login .left`). */
#login .left {
    padding-right: clamp(28px, 2.5vw, 40px) !important;
}

/* Taille calibrée par mesure, pas à l'estime : « machines avec Sedam Valentin »
   doit tenir sur une ligne jusqu'à 981 px — dernière largeur où le panneau
   gauche est affiché. La largeur disponible ne suit pas le viewport (le padding
   est en clamp), d'où deux paliers plutôt qu'un coefficient unique.
   Marge conservée ~5 % pour absorber une substitution de police. */
#login h1 {
    max-width: 100% !important;
    font-size: clamp(30px, 3.7vw, 56px) !important;
}

@media (max-width: 1100px) {
    #login h1 { font-size: 3.35vw !important; }
}

#login h1 span { white-space: nowrap; }

#login p.lead {
    max-width: 100% !important;
}

/* ---------------------------------------------------------------------------
 * Écran de connexion sur mobile : la marque redevient visible
 *
 * La maquette masque purement et simplement le panneau gauche sous 980 px
 * (`#login .left { display:none }`) : sur smartphone, il ne restait que le
 * formulaire, sans logo ni texte.
 *
 * On repasse l'écran en une colonne et on ordonne les blocs autour du
 * formulaire : logo et signature au-dessus — l'identité se voit tout de suite —
 * puis le formulaire, immédiatement utilisable sans défiler, et enfin le
 * discours. C'est l'ordre qui sert un outil de terrain : on arrive ici après
 * avoir scanné un QR code, la connexion prime sur la lecture.
 *
 * `display: contents` sur `.left` fait disparaître la boîte sans toucher au
 * gabarit : ses enfants deviennent enfants de `#login` et peuvent donc être
 * réordonnés individuellement.
 * ------------------------------------------------------------------------- */

@media (max-width: 980px) {
    /* Spécificité alignée sur `#login:not(.hidden)` de la maquette, qui impose
       `display:grid` — sans quoi la mise en colonne ne passerait pas. */
    #login:not(.hidden) {
        display: flex !important;
        flex-direction: column !important;
        align-items: center !important;
        justify-content: flex-start !important;
        padding: 26px 14px 36px !important;
        gap: 0 !important;
        /* `#login` est en `position:fixed` avec `overflow:hidden` : sans cela, tout
           ce qui dépasse la hauteur de l'écran est coupé ET inatteignable. */
        overflow-x: hidden !important;
        overflow-y: auto !important;
        overscroll-behavior: contain;
        /* Barres d'outils mobiles : `dvh` suit leur apparition, `vh` non. */
        height: 100dvh !important;
    }

    /* Filigrane « SV » ancré hors cadre (bottom:-8%) : il ajouterait du vide
       à faire défiler une fois l'overflow libéré. */
    #login::after { display: none !important; }

    #login .left { display: contents !important; }
    /* Décor absolu calibré pour un grand panneau : il déborderait ici. */
    #login .login-tech-signature { display: none !important; }

    /* Une seule colonne : tous les blocs partagent la largeur de la carte,
       donc le même bord gauche. */
    #login .login-logo,
    #login .brand-tag,
    #login .right,
    #login h1,
    #login p.lead {
        width: min(520px, calc(100vw - 28px)) !important;
        max-width: min(520px, calc(100vw - 28px)) !important;
        /* Enfants d'un conteneur flex en colonne : sans cela ils se laissent
           comprimer sous leur hauteur naturelle et leur contenu déborde —
           la bulle de démonstration passait par-dessus le titre. */
        flex: 0 0 auto !important;
    }

    #login .login-logo {
        order: 1;
        height: 56px !important;
        margin: 0 0 9px !important;
    }
    #login .brand-tag {
        order: 2;
        margin: 0 0 18px;
        font-size: 10px;
        letter-spacing: .14em;
    }
    #login .right {
        order: 3;
        margin: 0 !important;
        min-height: 0 !important;
    }
    #login h1 {
        order: 4;
        margin: 30px 0 0 !important;
        font-size: clamp(24px, 6.6vw, 32px) !important;
        line-height: 1.04 !important;
    }
    #login p.lead {
        order: 5;
        margin: 12px 0 0 !important;
        font-size: 14px !important;
    }
}

/* ---------------------------------------------------------------------------
 * Navigation latérale en accordéons (volet admin)
 *
 * HTML natif `<details>/<summary>` : repli/dépli sans JavaScript, au clavier,
 * annoncé par les lecteurs d'écran. L'accordéon qui contient la route courante
 * est rendu `open` par le serveur (voir templates/_nav.html.twig). On ne
 * redéfinit ici que ce que la maquette ne pouvait pas prévoir — le vocabulaire
 * `.nav a` de v28.css reste la référence pour les liens eux-mêmes.
 * ------------------------------------------------------------------------- */

.nav .nav-acc { margin: 6px 0; }

.nav .nav-acc-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    min-height: 42px;
    padding: 10px 12px;
    border-radius: 5px;
    color: var(--muted);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    cursor: pointer;
    list-style: none;
    user-select: none;
}
.nav .nav-acc-summary::-webkit-details-marker { display: none; }
.nav .nav-acc-summary:hover { color: var(--ink); background: var(--hover); }
.nav .nav-acc[open] > .nav-acc-summary { color: var(--ink); }
/* Contraste jour aligné sur les liens de nav (v28.css : #627d97). */
html[data-theme="day"] .nav .nav-acc-summary { color: #627d97; }

.nav .nav-acc-chevron {
    width: 15px;
    height: 15px;
    flex: none;
    opacity: .75;
    transition: transform .18s ease;
}
.nav .nav-acc[open] > .nav-acc-summary .nav-acc-chevron { transform: rotate(180deg); }

.nav .nav-acc-panel { padding: 2px 0 6px; }

/* Repli par défaut sur petit écran ? Non : le tiroir fait ~328 px, les libellés
   restent lisibles. Aucun traitement spécial n'est requis. */
