/* =============================================================================
   PSS — PHONE STRATEGIC SOURCING
   Console d'atelier. Espace de travail gris clair, navigation bleu nuit,
   accents cyan → vert repris du logo. Lisible à un mètre, cibles larges.
   ========================================================================== */

:root {
    /* Espace de travail */
    --paper:      #EDF1F5;
    --card:       #FFFFFF;
    --card-2:     #F4F7FA;
    --line:       #D3DCE4;
    --line-soft:  #E3E9EF;

    /* Navigation : bleu nuit, le logo y ressort */
    --deep:       #0C1922;
    --deep-2:     #142B38;
    --deep-line:  #1E4051;

    /* Marque */
    --cyan:       #0E8FA6;
    --cyan-vivid: #16B5D0;
    --lime:       #6E9E00;
    --lime-vivid: #8FD400;
    --brand:      linear-gradient(115deg, #16B5D0 0%, #8FD400 100%);

    /* Texte */
    --text:       #12222D;
    --text-soft:  #4A6272;
    --text-dim:   #74909F;

    /* Signalétique atelier */
    --signal:     #46760A;
    --signal-bg:  #EAF6D5;
    --alert:      #C42B1F;
    --alert-bg:   #FCE9E7;
    --wait:       #96610A;
    --wait-bg:    #FDF2DE;
    --info:       #0E7490;
    --info-bg:    #E2F3F8;

    --radius:     6px;
    --gap:        8px;
    --nav-w:      192px;
    --shadow:     0 1px 2px rgba(18, 34, 45, 0.06), 0 1px 3px rgba(18, 34, 45, 0.04);

    --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --mono: ui-monospace, "SFMono-Regular", "Cascadia Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

*, *::before, *::after { box-sizing: border-box; }

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

body {
    margin: 0;
    font-family: var(--font);
    font-size: 13px;
    line-height: 1.38;
    color: var(--text);
    background: var(--paper);
    -webkit-font-smoothing: antialiased;
}

a { color: var(--cyan); text-decoration: none; }
a:hover { color: #0A6B7C; text-decoration: underline; }

h1, h2, h3 { margin: 0 0 8px; line-height: 1.2; }
h1 { font-size: 15px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; }
h2 { font-size: 12px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; }
h3 {
    font-size: 10px; font-weight: 700; letter-spacing: 0.14em;
    text-transform: uppercase; color: var(--text-dim); margin-bottom: 6px;
}

/* -------------------------------------------------------------- Structure */
.shell {
    display: flex;
    min-height: 100vh;
    gap: 0;
    padding: 6px;
}

/* ---- Barre latérale : panneau flottant, arrondi, détaché du bord ---- */
.nav {
    width: var(--nav-w);
    flex: 0 0 var(--nav-w);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 6px;
    height: calc(100vh - 12px);
    border-radius: 12px;
    overflow: hidden;
    background:
        radial-gradient(420px 200px at 20% 0%, rgba(22, 181, 208, 0.22), transparent 65%),
        radial-gradient(360px 260px at 100% 100%, rgba(143, 212, 0, 0.14), transparent 65%),
        linear-gradient(180deg, #102534 0%, #0A1620 100%);
    box-shadow: 0 12px 34px rgba(12, 25, 34, 0.22);
}

/* Trame de circuit imprimé, très discrète, reprise du logo */
.nav::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(rgba(255, 255, 255, 0.035) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, 0.035) 1px, transparent 1px);
    background-size: 38px 38px;
    -webkit-mask-image: linear-gradient(180deg, #000 0%, transparent 55%);
    mask-image: linear-gradient(180deg, #000 0%, transparent 55%);
    pointer-events: none;
}

.nav__brand {
    padding: 11px 11px 9px;
    text-align: center;
    position: relative;
}
.nav__brand img {
    width: 100%;
    max-width: 118px;
    height: auto;
    display: block;
    margin: 0 auto;
}
.nav__brand span {
    display: block;
    margin-top: 6px;
    font-size: 8px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: #6E8D9D;
}
/* Séparateur dégradé, plus doux qu'un trait plein */
.nav__brand::after {
    content: "";
    position: absolute;
    left: 22px; right: 22px; bottom: 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(22,181,208,.55), rgba(143,212,0,.45), transparent);
}

.nav__scroll {
    flex: 1;
    overflow-y: auto;
    padding: 6px 0 10px;
    scrollbar-width: thin;
    scrollbar-color: rgba(255,255,255,.16) transparent;
}
.nav__scroll::-webkit-scrollbar { width: 6px; }
.nav__scroll::-webkit-scrollbar-thumb { background: rgba(255,255,255,.14); border-radius: 3px; }

.nav__group { padding: 8px 0 0; position: relative; }

.nav__group-title {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 14px 5px;
    font-size: 8.5px;
    text-transform: uppercase;
    letter-spacing: 0.2em;
    color: #5E7C8C;
}
/* Petite amorce de piste, à la place d'un simple libellé aligné */
.nav__group-title::after {
    content: "";
    flex: 1;
    height: 1px;
    background: linear-gradient(90deg, rgba(255,255,255,.12), transparent);
}

.nav__link {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 1px 6px;
    padding: 6px 9px;
    border-radius: 8px;
    color: #AFC4D0;
    font-size: 13px;
    font-weight: 500;
    position: relative;
    transition: background .15s ease, color .15s ease, transform .12s ease;
}
.nav__link:hover {
    background: rgba(255, 255, 255, 0.07);
    color: #FFF;
    transform: translateX(3px);
    text-decoration: none;
}

.nav__icon {
    width: 16px;
    height: 16px;
    flex: 0 0 16px;
    opacity: .82;
    transition: opacity .15s ease, color .15s ease;
}
.nav__link:hover .nav__icon { opacity: 1; }

.nav__label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Élément actif : pastille au dégradé de la marque */
.nav__link--active {
    background: linear-gradient(112deg, #16B5D0 0%, #58C56A 55%, #8FD400 100%);
    color: #05161D;
    font-weight: 700;
    text-decoration: none;
    box-shadow: 0 6px 16px rgba(22, 181, 208, 0.28);
}
.nav__link--active:hover {
    background: linear-gradient(112deg, #16B5D0 0%, #58C56A 55%, #8FD400 100%);
    color: #05161D;
    transform: translateX(3px);
}
.nav__link--active .nav__icon { opacity: 1; }

/* ---- Pied : compte connecté ---- */
.nav__footer {
    padding: 10px 12px 12px;
    position: relative;
}
.nav__footer::before {
    content: "";
    position: absolute;
    left: 20px; right: 20px; top: 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(255,255,255,.14), transparent);
}

.nav__account { display: flex; align-items: center; gap: 12px; }

.nav__avatar {
    flex: 0 0 32px;
    width: 32px; height: 32px;
    border-radius: 9px;
    display: flex; align-items: center; justify-content: center;
    background: linear-gradient(135deg, #16B5D0, #8FD400);
    color: #05161D;
    font-weight: 800;
    font-size: 14px;
    letter-spacing: 0.04em;
}

.nav__identity { min-width: 0; display: block; }
.nav__user {
    display: block;
    color: #FFF;
    font-weight: 600;
    font-size: 14px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.nav__role {
    display: block;
    color: #8FD400;
    text-transform: uppercase;
    font-size: 9px;
    letter-spacing: 0.18em;
    margin-top: 1px;
}

.nav__account-actions { display: flex; gap: 6px; margin-top: 9px; }
.nav__account-actions form { margin: 0; flex: 1; }

.nav__action {
    display: block;
    width: 100%;
    text-align: center;
    padding: 5px 8px;
    border-radius: 7px;
    border: 1px solid rgba(255,255,255,.14);
    background: rgba(255,255,255,.05);
    color: #B6C9D4;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    flex: 1;
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.nav__action:hover {
    background: rgba(255,255,255,.11);
    color: #FFF;
    text-decoration: none;
    border-color: rgba(255,255,255,.24);
}
.nav__action--exit:hover { border-color: rgba(255,90,78,.5); color: #FF9B93; }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; padding-left: 6px; }

.topbar {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: 9px;
    box-shadow: var(--shadow);
    padding: 6px 12px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--gap);
    position: relative;
}
.topbar::after {
    content: "";
    position: absolute;
    left: 22px; right: 22px; bottom: -1px;
    height: 3px;
    border-radius: 3px;
    background: var(--brand);
}
.topbar h1 { margin: 0; }

.content { padding: 8px 0 5px; flex: 1; }
.content > * + * { margin-top: var(--gap); }

/* -------------------------------------------------------------- Cartes */
.card {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    overflow: hidden;
}
.card__head {
    padding: 15px 20px;
    border-bottom: 1px solid var(--line-soft);
    background: var(--card-2);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}
.card__head h2 { margin: 0; }
.card__body { padding: 11px; }
.card__body > * + * { margin-top: 8px; }

.grid { display: grid; gap: var(--gap); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }

/* Compteurs : le chiffre est l'information, tout le reste s'efface */
.metric {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 9px 11px;
    position: relative;
    overflow: hidden;
}
.metric::before {
    content: "";
    position: absolute;
    top: 0; left: 0;
    width: 3px; height: 100%;
    background: var(--brand);
}
.metric__value {
    font-size: 22px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    line-height: 1.05;
    letter-spacing: -0.02em;
    color: var(--text);
}
.metric__label {
    font-size: 9px;
    text-transform: uppercase;
    letter-spacing: 0.13em;
    color: var(--text-dim);
    margin-top: 3px;
}

/* -------------------------------------------------------------- IMEI */
/* Traitement unique dans toute l'application : l'IMEI est le centre du système. */
.imei {
    display: inline-block;
    font-family: var(--mono);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0;
    font-variant-numeric: tabular-nums;
    /* Sélection au double-clic, pas au premier : « all » mettait l'IMEI en
       surbrillance dès qu'on effleurait la cellule, et la ligne ne s'ouvrait
       plus. Le double-clic sélectionne le numéro entier, géré au script. */
    -moz-user-select: text;
    user-select: text;
    cursor: text;
    color: var(--text);
    background: linear-gradient(to top, rgba(143, 212, 0, 0.28) 0 3px, rgba(22, 181, 208, 0.07) 3px);
    padding: 0 4px;
    border-radius: 3px 3px 0 0;
    white-space: nowrap;
}

/* -------------------------------------------------------------- Boutons */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 30px;
    padding: 5px 12px;
    border: 1px solid transparent;
    border-radius: var(--radius);
    background: var(--deep);
    color: #FFF;
    font: inherit;
    font-weight: 700;
    letter-spacing: 0.03em;
    cursor: pointer;
    text-align: center;
    transition: filter .12s ease, transform .06s ease;
}
.btn:hover { background: var(--deep-2); color: #FFF; text-decoration: none; }
.btn:active { transform: translateY(1px); }

.btn:focus-visible, a:focus-visible, input:focus-visible,
select:focus-visible, button:focus-visible, textarea:focus-visible {
    outline: 3px solid var(--cyan-vivid);
    outline-offset: 2px;
}

.btn--ghost {
    background: var(--card);
    color: var(--text);
    border-color: var(--line);
}
.btn--ghost:hover { background: var(--card-2); color: var(--text); border-color: var(--cyan); }

/* Action principale : le dégradé de la marque */
.btn--go {
    background: var(--brand);
    color: #06131A;
    border-color: transparent;
}
.btn--go:hover { filter: brightness(1.08); background: var(--brand); color: #06131A; }

.btn--stop { background: #C42B1F; color: #FFF; }
.btn--stop:hover { background: #A32217; color: #FFF; }

.btn--lg { min-height: 36px; font-size: 13px; padding: 8px 18px; }
.btn--sm { min-height: 26px; padding: 3px 10px; font-size: 12px; }
.btn--block { width: 100%; }
.btn[disabled] { opacity: 0.45; cursor: not-allowed; filter: grayscale(0.4); }

.actions { display: flex; flex-wrap: wrap; gap: 7px; align-items: center; }

/* -------------------------------------------------------------- Formulaires */
.field { margin-bottom: 9px; }
.field > label {
    display: block;
    font-size: 10px;
    font-weight: 700;
    margin-bottom: 4px;
    text-transform: uppercase;
    letter-spacing: 0.11em;
    color: var(--text-soft);
}
.input, select, textarea {
    width: 100%;
    min-height: 31px;
    padding: 5px 9px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--card);
    font: inherit;
    color: var(--text);
    transition: border-color .12s ease, box-shadow .12s ease;
}
.input::placeholder { color: var(--text-dim); }
.input:focus, select:focus, textarea:focus {
    border-color: var(--cyan-vivid);
    box-shadow: 0 0 0 3px rgba(22, 181, 208, 0.18);
}
.input--mono { font-family: var(--mono); letter-spacing: 0.1em; font-weight: 600; }

select {
    appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, #4A6272 50%),
                      linear-gradient(135deg, #4A6272 50%, transparent 50%);
    background-position: calc(100% - 19px) 50%, calc(100% - 13px) 50%;
    background-size: 6px 6px, 6px 6px;
    background-repeat: no-repeat;
    padding-right: 38px;
}

input[type="file"] { padding: 10px 12px; }
input[type="file"]::file-selector-button {
    background: var(--card-2); color: var(--text); border: 1px solid var(--line);
    border-radius: 5px; padding: 7px 14px; margin-right: 12px; cursor: pointer; font: inherit;
}

.field__hint { font-size: 12px; color: var(--text-dim); margin-top: 3px; }
.field__error { font-size: 12px; color: var(--alert); margin-top: 3px; font-weight: 600; }
.field--invalid .input, .field--invalid select { border-color: var(--alert); }

.check { display: flex; align-items: flex-start; gap: 8px; padding: 3px 0; }
.check input { width: 17px; height: 17px; margin: 1px 0 0; flex: 0 0 auto; accent-color: #16B5D0; }
.check label {
    font-weight: 500; text-transform: none; letter-spacing: 0;
    color: var(--text); margin: 0; font-size: 13.5px;
}
.check label .small { display: block; color: var(--text-dim); }

fieldset {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 8px 10px;
    margin: 0 0 9px;
    background: var(--card-2);
}
legend {
    font-size: 10px; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.18em; color: var(--cyan); padding: 0 8px;
}

code {
    font-family: var(--mono);
    font-size: 0.9em;
    background: var(--card-2);
    border: 1px solid var(--line);
    padding: 1px 6px;
    border-radius: 4px;
    color: #0A6B7C;
}

/* -------------------------------------------------------------- Tableaux */
.table-wrap { overflow-x: auto; }
table.table { width: 100%; border-collapse: collapse; font-size: 12px; }

/* Valeurs centrées dans leur colonne : l'œil suit les colonnes plutôt que
   de balayer chaque ligne. Les chiffres restent en chasse fixe pour rester
   comparables d'une ligne à l'autre. */
.table th, .table td {
    padding: 4px 8px;
    text-align: center;
    border-bottom: 1px solid var(--line-soft);
    vertical-align: middle;
}
.table th {
    background: var(--card-2);
    font-size: 9px;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-soft);
    font-weight: 700;
    white-space: nowrap;
    text-align: center;
    position: sticky;
    top: 0;
    z-index: 2;
    border-bottom: 1px solid var(--line);
}
.table tbody tr { transition: background .1s ease; }
.table tbody tr:hover { background: #F0F8FA; }
.table tbody tr:last-child td { border-bottom: 0; }
.table td.num, .table th.num { text-align: center; font-variant-numeric: tabular-nums; }
.table__empty { padding: 20px; text-align: center; color: var(--text-dim); }

/* -------------------------------------------------------------- Signalétique */
.tag {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    border: 1px solid transparent;
}
.tag--on   { background: var(--signal-bg); color: var(--signal); border-color: #C4E38C; }
.tag--off  { background: #EDF1F5; color: var(--text-dim); border-color: var(--line); }
.tag--warn { background: var(--wait-bg); color: var(--wait); border-color: #EFD4A0; }
.tag--stop { background: var(--alert-bg); color: var(--alert); border-color: #F1BEB9; }
.tag--info { background: var(--info-bg); color: var(--info); border-color: #A9DAE7; }

.flash {
    padding: 7px 11px;
    border-radius: var(--radius);
    border: 1px solid;
    border-left-width: 4px;
    font-weight: 600;
    font-size: 13px;
}
.flash--success { background: var(--signal-bg); border-color: #7CB518; color: #35590A; }
.flash--error   { background: var(--alert-bg);  border-color: var(--alert);  color: #8C1E15; }
.flash--warning { background: var(--wait-bg);   border-color: #D89216;       color: #6E4707; }

.muted { color: var(--text-dim); }
.small { font-size: 12px; }
.nowrap { white-space: nowrap; }
.stack > * + * { margin-top: 8px; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }

/* -------------------------------------------------------------- Pages nues */
.blank {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 26px;
    background:
        radial-gradient(820px 460px at 50% -8%, rgba(22, 181, 208, 0.10), transparent 70%),
        radial-gradient(620px 380px at 88% 108%, rgba(143, 212, 0, 0.10), transparent 70%),
        var(--paper);
    position: relative;
    overflow: hidden;
}

/* Signature : trame de circuit imprimé en fond, rappel du logo */
.blank::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(rgba(18, 34, 45, 0.05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(18, 34, 45, 0.05) 1px, transparent 1px);
    background-size: 46px 46px;
    -webkit-mask-image: radial-gradient(circle at 50% 40%, #000 0%, transparent 76%);
    mask-image: radial-gradient(circle at 50% 40%, #000 0%, transparent 76%);
    pointer-events: none;
}

.panel {
    position: relative;
    width: 100%;
    max-width: 400px;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 0 0 22px;
    box-shadow: 0 18px 48px rgba(18, 34, 45, 0.16);
    overflow: hidden;
}
.panel--wide { max-width: 800px; }

/* Le logo est blanc : il lui faut son bandeau bleu nuit */
.panel__brand {
    background: var(--deep);
    padding: 20px 18px 16px;
    text-align: center;
    margin: 0 0 18px;
    position: relative;
}
.panel__brand::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 3px;
    background: var(--brand);
}
.panel__brand img { width: 100%; max-width: 200px; height: auto; display: block; margin: 0 auto; }
.panel__brand span {
    display: block;
    font-size: 10px;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: #6C8B9B;
}

/* Le contenu des pages nues respire à l'intérieur du panneau */
.panel > form,
.panel > h2,
.panel > p,
.panel > ul,
.panel > .flash,
.panel > .steps,
.panel > .actions,
.panel > table { margin-left: 22px; margin-right: 22px; }
.panel > .flash { margin-bottom: 12px; }

/* -------------------------------------------------------------- Installation */
.steps { display: flex; gap: 5px; margin-bottom: 16px; flex-wrap: wrap; }
.steps__item {
    flex: 1;
    min-width: 96px;
    padding: 6px 8px;
    border-radius: 5px;
    background: var(--card-2);
    border: 1px solid var(--line);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-dim);
    text-align: center;
}
.steps__item--done { background: var(--signal-bg); color: var(--signal); border-color: #C4E38C; }
.steps__item--current { background: var(--deep); color: #FFF; border-color: var(--deep); }

.checklist { list-style: none; margin: 0; padding: 0; }
.checklist li {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 6px 0;
    border-bottom: 1px solid var(--line-soft);
    font-size: 13px;
}
.checklist li:last-child { border-bottom: 0; }
.checklist__state { font-weight: 700; font-size: 10px; letter-spacing: 0.12em; min-width: 82px; }
.checklist__state--ok { color: var(--signal); }
.checklist__state--ko { color: var(--alert); }

/* -------------------------------------------------------------- Matrice des droits */
.matrix { overflow-x: auto; }
.matrix table { border-collapse: collapse; width: 100%; font-size: 14px; }
.matrix th, .matrix td { border: 1px solid var(--line); padding: 5px 8px; }
.matrix thead th {
    background: var(--card-2); font-size: 10px;
    text-transform: uppercase; letter-spacing: 0.12em; color: var(--text-soft);
}
.matrix tbody th { text-align: left; font-weight: 500; }
.matrix td { text-align: center; }
.matrix input[type="checkbox"] { width: 20px; height: 20px; accent-color: #16B5D0; }

/* -------------------------------------------------------------- Pagination */
.pager { display: flex; gap: 7px; align-items: center; flex-wrap: wrap; }

/* -------------------------------------------------------------- Réactif */
@media (max-width: 900px) {
    .shell { flex-direction: column; padding: 10px; }
    .main { padding-left: 0; }
    .nav {
        width: 100%; flex: none; position: static;
        height: auto; border-radius: 14px; margin-bottom: 12px;
    }
    .nav__brand { padding: 16px 16px 14px; }
    .nav__brand img { max-width: 140px; }
    .nav__brand span { display: none; }
    .nav__scroll { display: flex; overflow-x: auto; padding: 8px; }
    .nav__group { display: flex; align-items: center; padding: 0; }
    .nav__group-title { display: none; }
    .nav__link { margin: 0 4px; white-space: nowrap; }
    .nav__link:hover, .nav__link--active:hover { transform: none; }
    .nav__footer { padding: 12px 14px 14px; }
    .nav__account-actions { margin-top: 10px; }
    .content { padding: 12px 0 6px; }
    .topbar { padding: 13px 16px; }
    .metric__value { font-size: 30px; }
    .panel > form, .panel > h2, .panel > p, .panel > ul,
    .panel > .flash, .panel > .steps, .panel > .actions,
    .panel > table { margin-left: 20px; margin-right: 20px; }
}

@media (prefers-reduced-motion: reduce) {
    * { animation: none !important; transition: none !important; }
}

@media print {
    .nav, .topbar, .actions { display: none; }
    .card, .metric { box-shadow: none; border-color: #CCC; }
}

/* =============================================================================
   ÉCRAN SCANNER — réception, gradage, regradage.
   Conçu pour l'usage intensif : cibles larges, retour visuel immédiat,
   aucune information superflue entre deux scans.
   ========================================================================== */

.scanner { display: flex; flex-direction: column; gap: 8px; }

/* ---- En-tête : identité de la réception + compteurs ---- */
.scanhead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 9px 13px;
    flex-wrap: wrap;
}
.scanhead__meta h2 { margin: 0; }
.scanhead__meta p { margin: 0; }
.scanhead__counters { display: flex; gap: 6px; flex-wrap: wrap; }

.tally {
    min-width: 78px;
    padding: 5px 10px;
    border-radius: 8px;
    background: var(--card-2);
    border: 1px solid var(--line);
    text-align: center;
}
.tally--go   { background: var(--signal-bg); border-color: #C4E38C; }
.tally--warn { background: var(--wait-bg);   border-color: #EFD4A0; }
.tally__value {
    display: block;
    font-size: 20px;
    font-weight: 800;
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
}
.tally__label {
    display: block;
    font-size: 8px;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--text-dim);
    margin-top: 1px;
}

/* ---- Barre de scan : l'élément le plus important de l'écran ---- */
.scanbar {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 13px;
    border-radius: 10px;
    background: linear-gradient(135deg, #102534 0%, #0A1620 100%);
    box-shadow: 0 10px 26px rgba(12, 25, 34, 0.2);
    position: relative;
    overflow: hidden;
}
.scanbar::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 3px;
    background: var(--brand);
}
.scanbar__label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: #6E8D9D;
    white-space: nowrap;
}
.scanbar__input {
    flex: 1;
    min-width: 0;
    min-height: 42px;
    padding: 8px 13px;
    border-radius: 7px;
    border: 1px solid rgba(255,255,255,.16);
    background: rgba(255,255,255,.06);
    color: #FFF;
    font-family: var(--mono);
    font-size: 19px;
    font-weight: 600;
    letter-spacing: 0.02em;
}
.scanbar__input::placeholder { color: #5E7C8C; font-size: 15px; letter-spacing: 0.04em; font-family: var(--font); }
.scanbar__input:focus {
    outline: none;
    border-color: #8FD400;
    box-shadow: 0 0 0 3px rgba(143, 212, 0, 0.25);
}

/* ---- Bandeau d'état : lisible à un mètre ---- */
.scanstrip {
    display: flex;
    align-items: baseline;
    gap: 12px;
    padding: 7px 13px;
    border-radius: 8px;
    border: 1px solid var(--line);
    background: var(--card);
    min-height: 36px;
}
.scanstrip__title {
    font-size: 15px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    white-space: nowrap;
}
.scanstrip__detail { color: var(--text-soft); font-size: 13px; }

.scanstrip--idle .scanstrip__title { color: var(--text-dim); }
.scanstrip--busy { background: var(--info-bg); border-color: #A9DAE7; }
.scanstrip--busy .scanstrip__title { color: var(--info); }
.scanstrip--go   { background: var(--signal-bg); border-color: #7CB518; }
.scanstrip--go   .scanstrip__title { color: var(--signal); }
.scanstrip--warn { background: var(--wait-bg); border-color: #D89216; }
.scanstrip--warn .scanstrip__title { color: var(--wait); }
.scanstrip--stop { background: var(--alert-bg); border-color: var(--alert); }
.scanstrip--stop .scanstrip__title { color: var(--alert); }

/* ---- Les deux colonnes ---- */
.scancols { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; align-items: start; }
.scancol { display: flex; flex-direction: column; max-height: 68vh; }

.scanlist {
    list-style: none;
    margin: 0;
    padding: 0;
    overflow-y: auto;
    flex: 1;
}

/* Les listes du poste atelier : une hauteur d'écran maîtrisée, et TOUS
   les appareils dedans — la liste se déroule, la page ne s'étire pas. */
.scanlist--scroll {
    max-height: 58vh;
    overflow-y: auto;
    scrollbar-gutter: stable;
    padding-right: 4px;
}
.scanlist__item {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 4px 11px;
    border-bottom: 1px solid var(--line-soft);
    font-size: 13px;
}
.scanlist__item:last-child { border-bottom: 0; }
.scanlist__meta { color: var(--text-dim); font-size: 12px; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.scanlist__time { color: var(--text-dim); font-size: 12px; font-variant-numeric: tabular-nums; }

.scanlist__item--done { background: rgba(143, 212, 0, 0.07); cursor: pointer; }
.scanlist__item--done:hover { background: rgba(143, 212, 0, 0.14); }
.scanlist__item--extra { background: rgba(255, 176, 32, 0.10); }
.scanlist__item--extra:hover { background: rgba(255, 176, 32, 0.18); }

.scanlist__check {
    flex: 0 0 17px;
    width: 17px; height: 17px;
    border-radius: 5px;
    display: flex; align-items: center; justify-content: center;
    background: var(--brand);
    color: #05161D;
    font-size: 13px;
    font-weight: 800;
}
.scanlist__empty { padding: 22px 14px; text-align: center; color: var(--text-dim); margin: 0; }

/* ---- IMEI non prévu : décision bloquante, volontairement ---- */
.modal {
    position: fixed;
    inset: 0;
    /* Au-dessus de tout : la barre de recherche montait à 200 et découpait
       le voile en biais, ce qui donnait un écran à moitié assombri. */
    z-index: 950;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    /* Aucun voile : la fenêtre se distingue par son ombre portée, et
       assombrir l'écran derrière donnait l'impression d'un défaut. */
    background: transparent;
}
.modal[hidden] { display: none; }
.modal__box {
    width: 100%;
    max-width: 420px;
    background: var(--card);
    border-radius: 12px;
    padding: 22px;
    text-align: center;
    box-shadow: 0 26px 70px rgba(7, 14, 19, 0.45);
    border-top: 4px solid #D89216;

    /* Une fenêtre ne dépasse jamais l'écran : sans borne, une fiche longue
       s'étirait au-delà de la page et ses boutons devenaient inatteignables.
       Le contenu défile à l'intérieur, la boîte garde sa forme. */
    max-height: calc(100vh - 48px);
    display: flex;
    flex-direction: column;

    /* La boîte défile d'elle-même par défaut. Certaines fenêtres n'ont pas
       de zone dédiée — l'import, la déclaration de pièces — et « hidden »
       coupait leur contenu au lieu de le laisser atteindre. */
    overflow-y: auto;
}

/* Quand une zone de contenu existe, c'est elle qui défile : l'en-tête et
   les boutons restent alors en place. */
.modal__box:has(> .modal__content) { overflow: hidden; }
.modal__box > .modal__content { min-height: 0; overflow-y: auto; }
.modal__box .actions { justify-content: center; margin: 22px 0 12px; }
.modal__box .actions .btn { flex: 1; }
.modal__imei { font-size: 19px; margin: 12px 0 8px; display: inline-block; }

@media (max-width: 1000px) {
    .scancols { grid-template-columns: 1fr; }
    .scancol { max-height: 46vh; }
    .scanhead { flex-direction: column; align-items: stretch; }
    .scanhead__counters { justify-content: space-between; }
    .tally { flex: 1; min-width: 0; }
    .scanbar { flex-wrap: wrap; }
    .scanbar__label { width: 100%; }
    .scanbar__input { font-size: 19px; }
}

/* ---- Cadence : file d'attente, ligne en cours d'envoi, retour sonore ---- */
.soundtoggle {
    border: 1px solid rgba(255,255,255,.18);
    background: rgba(255,255,255,.06);
    color: #B6C9D4;
    border-radius: 7px;
    padding: 6px 11px;
    font: inherit;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    min-height: 32px;
}
.soundtoggle:hover { background: rgba(255,255,255,.12); color: #FFF; }
.soundtoggle.is-off { color: #7C99A8; border-color: rgba(255,255,255,.10); opacity: .75; }

.queuebadge {
    align-self: flex-start;
    margin-top: -8px;
    padding: 4px 12px;
    border-radius: 999px;
    background: var(--info-bg);
    border: 1px solid #A9DAE7;
    color: var(--info);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
}
.queuebadge[hidden] { display: none; }

/* Ligne affichée avant confirmation du serveur */
.scanlist__item--pending { opacity: .55; }
.scanlist__item--pending .scanlist__check {
    background: var(--card-2);
    color: var(--text-dim);
    border: 1px dashed var(--line);
}
.scanlist__item--leaving { opacity: .3; }

.scanlist__more {
    padding: 7px 11px;
    border-top: 1px solid var(--line-soft);
    background: var(--card-2);
    color: var(--text-dim);
    font-size: 11px;
}

/* Le défilement des colonnes ne doit jamais accrocher */
.scanlist { overscroll-behavior: contain; will-change: transform; }


/* =============================================================================
   DENSITÉ — un outil d'entrepôt affiche le maximum d'informations utiles
   sans défilement. Les marges verticales des blocs de texte sont resserrées.
   ========================================================================== */

p { margin: 0 0 8px; }
p:last-child { margin-bottom: 0; }
ul, ol { margin: 0 0 8px; padding-left: 20px; }
ul li, ol li { margin-bottom: 2px; }

/* Formulaires côte à côte plutôt qu'empilés dès que la place le permet */
.card__body .grid--2 > .field,
.card__body .grid--3 > .field { margin-bottom: 0; }

/* Dernier champ d'une carte : pas de marge inutile en bas */
.card__body .field:last-of-type { margin-bottom: 8px; }

/* Tableaux : les cellules numériques et de statut restent compactes */
.table td .tag { vertical-align: middle; }
.table td.small, .table th.small { font-size: 11.5px; }

/* Cartes enchaînées : espacement réduit */
.content > .card + .card,
.content > .grid + .card,
.content > .card + .grid { margin-top: 10px; }

/* Barre de filtres : tout sur une ligne, sans carte séparée trop haute */
.filters { padding: 9px 13px; }
.filters .grid { gap: 8px; }
.filters .actions { margin-top: 8px; }

/* Fenêtre modale contenant un formulaire : alignement à gauche, plus large */
.modal__box--form { max-width: 480px; text-align: left; }
.modal__box--form h2 { margin: 0; }
.modal__box--form .actions { justify-content: flex-start; margin: 12px 0 0; }
.modal__box--form .actions .btn { flex: 0 0 auto; }

/* ---- Zone de dépôt de fichier ---- */
.dropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 22px 16px;
    border: 2px dashed var(--line);
    border-radius: 10px;
    background: var(--card-2);
    cursor: pointer;
    text-align: center;
    transition: border-color .15s ease, background .15s ease;
}
.dropzone:hover { border-color: var(--cyan); background: #F0F8FA; }
.dropzone.is-over {
    border-color: var(--lime-vivid);
    background: var(--signal-bg);
    border-style: solid;
}
.dropzone.is-filled { border-style: solid; border-color: var(--lime); background: var(--signal-bg); }

.dropzone__icon svg { width: 26px; height: 26px; color: var(--cyan); }
.dropzone.is-filled .dropzone__icon svg { color: var(--signal); }

.dropzone__text { display: flex; flex-direction: column; gap: 2px; }
.dropzone__text strong { font-size: 13.5px; overflow-wrap: anywhere; }
.dropzone__text span { font-size: 12px; color: var(--text-dim); }
.dropzone__formats { font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--text-dim); }

/* L'input reste accessible au clavier mais invisible : le label porte l'apparence */
.dropzone input[type="file"] {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0);
    white-space: nowrap; border: 0;
}
.dropzone:focus-within { outline: 3px solid var(--cyan-vivid); outline-offset: 2px; }

/* Ligne mise en avant dans un tableau explicatif */
.table tr.row--highlight td { background: var(--wait-bg); }


/* Saisie directement dans un tableau : le champ ne doit pas gonfler la ligne */
.table .input, .table select {
    min-height: 26px;
    padding: 3px 7px;
    font-size: 12px;
    border-radius: 4px;
}
.table td .field { margin: 0; }

/* ---- Champ avec bouton accolé ---- */
.input-group { display: flex; gap: 6px; }
.input-group .input { flex: 1; min-width: 0; }
.input-group .btn { flex: 0 0 auto; white-space: nowrap; }

/* ---- Résultat d'une recherche d'entreprise ---- */
.lookup-result {
    margin: 9px 0 0;
    padding: 8px 11px;
    border-radius: 6px;
    border-left: 3px solid var(--line);
    background: var(--card-2);
    font-size: 12.5px;
    line-height: 1.45;
}
.lookup-result[hidden] { display: none; }
.lookup-result--ok    { background: var(--signal-bg); border-color: var(--signal); color: #35590A; }
.lookup-result--warn  { background: var(--wait-bg);   border-color: var(--wait);   color: #6E4707; }
.lookup-result--error { background: var(--alert-bg);  border-color: var(--alert);  color: #8C1E15; }
.lookup-result--info  { background: var(--info-bg);   border-color: var(--info);   color: #0A5568; }

/* Bouton discret intégré à une phrase */
.linklike {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    font-weight: 700;
    color: inherit;
    text-decoration: underline;
    cursor: pointer;
}


/* =============================================================================
   ALIGNEMENT
   Les valeurs sont centrées par défaut. Seuls les textes longs — phrases,
   descriptions, motifs — restent alignés à gauche : centrer un paragraphe
   le rend illisible.
   ========================================================================== */

.table td.al-left, .table th.al-left { text-align: left; }
.table td.al-right, .table th.al-right { text-align: right; }

/* Cellules contenant une phrase plutôt qu'une valeur */
.table td[style*="max-width"] { text-align: left; }

/* Compteurs et pastilles : centrage complet */
.metric { text-align: center; }
.metric::before { width: 100%; height: 3px; }

/* Champs de saisie dans un tableau : le texte suit l'alignement de la colonne */
.table .input { text-align: center; }
.table .input--left { text-align: left; }

/* Les listes de scan gardent leur lecture naturelle de gauche à droite */
.scanlist__item { text-align: left; }

/* ---- Modèle de fichier attendu ---- */
.template {
    border: 1px solid var(--line);
    border-radius: 7px;
    background: var(--card-2);
    padding: 10px 12px;
    margin-bottom: 11px;
    text-align: left;
}
.template__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 8px;
    font-size: 12px;
}
.template__columns { display: flex; flex-wrap: wrap; gap: 4px; }
.template__column {
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 600;
    padding: 3px 7px;
    border-radius: 4px;
    background: var(--deep);
    color: #B6C9D4;
    white-space: nowrap;
}
.template__hint { font-size: 11.5px; color: var(--text-dim); margin: 8px 0 0; line-height: 1.4; }

.template__grid { border-collapse: collapse; font-family: var(--mono); font-size: 11.5px; }
.template__grid th {
    background: var(--deep);
    color: #B6C9D4;
    font-family: var(--font);
    font-size: 10px;
    letter-spacing: .1em;
    text-transform: uppercase;
    padding: 3px 12px;
    border: 1px solid var(--line);
}
.template__grid td {
    padding: 3px 12px;
    border: 1px solid var(--line);
    background: var(--card);
}

/* ---- Panneau du dernier scan : saisie immédiate sans quitter la rafale ---- */
.lastscan {
    border: 1px solid var(--line);
    border-left: 4px solid var(--cyan-vivid);
    border-radius: 8px;
    background: var(--card);
    padding: 9px 13px;
    box-shadow: var(--shadow);
}
.lastscan[hidden] { display: none; }

.lastscan__identity { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.lastscan__label {
    font-size: 9px; font-weight: 700; letter-spacing: .16em;
    text-transform: uppercase; color: var(--text-dim);
}
.lastscan__imei { font-size: 15px; }
.lastscan__tags { display: flex; gap: 4px; flex-wrap: wrap; }

.lastscan__fields { display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap; }
.lastscan__field { display: flex; flex-direction: column; gap: 3px; flex: 1 1 140px; min-width: 0; }
.lastscan__field span {
    font-size: 9px; font-weight: 700; letter-spacing: .12em;
    text-transform: uppercase; color: var(--text-soft);
}
.lastscan__hint { font-size: 11.5px; color: var(--text-dim); margin: 7px 0 0; }

@media (max-width: 1000px) {
    .lastscan__fields { flex-direction: column; align-items: stretch; }
    .lastscan__fields .btn { width: 100%; }
}

/* ---- Recherche globale, présente sur tous les écrans ---- */
.topsearch { display: flex; gap: 6px; align-items: center; flex: 0 1 340px; }
.topsearch__input { min-height: 30px; font-size: 13px; letter-spacing: .02em; }

@media (max-width: 900px) {
    .topbar { flex-wrap: wrap; }
    .topsearch { flex: 1 1 100%; }
}

/* ---- Compteurs de stock cliquables ---- */
.stockgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); gap: 8px; }

.stockcard {
    display: block;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: 7px;
    padding: 10px 8px;
    text-align: center;
    text-decoration: none;
    color: var(--text);
    box-shadow: var(--shadow);
    transition: border-color .12s ease, transform .08s ease;
}
.stockcard:hover { border-color: var(--cyan); transform: translateY(-1px); text-decoration: none; color: var(--text); }
.stockcard--active { border-color: var(--cyan-vivid); box-shadow: 0 0 0 2px rgba(22,181,208,.18); }
.stockcard--total { background: var(--deep); color: #FFF; border-color: var(--deep); }
.stockcard--total .stockcard__label { color: #8FB0C0; }

.stockcard__value { display: block; font-size: 21px; font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1.1; }
.stockcard__label {
    display: block; margin-top: 3px;
    font-size: 9px; font-weight: 700; letter-spacing: .12em;
    text-transform: uppercase; color: var(--text-dim);
}

/* ---- Fiche appareil ---- */
.sheet__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.sheet__imei { font-size: 20px; }

.timeline { list-style: none; margin: 0; padding: 0; }
.timeline__item {
    display: grid;
    grid-template-columns: 108px 1fr;
    gap: 10px;
    padding: 6px 13px;
    border-bottom: 1px solid var(--line-soft);
    text-align: left;
}
.timeline__item:last-child { border-bottom: 0; }
.timeline__date { font-size: 11.5px; color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
.timeline__label { font-size: 12.5px; }
.timeline__details { font-size: 11.5px; color: var(--text-dim); margin-top: 2px; }
.timeline__author { font-size: 11px; color: var(--text-dim); }

@media (max-width: 700px) {
    .timeline__item { grid-template-columns: 1fr; gap: 2px; }
}

/* ---- Choix du technicien destinataire ---- */
/* Choix du technicien : la charge se lit d'un coup d'œil, c'est elle qui
   décide à qui confier le lot suivant. */
.techpick {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 9px;
}
.techpick__cell { position: relative; display: flex; }

.techpick__item {
    display: flex;
    flex-direction: column;
    gap: 7px;
    flex: 1;
    min-width: 0;
    padding: 12px 58px 12px 14px;
    border: 1px solid var(--line);
    border-radius: 7px;
    background: var(--card);
    font: inherit;
    color: var(--text);
    cursor: pointer;
    text-align: left;
    transition: border-color .12s ease, background .12s ease;
}
.techpick__item:hover { border-color: var(--cyan); }
.techpick__item.is-selected {
    border-color: var(--signal);
    background: var(--signal-bg);
    box-shadow: 0 0 0 2px rgba(143,212,0,.18);
}

.techpick__name {
    font-size: 14px;
    font-weight: 700;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.techpick__load {
    display: flex;
    gap: 14px;
    font-size: 11px;
    color: var(--text-dim);
}
.techpick__stat {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
}
.techpick__stat strong {
    font-size: 19px;
    font-weight: 700;
    color: var(--text-soft);
    font-variant-numeric: tabular-nums;
}
.techpick__stat--wait strong { color: var(--wait); }
.techpick__stat--go strong { color: var(--info); }
.techpick__item.is-selected .techpick__load { color: #4A7A0C; }

/* Accès au détail : distinct du choix, pour que le clic reste prévisible */
.techpick__see {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 1;
    padding: 3px 9px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--card-2);
    color: var(--text-dim);
    font-size: 11px;
    font-weight: 600;
    text-decoration: none;
}
.techpick__see:hover {
    border-color: var(--cyan);
    background: var(--info-bg);
    color: var(--cyan);
}


/* =============================================================================
   BACS DE TEST
   Deux colonnes : la liste des bacs à gauche, le poste de travail à droite.
   ========================================================================== */

.binboard {
    display: grid;
    /* La liste des bacs occupe désormais près de la moitié de l'écran :
       c'est le point de départ du travail, pas une annexe. */
    grid-template-columns: minmax(0, 1fr) minmax(420px, 0.85fr);
    gap: 8px;
    align-items: start;
}
.binboard__side { display: flex; flex-direction: column; gap: 8px; position: sticky; top: 6px; }
.binboard__main { min-width: 0; display: flex; flex-direction: column; gap: 8px; }

.binboard__empty { text-align: center; padding: 44px 20px; }
.binboard__empty svg { width: 44px; height: 44px; color: var(--text-dim); margin-bottom: 10px; }
.binboard__empty h2 { margin-bottom: 5px; }
.binboard__empty p { max-width: 380px; margin: 0 auto; }

/* ---- Action principale du poste de travail ---- */
.binaction { display: flex; justify-content: flex-end; align-items: center; gap: 11px; flex-wrap: wrap; }
.binaction .btn { min-width: 220px; justify-content: center; }

/* =============================================================================
   SAISIE DES PANNES
   Regroupées par famille, avec une icône par panne : sur deux cents appareils,
   l'œil reconnaît un pictogramme plus vite qu'il ne lit un libellé.
   ========================================================================== */

.faultpanel {
    border: 1px solid var(--line);
    border-left: 4px solid var(--wait);
    border-radius: 9px;
    background: var(--card);
    padding: 11px 14px;
    box-shadow: 0 6px 22px rgba(11,42,58,.10);
}
.faultpanel[hidden] { display: none; }

.faultpanel__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    padding-bottom: 9px;
    border-bottom: 1px solid var(--line-soft);
}
.faultpanel__identity { display: flex; flex-direction: column; gap: 1px; }
.faultpanel__announced {
    margin: 8px 0 0;
    padding: 6px 10px;
    border-radius: 6px;
    background: var(--info-bg);
    color: #0A5568;
    font-size: 11.5px;
}

.faultgroups {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
    gap: 11px;
    margin-top: 10px;

    /* Hauteur calculée sur l'écran réel, et non une fraction fixe : sur un
       portable de 768 px de haut, 40 % ne laissaient voir que trois pannes,
       et il fallait faire défiler pour trouver la bonne. On garde de quoi
       voir la barre de scan au-dessus, et on donne le reste aux pannes.
       Le minimum protège les très petits écrans du défilement dans le
       défilement, où l'on ne sait plus ce qu'on déplace. */
    max-height: max(280px, calc(100vh - 420px));
    overflow-y: auto;
    padding-right: 3px;
}

/* Écran étroit : des colonnes plus fines valent mieux qu'un défilement.
   Une panne tient sur une ligne courte, quatre colonnes de 150 px passent
   là où deux de 230 px obligeaient à dérouler. */
@media (max-width: 1200px) {
    .faultgroups { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
    .faultchip__label { font-size: 12.5px; }
}

/* Écran bas : la hauteur prime sur la marge. */
@media (max-height: 800px) {
    .faultgroups { max-height: calc(100vh - 340px); }
}

.faultgroup__title {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 5px;
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--text-dim);
}
.faultgroup__icon { width: 14px; height: 14px; color: var(--cyan); flex: 0 0 14px; }
.faultgroup__items { display: flex; flex-direction: column; gap: 3px; }

.faultchip {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 9px;
    border: 1px solid var(--line);
    border-radius: 7px;
    background: var(--card);
    cursor: pointer;
    font-size: 12.5px;
    line-height: 1.2;
    transition: border-color .12s ease, background .12s ease, transform .06s ease;
}
.faultchip:hover { border-color: var(--wait); background: var(--card-2); }
.faultchip:active { transform: scale(.985); }

.faultchip input {
    position: absolute;
    opacity: 0;
    width: 0; height: 0;
    pointer-events: none;
}

.faultchip__icon { width: 18px; height: 18px; flex: 0 0 18px; color: var(--text-soft); }
.faultchip__label { flex: 1; min-width: 0; }

.faultchip:has(input:checked) {
    border-color: var(--wait);
    background: var(--wait-bg);
    font-weight: 700;
    box-shadow: inset 0 0 0 1px var(--wait);
}
.faultchip:has(input:checked) .faultchip__icon { color: #B87400; }
.faultchip:has(input:focus-visible) { outline: 3px solid var(--cyan-vivid); outline-offset: 2px; }

.faultpanel__foot {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-top: 10px;
    padding-top: 9px;
    border-top: 1px solid var(--line-soft);
}
.faultpanel__foot .input { flex: 1; min-width: 0; }

.btn__icon { width: 15px; height: 15px; flex: 0 0 15px; }

@media (max-width: 1200px) {
    .binboard { grid-template-columns: 1fr; }
    .binboard__side { position: static; }
    .binlist { max-height: 240px; }
}
@media (max-width: 700px) {
    .faultpanel__foot { flex-direction: column; align-items: stretch; }
    .binaction .btn { width: 100%; }
}

/* ---- Ouverture d'un bac : le numéro se tape, rien n'est pré-créé ---- */
.binstart { display: flex; gap: 8px; align-items: stretch; max-width: 460px; }
.binstart__input {
    flex: 1;
    min-height: 40px;
    font-family: var(--mono);
    font-size: 17px;
    font-weight: 700;
    letter-spacing: .04em;
    text-align: center;
}

/* ---- Contrôle des caractéristiques pendant le dépouillement ---- */
.faultcheck {
    margin-top: 9px;
    padding: 9px 11px;
    border: 1px solid var(--line);
    border-radius: 7px;
    background: var(--card-2);
}
.faultcheck__title {
    display: block;
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-bottom: 6px;
}
.faultcheck__fields { display: flex; gap: 8px; flex-wrap: wrap; }
.faultcheck__fields .lastscan__field { flex: 1 1 140px; }

/* ---- Colonne des bacs : numéro, testeuse, date, quantité ---- */
/* ---- Tableau des bacs ----
   La colonne est étroite : chaque cellule doit tenir sans provoquer de
   défilement horizontal, qui masquerait les boutons d'action. */
.bintable { font-size: 12.5px; table-layout: fixed; width: 100%; }
.bintable th { font-size: 8.5px; padding: 4px 4px; }
.bintable td { padding: 4px 4px; }

.bintable th:nth-child(1), .bintable td:nth-child(1) { width: 96px; }
.bintable th:nth-child(3), .bintable td:nth-child(3) { width: 52px; }
.bintable th:nth-child(4), .bintable td:nth-child(4) { width: 168px; }

.bintable td:nth-child(2) { overflow: hidden; text-overflow: ellipsis; }
.bintable .chipbtn { padding: 2px 8px; font-size: 10.5px; }
.bintable .iconbtn { width: 22px; height: 22px; }
.bintable .iconbtn svg { width: 12px; height: 12px; }

.bintable__row { border-left: 3px solid transparent; cursor: default; }
.bintable__row[data-href] { cursor: pointer; }
.bintable__row[data-href]:hover { background: var(--card-2); }
.bintable__row.is-current { background: var(--signal-bg); border-left-color: var(--signal); }
.bintable__row.bin--filling   { border-left-color: var(--cyan); }
.bintable__row.bin--intest    { border-left-color: var(--wait); }
.bintable__row.bin--returning { border-left-color: var(--info); }



.binlist__tool {
    width: 23px; height: 23px;
    display: inline-flex; align-items: center; justify-content: center;
    border: 0; border-radius: 5px;
    background: none;
    color: var(--text-dim);
    cursor: pointer;
    transition: opacity .12s ease, background .12s ease, color .12s ease;
}
.binlist__tool:hover { background: var(--line-soft); color: var(--text); }
.binlist__tool--danger:hover { background: var(--alert-bg); color: var(--alert); }
.binlist__tool svg { width: 13px; height: 13px; }

/* Dans un bac : plein écran, la liste des autres bacs disparaît */
.binboard--focus { grid-template-columns: minmax(0, 1fr); }

.binback {
    display: flex;
    align-items: center;
    gap: 11px;
    flex-wrap: wrap;
}
.binback__title { font-size: 13px; color: var(--text-soft); }
.binback__title strong { color: var(--text); letter-spacing: .03em; }

/* =============================================================================
   BOUTONS D'ACTION SUR UNE LIGNE
   Deux formes seulement : une icône carrée, ou une pastille avec libellé.
   Toutes deux suivent le thème plutôt que d'inventer leur propre apparence.
   ========================================================================== */

.iconbtn {
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--card);
    color: var(--text-soft);
    cursor: pointer;
    padding: 0;
    transition: border-color .12s ease, background .12s ease, color .12s ease;
}
.iconbtn + .iconbtn, form + form .iconbtn { margin-left: 3px; }
.iconbtn svg { width: 14px; height: 14px; }
.iconbtn:hover { border-color: var(--cyan); background: var(--card-2); color: var(--text); }
.iconbtn:focus-visible { outline: 3px solid var(--cyan-vivid); outline-offset: 2px; }

.iconbtn--danger:hover { border-color: var(--alert); background: var(--alert-bg); color: var(--alert); }

.chipbtn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--card);
    color: var(--text-soft);
    font: inherit;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition: border-color .12s ease, background .12s ease, color .12s ease;
}
.chipbtn:hover { border-color: var(--cyan); color: var(--text); }
.chipbtn--danger:hover { border-color: var(--alert); background: var(--alert-bg); color: var(--alert); }
.chipbtn:focus-visible { outline: 3px solid var(--cyan-vivid); outline-offset: 2px; }

/* Les outils restent discrets tant que la ligne n'est pas survolée */
.bintable__tools .iconbtn { opacity: 0; }
.bintable__row:hover .iconbtn,
.bintable__tools .iconbtn:focus-visible { opacity: 1; }

/* ---- Panne affichée avec son icône ---- */
.faultline { display: inline-flex; align-items: center; gap: 7px; text-decoration: none; color: var(--text); }
.faultline:hover { text-decoration: none; color: var(--cyan-vivid); }
.faultline__icon { width: 17px; height: 17px; flex: 0 0 17px; color: var(--text-soft); }
.faultline:hover .faultline__icon { color: var(--cyan-vivid); }

.card__head h2 .faultgroup__icon,
.card__head h2 .faultline__icon { vertical-align: -3px; margin-right: 5px; }

textarea.input { min-height: 78px; resize: vertical; font-family: inherit; line-height: 1.45; }

/* ---- IMEI modifiable dans le panneau de contrôle ---- */
.faultpanel__imei {
    min-height: 32px;
    padding: 3px 9px;
    font-size: 17px;
    font-weight: 700;
    letter-spacing: .02em;
    border-color: transparent;
    background: transparent;
    width: 100%;
    max-width: 260px;
}
.faultpanel__imei:hover { border-color: var(--line); background: var(--card-2); }
.faultpanel__imei:focus { border-color: var(--cyan-vivid); background: #FFF; }
.faultpanel__imei.is-changed {
    border-color: var(--wait);
    background: var(--wait-bg);
    color: #6E4707;
}

.faultpanel__rename {
    margin-top: 9px;
    padding: 9px 11px;
    border: 1px solid var(--wait);
    border-radius: 7px;
    background: var(--wait-bg);
}
.faultpanel__rename .template__hint { color: #6E4707; }

/* ---- Actions d'une ligne de bac ---- */
.rowactions { display: inline-flex; align-items: center; gap: 3px; justify-content: flex-end; }
.rowactions .iconbtn { opacity: .45; }
.bintable__row:hover .rowactions .iconbtn,
.rowactions .iconbtn:focus-visible { opacity: 1; }

.chipbtn--go {
    border-color: var(--signal);
    background: var(--signal-bg);
    color: #35590A;
    text-decoration: none;
}
.chipbtn--go:hover {
    border-color: var(--lime-vivid);
    background: #E8F6CE;
    color: #35590A;
    text-decoration: none;
}

.binrow__date { display: block; font-size: 10px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.bintable__tools { width: auto; white-space: nowrap; }

/* ---- Liste condensée des pannes ---- */
.faultlist {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(196px, 1fr));
    gap: 3px;
    padding: 9px 11px 11px;
}

.faultitem {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 9px;
    border: 1px solid var(--line);
    border-radius: 7px;
    background: var(--card);
    text-decoration: none;
    color: var(--text);
    font-size: 12.5px;
    transition: border-color .12s ease, background .12s ease;
}
.faultitem:hover { border-color: var(--cyan); background: var(--card-2); text-decoration: none; color: var(--text); }
.faultitem__icon { width: 17px; height: 17px; flex: 0 0 17px; color: var(--text-soft); }
.faultitem:hover .faultitem__icon { color: var(--cyan-vivid); }
.faultitem__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.faultitem__parts {
    font-size: 10px; font-weight: 700;
    background: var(--signal-bg); color: #35590A;
    border-radius: 999px; padding: 1px 7px;
}
.faultitem__price { font-size: 10.5px; color: var(--text-dim); font-variant-numeric: tabular-nums; }

/* ---- Sélecteur d'icône ---- */
.namepick { display: flex; gap: 7px; align-items: stretch; }
.namepick > .input { flex: 1; min-width: 0; }

.iconpick { display: flex; align-items: stretch; gap: 5px; flex: 0 0 auto; }
.iconpick__preview {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--card-2);
    color: var(--cyan-vivid);
}
.iconpick__svg { width: 18px; height: 18px; }
.iconpick select { width: 132px; }

/* Un bouton d'icône désactivé ne doit pas donner le change */
.iconbtn:disabled { opacity: .3; cursor: default; }
.iconbtn:disabled:hover { border-color: var(--line); background: var(--card); color: var(--text-soft); }

/* =============================================================================
   PROGRESSION D'UNE OPÉRATION LONGUE
   Importer vingt mille pièces prend des minutes : sans retour visible,
   l'opérateur croit l'application bloquée et relance tout.
   ========================================================================== */

.progress {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: rgba(11, 42, 58, .55);
    backdrop-filter: blur(2px);
}
.progress[hidden] { display: none; }

.progress__box {
    width: 100%;
    max-width: 460px;
    background: var(--card);
    border-radius: 12px;
    padding: 22px 24px;
    box-shadow: 0 18px 50px rgba(11, 42, 58, .3);
    text-align: center;
}

.progress__title { margin: 0 0 5px; font-size: 15px; }
.progress__label { margin: 0 0 14px; font-size: 12.5px; color: var(--text-soft); min-height: 18px; }

.progress__track {
    height: 8px;
    border-radius: 999px;
    background: var(--line-soft);
    overflow: hidden;
}
.progress__bar {
    height: 100%;
    width: 0;
    border-radius: 999px;
    background: var(--brand);
    transition: width .35s ease;
}

/* Tant que le total est inconnu, la barre balaie au lieu de mentir sur l'avancement */
.progress__bar--unknown {
    width: 35% !important;
    animation: progress-sweep 1.25s ease-in-out infinite;
}
@keyframes progress-sweep {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(320%); }
}

.progress__meta {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    margin-top: 9px;
    font-size: 11.5px;
    color: var(--text-dim);
    font-variant-numeric: tabular-nums;
}

.progress__warning {
    margin: 14px 0 0;
    padding-top: 11px;
    border-top: 1px solid var(--line-soft);
    font-size: 11px;
    color: var(--text-dim);
}

/* Une action irréversible se signale avant d'être cliquée */
.card--danger { border-color: var(--alert); }
.card--danger .card__head { background: var(--alert-bg); border-bottom-color: var(--alert); }
.card--danger .card__head h2 { color: #8C1E15; }

/* ---- Choix de la marque avant le modèle ---- */
.brandbar { display: flex; flex-wrap: wrap; gap: 5px; }

.brandchip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 13px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--card);
    color: var(--text);
    font-size: 12.5px;
    font-weight: 600;
    text-decoration: none;
    transition: border-color .12s ease, background .12s ease;
}
.brandchip:hover { border-color: var(--cyan); text-decoration: none; color: var(--text); }
.brandchip.is-selected {
    border-color: var(--signal);
    background: var(--signal-bg);
    color: #35590A;
}
.brandchip__count {
    font-size: 10px;
    font-weight: 800;
    background: var(--card-2);
    border-radius: 999px;
    padding: 1px 6px;
    color: var(--text-dim);
}
.brandchip.is-selected .brandchip__count { background: #FFF; color: #35590A; }

/* ---- Ajout rapide d'une référence ---- */
.quickadd { border: 1px solid var(--line); border-radius: 7px; background: var(--card-2); }
.quickadd > summary {
    padding: 8px 12px;
    cursor: pointer;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text-soft);
    list-style: none;
}
.quickadd > summary::-webkit-details-marker { display: none; }
.quickadd > summary::before { content: "+ "; font-weight: 800; color: var(--cyan-vivid); }
.quickadd[open] > summary { border-bottom: 1px solid var(--line); color: var(--text); }
.quickadd[open] > summary::before { content: "− "; }
.quickadd > form { padding: 11px 12px 13px; }

/* ---- Sous-pannes dans l'écran de test ---- */
.faultblock { display: flex; flex-direction: column; gap: 3px; }

.faultchip__more {
    font-size: 9.5px;
    font-weight: 800;
    background: var(--card-2);
    color: var(--text-dim);
    border-radius: 999px;
    padding: 1px 6px;
}
.faultchip:has(input:checked) .faultchip__more { background: #FFF; color: #B87400; }

.faultchildren {
    display: flex;
    flex-direction: column;
    gap: 3px;
    margin: 1px 0 3px 16px;
    padding-left: 9px;
    border-left: 2px solid var(--wait);
}
.faultchildren[hidden] { display: none; }

.faultchip--child { padding: 4px 9px; font-size: 12px; background: var(--card-2); }
.faultchip--child::before {
    content: "";
    width: 5px; height: 5px;
    border-radius: 50%;
    background: var(--text-dim);
    flex: 0 0 5px;
}
.faultchip--child:has(input:checked)::before { background: #B87400; }

/* Repère du nombre de sous-pannes dans le référentiel */
.faultitem__children {
    font-size: 9.5px;
    font-weight: 700;
    color: var(--text-dim);
    background: var(--card-2);
    border-radius: 999px;
    padding: 1px 7px;
    white-space: nowrap;
}

/* Couleur constatée en stock mais absente du référentiel */
.brandchip__flag {
    font-size: 8.5px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: #B87400;
    background: var(--wait-bg);
    border-radius: 999px;
    padding: 1px 6px;
}


/* Ligne de tableau ouvrant une fiche */
.row--clickable { cursor: pointer; }
.row--clickable:hover { background: var(--card-2); }
.row--clickable .iconbtn { opacity: 0; }
.row--clickable:hover .iconbtn,
.row--clickable .iconbtn:focus-visible { opacity: 1; }

/* =============================================================================
   RÉPARTITION PAR GRADE
   Les compteurs servent aussi de filtres : un clic isole la catégorie.
   ========================================================================== */

.gradebar {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 6px;
}

.gradecard {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1px;
    padding: 11px 9px;
    border: 1px solid var(--line);
    border-top: 3px solid var(--line);
    border-radius: 9px;
    background: var(--card);
    text-decoration: none;
    color: var(--text);
    transition: border-color .12s ease, background .12s ease, transform .06s ease;
}
.gradecard:hover { background: var(--card-2); text-decoration: none; color: var(--text); }
.gradecard:active { transform: scale(.99); }
.gradecard.is-selected { background: var(--card-2); box-shadow: inset 0 0 0 1px var(--line); }

.gradecard__value { font-size: 21px; font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1.1; }
.gradecard__label { font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--text-dim); }

.gradecard--none { border-top-color: var(--text-dim); }
.gradecard--a    { border-top-color: var(--signal); }
.gradecard--b    { border-top-color: var(--cyan); }
.gradecard--c    { border-top-color: var(--wait); }

/* Quantités dans le tableau des déclinaisons */
.qty {
    display: inline-block;
    min-width: 26px;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.qty--none { background: var(--line-soft); color: var(--text-soft); }
.qty--a    { background: var(--signal-bg); color: #35590A; }
.qty--b    { background: var(--info-bg);   color: #0A5568; }
.qty--c    { background: var(--wait-bg);   color: #6E4707; }

/* Déclinaison absente du stock : présente au référentiel, sans appareil */
.row--muted td { opacity: .55; }
.row--muted:hover td { opacity: 1; }

/* Tableau resserré, valeurs centrées */
.table--dense td { padding: 3px 6px; }
.table--dense th { padding: 4px 6px; }

/* Bloc signalant un écart à traiter */
.card--warn { border-color: var(--wait); }
.card--warn .card__head { background: var(--wait-bg); border-bottom-color: var(--wait); }
.card--warn .card__head h2 { color: #6E4707; }

/* ---- Barre de filtres compacte ---- */
.filterbar {
    display: flex;
    align-items: flex-end;
    gap: 9px;
    flex-wrap: wrap;
    margin-top: 9px;
    padding-top: 9px;
    border-top: 1px solid var(--line-soft);
}
.filterbar__field { display: flex; flex-direction: column; gap: 2px; }
.filterbar__field > span {
    font-size: 9px;
    font-weight: 800;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--text-dim);
}
.filterbar__field select { min-width: 148px; }
.filterbar__actions { margin-left: auto; display: flex; align-items: center; gap: 7px; }

/* Compteurs de grade resserrés */
.gradebar { grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 5px; }
.gradecard { padding: 7px 8px; border-radius: 7px; }
.gradecard__value { font-size: 17px; }
.gradecard__label { font-size: 9px; }

/* ================================================ Actions au survol d'une ligne

   Une action destructive posée en bout de ligne ne doit pas s'offrir en
   permanence : sur cent lignes, cent boutons rouges attirent l'œil plus que
   le contenu, et le clic part vite. Elle apparaît quand le curseur désigne
   la ligne — le geste dit déjà lequel on vise.

   La règle vaut partout : listes de scan, tableaux, fiches. Une exception
   par écran finirait par se voir, et l'opérateur ne saurait plus si un
   bouton manque ou s'il faut survoler. */

.scanlist__item .chipbtn,
.table tbody tr .chipbtn--danger,
.varlist__item .varlist__remove {
    margin-left: auto;
    opacity: 0;
    transition: opacity .12s;
}

.scanlist__item:hover .chipbtn,
.scanlist__item:focus-within .chipbtn,
.scanlist__item .chipbtn:focus-visible,
.table tbody tr:hover .chipbtn--danger,
.table tbody tr:focus-within .chipbtn--danger,
.table tbody tr .chipbtn--danger:focus-visible,
.varlist__item:hover .varlist__remove,
.varlist__item:focus-within .varlist__remove,
.varlist__item .varlist__remove:focus-visible {
    opacity: 1;
}

/* Au clavier comme au doigt, le survol n'existe pas : les actions restent
   visibles là où le pointeur fin fait défaut. */
@media (hover: none) {
    .scanlist__item .chipbtn,
    .table tbody tr .chipbtn--danger,
    .varlist__item .varlist__remove {
        opacity: 1;
    }
}

/* La ligne visée se distingue : sans repère, on ne sait pas sur laquelle
   le bouton qui vient d'apparaître va agir. */
.scanlist__item:hover { background: var(--card-2); }

/* ---- Bascule entre deux vues d'un même contenu ---- */
.tabs {
    display: inline-flex;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--card-2);
    padding: 2px;
}
.tabs__item {
    padding: 3px 13px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--text-soft);
    text-decoration: none;
    transition: background .12s ease, color .12s ease;
}
.tabs__item:hover { color: var(--text); text-decoration: none; }
.tabs__item.is-selected {
    background: var(--card);
    color: var(--text);
    box-shadow: 0 1px 3px rgba(11,42,58,.12);
}

/* Total en pied de tableau */
.table tfoot td {
    border-top: 2px solid var(--line);
    background: var(--card-2);
    padding: 5px 6px;
}

/* =============================================================================
   LISTE DÉROULANTE CHERCHABLE
   La liste d'origine reste dans la page pour porter la valeur ; seul
   l'affichage change.
   ========================================================================== */

.combo { position: relative; }
.combo__native { position: absolute; opacity: 0; pointer-events: none; width: 0; height: 0; }
.combo__input { width: 100%; }

.combo__list {
    /* Placé par le script dans le corps du document : aucune carte ni tableau
       ne peut le rogner. La position est donc fixée à l'écran.
       Au-dessus des fenêtres (950) : un combo ne s'ouvre que sous le doigt,
       jamais sans raison — à 900, il s'ouvrait DERRIÈRE la fiche panne. */
    position: fixed;
    z-index: 990;
    max-height: 260px;
    overflow-y: auto;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: 8px;
    box-shadow: 0 10px 30px rgba(11, 42, 58, .16);
    padding: 3px;
}
.combo__list[hidden] { display: none; }

.combo__item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 5px 9px;
    border: 0;
    border-radius: 5px;
    background: none;
    font: inherit;
    font-size: 12.5px;
    color: var(--text);
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.combo__item:hover,
.combo__item.is-active { background: var(--card-2); }
.combo__item.is-selected { font-weight: 700; color: var(--cyan-vivid); }

.combo__empty { display: block; padding: 7px 9px; font-size: 12px; color: var(--text-dim); }

/* Choix de pièce directement dans le tableau de correspondance */
.matchform { margin: 0; min-width: 260px; }
.matchform select { width: 100%; }
.matchform .combo { min-width: 260px; }

/* =============================================================================
   RETOUR SUR LA LIGNE TRAITÉE
   Après une association, la page revient à la ligne concernée plutôt qu'en
   haut du tableau, et la signale brièvement.
   ========================================================================== */

.table tr[id] { scroll-margin-top: 90px; }

.table tr.row--flash td {
    background: var(--signal-bg);
    animation: ligne-traitee 2.4s ease-out;
}

@keyframes ligne-traitee {
    0%   { background: var(--lime-vivid); }
    35%  { background: var(--signal-bg); }
    100% { background: var(--signal-bg); }
}

/* Panne qui ouvre ses sous-pannes au lieu d'être cochée */
.faultchip--parent {
    width: 100%;
    text-align: left;
    cursor: pointer;
    font-weight: 600;
}
.faultchip--parent .faultchip__more { margin-left: auto; }
.faultchip--parent.is-open {
    border-color: var(--wait);
    background: var(--wait-bg);
}
.faultchip--parent::after {
    content: "▾";
    font-size: 10px;
    color: var(--text-dim);
    margin-left: 4px;
}
.faultchip--parent.is-open::after { content: "▴"; }

/* Sélection en masse de modèles */
.masslist {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 3px;
    max-height: 46vh;
    overflow-y: auto;
    padding-right: 3px;
}

/* Saisie d'une référence directement dans le tableau */
.lineform { display: flex; gap: 6px; align-items: center; margin: 0; flex-wrap: wrap; }
.lineform select { min-width: 150px; }
.lineform .input { min-width: 130px; flex: 1; }

/* Ligne attendue dont les caractéristiques manquent */
.scanlist__item--todo { border-left: 3px solid var(--wait); }
.scanlist__item--todo .chipbtn { margin-left: auto; }

/* Écran ouvert en fenêtre modale */
.modal__box--wide {
    position: relative;
    /* La boîte de base est un avertissement court : texte centré, boutons
       étirés. Un écran complet ouvert dedans hérite de ces règles et paraît
       déséquilibré — il faut les annuler explicitement. */
    width: min(1120px, 94vw);
    max-width: none;
    max-height: 92vh;
    overflow-y: auto;
    padding: 0;
    text-align: left;
    border-top: 0;
}
.modal__box--wide .actions { justify-content: flex-start; margin: 0; }
.modal__box--wide .actions .btn { flex: 0 0 auto; }
.modal__box--wide .card {
    border: 0;
    box-shadow: none;
    margin: 0;
}
.modal__box--wide .card + .card { border-top: 1px solid var(--line); }
.modal__close {
    /* Posé par-dessus, jamais dans le flux : en flottant, il creusait une
       encoche blanche dans le bandeau, que le contenu contournait. */
    position: absolute;
    top: 10px;
    right: 12px;
    z-index: 3;
    width: 28px;
    height: 28px;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--surface);
    color: var(--text-dim);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
}
.modal__close:hover { background: var(--surface-2); color: var(--text); }
.modal__loading {
    padding: 28px;
    text-align: center;
    color: var(--text-dim);
}

/* Bloc replié : ce dont on a rarement besoin ne prend pas de place */
.foldable {
    margin: 11px 0;
    border: 1px solid var(--line);
    border-radius: 7px;
    background: var(--surface-2);
}
.foldable > summary {
    padding: 8px 12px;
    cursor: pointer;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-dim);
    list-style: none;
    user-select: none;
}
.foldable > summary::-webkit-details-marker { display: none; }
.foldable > summary::before {
    content: "▸";
    display: inline-block;
    width: 13px;
    color: var(--text-dim);
}
.foldable[open] > summary::before { content: "▾"; }
.foldable[open] > summary {
    border-bottom: 1px solid var(--line);
    color: var(--text);
}
.foldable > *:not(summary) { padding: 0 12px; }
.foldable > *:not(summary):first-of-type { padding-top: 11px; }
.foldable > *:not(summary):last-child { padding-bottom: 12px; }

/* Ligne attendue : tout le bloc réagit au clic */
.scanlist__item--todo { cursor: pointer; }
.scanlist__item--todo:hover { background: var(--wait-bg); }
.scanlist__item--todo .tag { margin-left: auto; }

/* Choix de la testeuse resté vide */
.field--invalid .techpick {
    border: 1px solid var(--alert);
    border-radius: 7px;
    padding: 5px;
}
.field--invalid .field__error { margin-bottom: 5px; }

/* Écran chargé qui a besoin de place : catalogue de pièces, tableaux larges */
.modal__box--large { width: min(1560px, 96vw); }

@media (min-width: 1200px) {
    .modal__box--wide .faultgroups {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
        gap: 11px;
        align-items: start;
    }
    .modal__box--wide .masslist {
        grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
        max-height: 56vh;
    }
    .modal__box--wide .field__hint { max-width: 78ch; }
}

/* Réception déjà commencée, à sa place dans l'ordre des numéros */
.row--open > td:first-child { box-shadow: inset 3px 0 0 var(--wait); }

/* Valeur en cours rappelée pendant la saisie */
.combo__input:focus::placeholder {
    color: var(--text-dim);
    opacity: .75;
    font-style: italic;
}

/* Signalement replié : un repère discret qui s'ouvre au clic */
/* Les sections pliables de la fiche appareil : fermées par défaut, un
   clic les ouvre. Le chevron dit l'état. */
.fold > .fold__head { cursor: pointer; list-style: none; user-select: none; }
.fold > .fold__head::-webkit-details-marker { display: none; }
.fold > .fold__head::after {
    content: '▸'; margin-left: auto; color: var(--text-dim);
    transition: transform .15s ease;
}
.fold[open] > .fold__head::after { transform: rotate(90deg); }

.alertfold {
    margin: 0 0 11px;
    border: 1px solid var(--wait);
    border-radius: var(--radius);
    background: var(--wait-bg);
    overflow: hidden;
}
.alertfold__head {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 13px;
    cursor: pointer;
    list-style: none;
    user-select: none;
}
.alertfold__head::-webkit-details-marker { display: none; }
.alertfold__mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    flex: 0 0 20px;
    border-radius: 50%;
    background: var(--wait);
    color: #fff;
    font-size: 13px;
    font-weight: 800;
}
.alertfold__title {
    font-size: 13px;
    font-weight: 700;
    color: var(--text);
    flex: 1;
    min-width: 0;
}
.alertfold__hint {
    font-size: 11.5px;
    color: var(--text-dim);
    white-space: nowrap;
}
.alertfold__hint::after {
    content: " ▾";
    font-size: 10px;
}
.alertfold[open] .alertfold__hint::after { content: " ▴"; }
.alertfold[open] .alertfold__head {
    border-bottom: 1px solid var(--wait);
}
.alertfold__body {
    padding: 11px 13px 13px;
    background: var(--card);
}

/* ============================================================ Fiche de panne
   Lisible en pleine page comme en fenêtre : bandeau d'identité, deux colonnes,
   pied d'actions. L'icône en grand sert de repère — c'est elle que l'opérateur
   reconnaît sur l'écran de test, pas le libellé. */

.faultsheet {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    overflow: hidden;
    text-align: left;
}

/* En fenêtre, la boîte porte déjà le cadre : la fiche s'y fond. */
.modal__box--wide .faultsheet {
    border: 0;
    box-shadow: none;
    border-radius: 0;
}

.faultsheet__head {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 20px 56px 20px 24px;
    background: linear-gradient(180deg, var(--card-2) 0%, var(--card) 100%);
    border-bottom: 1px solid var(--line);
}

.faultsheet__plate {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    flex: 0 0 56px;
    border-radius: 12px;
    background: var(--card);
    border: 1px solid var(--line);
    box-shadow: inset 0 0 0 4px #fff, 0 1px 3px rgba(18, 34, 45, .08);
    color: var(--cyan);
}
.faultsheet__icon { width: 26px; height: 26px; }

.faultsheet__ident { min-width: 0; flex: 1; }

.faultsheet__path {
    margin: 0 0 2px;
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-dim);
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}
.faultsheet__path a { color: var(--cyan); text-decoration: none; }
.faultsheet__path a:hover { text-decoration: underline; }
.faultsheet__sep { color: var(--line); }

.faultsheet__name {
    margin: 0;
    font-size: 21px;
    line-height: 1.2;
    font-weight: 700;
    color: var(--text);
    /* Les h2 de l'application sont des étiquettes en capitales ; ici c'est un
       nom propre, qui doit se lire tel qu'il a été saisi. */
    text-transform: none;
    letter-spacing: -0.01em;
}

.faultsheet__state {
    margin: 7px 0 0;
    display: flex;
    align-items: center;
    gap: 9px;
    flex-wrap: wrap;
}
.faultsheet__note {
    font-size: 12px;
    color: var(--text-soft);
    margin: 0;
}

.faultsheet__cols {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
}
@media (min-width: 860px) {
    .faultsheet__cols { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .faultsheet__col + .faultsheet__col {
        border-left: 1px solid var(--line-soft);
        border-top: 0;
    }
}
.faultsheet__col { padding: 20px 24px; }
.faultsheet__col + .faultsheet__col { border-top: 1px solid var(--line-soft); }

.faultsheet__legend {
    margin: 0 0 14px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--text-dim);
    display: flex;
    align-items: center;
    gap: 8px;
}
.faultsheet__count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--card-2);
    border: 1px solid var(--line);
    color: var(--text-soft);
    font-size: 11px;
    letter-spacing: 0;
}

.faultsheet__empty {
    margin: 0;
    padding: 16px;
    border: 1px dashed var(--line);
    border-radius: 8px;
    background: var(--card-2);
    color: var(--text-soft);
    font-size: 12.5px;
}

.faultsheet__list {
    list-style: none;
    margin: 11px 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 5px;
    max-height: 260px;
    overflow-y: auto;
}
/* Le nom et sa corbeille sur la même ligne : le bouton tombait dessous,
   ce qui doublait la hauteur de chaque sous-panne et éloignait l'action
   de ce qu'elle supprime. */
.faultsheet__list > li {
    display: flex;
    align-items: center;
    gap: 5px;
}
.faultsheet__list > li > .faultsheet__child { flex: 1 1 auto; min-width: 0; }
.faultsheet__list > li > form { flex: none; }

.faultsheet__child {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 8px 11px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--card);
    color: var(--text);
    text-decoration: none;
    font-size: 13px;
    transition: border-color .12s, background .12s;
}
.faultsheet__child:hover {
    border-color: var(--cyan);
    background: var(--info-bg);
}
.faultsheet__childicon { width: 16px; height: 16px; flex: 0 0 16px; color: var(--cyan); }
.faultsheet__childname { flex: 1; min-width: 0; }
.faultsheet__childcount {
    font-size: 11px;
    font-weight: 700;
    color: var(--signal);
    background: var(--signal-bg);
    border-radius: 999px;
    padding: 1px 7px;
}

.faultsheet__foot {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 14px 24px;
    border-top: 1px solid var(--line);
    background: var(--card-2);
}
.faultsheet__spacer { flex: 1; }
.faultsheet__foot .btn { flex: 0 0 auto; }

/* Ajout d'une sous-panne : sous la liste, dans la même colonne */
.faultsheet__add {
    margin-top: 11px;
    padding-top: 11px;
    border-top: 1px dashed var(--line);
}
.faultsheet__add .field__hint { margin-top: 6px; }

/* Deux champs côte à côte même en colonne étroite : ils vont par paire */
.faultsheet__pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 9px;
}
.faultsheet__hidden { display: none; }

/* ================================================= Choix en cascade
   Marque, puis modèles, puis couleur. Les numéros disent l'ordre réel des
   gestes — ils ne décorent pas, ils guident. */

.pickchain { margin: 0; }

.pickchain__row {
    display: flex;
    gap: 13px;
    flex-wrap: wrap;
    align-items: flex-end;
}
.pickchain__step {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 190px;
    flex: 0 1 240px;
}
.pickchain__num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--cyan);
    color: #fff;
    font-size: 11px;
    font-weight: 800;
    flex: 0 0 18px;
}
.pickchain__label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--text-dim);
}
/* Le numéro se lit avec son intitulé, sur la même ligne */
.pickchain__step .pickchain__label,
.pickchain__head .pickchain__label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.pickchain__step > .pickchain__num { display: none; }
.pickchain__step .pickchain__label::before {
    content: attr(data-step);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 17px;
    height: 17px;
    border-radius: 50%;
    background: var(--cyan);
    color: #fff;
    font-size: 10.5px;
    font-weight: 800;
}

.pickchain__models {
    margin-top: 15px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--card-2);
}
.pickchain__head {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 11px;
    border-bottom: 1px solid var(--line);
    flex-wrap: wrap;
}
.pickchain__count {
    font-size: 12px;
    color: var(--text-soft);
    flex: 1;
}
.pickchain__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 2px;
    padding: 9px;
    max-height: 320px;
    overflow-y: auto;
}
.pickchain__item {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 5px 8px;
    border-radius: 6px;
    font-size: 12.5px;
    cursor: pointer;
    background: var(--card);
    border: 1px solid transparent;
}
.pickchain__item:hover { border-color: var(--line); }
.pickchain__item:has(input:checked) {
    background: var(--info-bg);
    border-color: var(--cyan);
    font-weight: 600;
}
.pickchain__item input { flex: 0 0 auto; }
.pickchain__item span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.pickchain__foot {
    display: flex;
    align-items: center;
    gap: 13px;
    margin-top: 13px;
    flex-wrap: wrap;
}

/* Dépendance à la couleur : le choix se lit sur son résultat, pas sur son nom */
.colorchoice {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 9px;
    margin: 11px 0 0;
}
.colorchoice__opt {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 13px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--card);
    cursor: pointer;
}
.colorchoice__opt:hover { border-color: var(--cyan); }
.colorchoice__opt:has(input:checked) {
    border-color: var(--cyan);
    background: var(--info-bg);
    box-shadow: inset 0 0 0 1px var(--cyan);
}
.colorchoice__name {
    font-weight: 700;
    font-size: 13px;
    flex: 0 0 auto;
}
.colorchoice__demo {
    font-family: var(--mono);
    font-size: 12px;
    color: var(--text-soft);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.colorchoice__opt:has(input:checked) .colorchoice__demo { color: var(--text); }

/* ====================================================== Fiche d'un modèle
   Le référentiel compte huit cents lignes pour quatre-vingt-huit appareils.
   Ici on voit l'appareil : ses capacités d'un côté, ses teintes de l'autre. */

.modelsheet {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    overflow: hidden;
    text-align: left;
}
.modal__box--wide .modelsheet {
    border: 0;
    box-shadow: none;
    border-radius: 0;
}

.modelsheet__head {
    display: flex;
    align-items: center;
    gap: 20px;
    padding: 18px 56px 18px 24px;
    background: linear-gradient(180deg, var(--card-2) 0%, var(--card) 100%);
    border-bottom: 1px solid var(--line);
    flex-wrap: wrap;
}
.modelsheet__ident { min-width: 0; flex: 1; }
.modelsheet__brand {
    margin: 0 0 2px;
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-dim);
}
.modelsheet__name {
    margin: 0;
    font-size: 21px;
    line-height: 1.2;
    font-weight: 700;
    color: var(--text);
    text-transform: none;
    letter-spacing: -0.01em;
}
.modelsheet__facts {
    display: flex;
    gap: 18px;
    font-size: 12px;
    color: var(--text-soft);
    flex-wrap: wrap;
}
.modelsheet__facts strong { color: var(--text); font-size: 15px; }

.modelsheet__cols {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 780px) {
    .modelsheet__cols { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .modelsheet__col + .modelsheet__col {
        border-left: 1px solid var(--line-soft);
        border-top: 0;
    }
}
.modelsheet__col { padding: 20px 24px; }
.modelsheet__col + .modelsheet__col { border-top: 1px solid var(--line-soft); }

.modelsheet__legend {
    margin: 0 0 13px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--text-dim);
}

.varlist {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.varlist__item {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 6px 9px 6px 12px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--card-2);
    font-size: 13px;
}
.varlist__value { font-weight: 600; color: var(--text); }
.varlist__stock {
    font-size: 11px;
    font-weight: 700;
    color: var(--info);
    background: var(--info-bg);
    border-radius: 999px;
    padding: 1px 7px;
}
.varlist__remove {
    border: 0;
    background: none;
    color: var(--text-dim);
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
    padding: 0 2px;
}
.varlist__remove:hover { color: var(--alert); }

.varadd {
    display: flex;
    gap: 7px;
    margin: 14px 0 0;
}
.varadd .input { flex: 1; min-width: 0; }

.modelsheet__foot {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 13px 24px;
    border-top: 1px solid var(--line);
    background: var(--card-2);
}

/* Renommage d'un modèle : replié tant qu'on ne le demande pas */
.renameform {
    display: flex;
    align-items: flex-end;
    gap: 9px;
    flex-wrap: wrap;
    margin: 0;
    padding: 15px 24px;
    background: var(--wait-bg);
    border-bottom: 1px solid var(--line);
}
.renameform__field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 0 1 200px;
    min-width: 0;
}
.renameform__field--wide { flex: 1 1 280px; }
.renameform__field > span {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--text-dim);
}

/* ======================================================= Fiche d'une pièce
   Un seul bloc, comme les fiches panne et modèle. Trois cartes empilées se
   lisaient comme trois fenêtres superposées dès qu'on ouvrait en fenêtre. */

.partsheet {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    overflow: hidden;
    text-align: left;
}
.modal__box--wide .partsheet {
    border: 0;
    box-shadow: none;
    border-radius: 0;
}

.partsheet__head {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 18px 56px 18px 24px;
    background: linear-gradient(180deg, var(--card-2) 0%, var(--card) 100%);
    border-bottom: 1px solid var(--line);
    flex-wrap: wrap;
}
.partsheet__ident { min-width: 0; flex: 1; }
.partsheet__kind {
    margin: 0 0 2px;
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-dim);
}
.partsheet__name {
    margin: 0;
    font-size: 20px;
    line-height: 1.2;
    font-weight: 700;
    color: var(--text);
    text-transform: none;
    letter-spacing: -0.01em;
}
.partsheet__state {
    margin: 7px 0 0;
    display: flex;
    gap: 7px;
    flex-wrap: wrap;
}

.partsheet__section { padding: 20px 24px; }
.partsheet__section + .partsheet__section { border-top: 1px solid var(--line-soft); }

.partsheet__legend {
    margin: 0 0 14px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--text-dim);
    display: flex;
    align-items: center;
    gap: 8px;
}
.partsheet__count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--card-2);
    border: 1px solid var(--line);
    color: var(--text-soft);
    font-size: 11px;
    letter-spacing: 0;
}

/* Un compte plutôt qu'une liste qu'on ne lira pas */
.bigcount {
    margin: 0 0 13px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.bigcount__value {
    font-size: 40px;
    font-weight: 700;
    line-height: 1;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}
.bigcount__label {
    font-size: 12.5px;
    color: var(--text-soft);
}

/* Liste de repère : quelques lignes, pas cinq cents */
.scanlist--short { max-height: 230px; overflow-y: auto; }

/* ================================================= Choix du bac de gradage
   Trois cibles larges : on grade avec un appareil dans une main et le
   scanner dans l'autre, sans viser. */

.gradepick {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 9px;
    max-width: 560px;
}
.gradepick__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: 13px 9px;
    border: 1px solid var(--line);
    border-radius: 9px;
    background: var(--card);
    cursor: pointer;
    transition: border-color .12s, background .12s;
}
.gradepick__letter {
    font-size: 26px;
    font-weight: 800;
    line-height: 1;
    color: var(--text-dim);
}
.gradepick__hint {
    font-size: 11px;
    color: var(--text-dim);
}
.gradepick__item:hover { border-color: var(--cyan); }

.gradepick__item.is-selected { border-width: 2px; padding: 12px 8px; }
.gradepick__item--a.is-selected {
    border-color: var(--signal);
    background: var(--signal-bg);
}
.gradepick__item--a.is-selected .gradepick__letter { color: var(--signal); }
.gradepick__item--b.is-selected {
    border-color: var(--wait);
    background: var(--wait-bg);
}
.gradepick__item--b.is-selected .gradepick__letter { color: var(--wait); }
.gradepick__item--c.is-selected {
    border-color: var(--alert);
    background: var(--alert-bg);
}
.gradepick__item--c.is-selected .gradepick__letter { color: var(--alert); }
.gradepick__item.is-selected .gradepick__hint { color: var(--text); }

/* Quatre choix au retour de regradage : les trois grades, et l'irréparable */
.gradepick:has(.gradepick__item--hs) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.gradepick__item--hs .gradepick__letter { font-size: 20px; }
.gradepick__item--hs.is-selected {
    border-color: var(--text-dim);
    background: var(--card-2);
}
.gradepick__item--hs.is-selected .gradepick__letter { color: var(--text); }

/* Bac affecté : le nom se lit, il ne se choisit plus */
.binowner {
    display: flex;
    align-items: center;
    gap: 11px;
    margin-top: 7px;
    padding: 11px 14px;
    border: 1px solid var(--signal);
    border-radius: 9px;
    background: var(--signal-bg);
    flex-wrap: wrap;
}
.binowner__name { font-size: 15px; font-weight: 700; color: var(--text); }
.binowner__note { font-size: 12px; color: var(--text-soft); }

/* ============================================ Choix d'une testeuse ou testeur
   Des vignettes courtes : il n'y a qu'un nom à lire, et souvent trois ou
   quatre comptes. Le style de l'attribution technicien réserve de la place
   pour des compteurs et un bouton « Voir » — ici il n'y a ni l'un ni l'autre,
   et cette place vide donnait des cartes démesurées. */

.testerpick {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    margin-top: 8px;
}
.testerpick__item {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--card);
    cursor: pointer;
    transition: border-color .12s, background .12s;
}
.testerpick__item:hover { border-color: var(--cyan); }
.testerpick__name {
    font-size: 13.5px;
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
}
.testerpick__item.is-selected {
    border-color: var(--signal);
    background: var(--signal-bg);
    box-shadow: inset 0 0 0 1px var(--signal);
}
.testerpick__item input { margin: 0; }

/* ============================================ Deux façons d'exporter un lot
   Le complet sert de preuve, le condensé se lit. Les présenter côte à côte
   évite d'imposer un choix qui dépend de l'interlocuteur. */

.exportpair {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    padding: 5px 11px 5px 12px;
    border: 1px solid var(--line);
    border-radius: 9px;
    background: var(--card-2);
    flex-wrap: wrap;
}
.exportpair__label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-dim);
}
.exportpair__group {
    display: inline-flex;
    align-items: center;
    gap: 5px;
}
.exportpair__group + .exportpair__group {
    padding-left: 9px;
    border-left: 1px solid var(--line);
}
.exportpair__kind {
    font-size: 11.5px;
    color: var(--text-soft);
}

/* ======================================================= Scan en série
   Cochée, une case enregistre au scan sans ouvrir la fiche. La barre change
   de couleur : on ne doit jamais scanner en série sans le savoir, surtout
   quand le mode envoie au rebut. */

.serialmode {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 13px;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, 0.22);
    background: rgba(255, 255, 255, 0.06);
    color: #E8F2F6;
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
}
.serialmode input { margin: 0; }
.serialmode:has(input:checked) { border-color: transparent; }
.serialmode--ok:has(input:checked) { background: var(--signal); color: #10240A; }
.serialmode--hs:has(input:checked) { background: var(--alert); color: #FFF; }

/* Jaune franc : le mode série se voit à l'autre bout de l'atelier */
.scanbar--serie-ok {
    background: linear-gradient(180deg, #F5C400 0%, #E0AF00 100%);
    box-shadow: 0 0 0 3px rgba(245, 196, 0, 0.35);
}
.scanbar--serie-ok .scanbar__label { color: #3A2C00; }
.scanbar--serie-ok .scanbar__input {
    background: rgba(255, 255, 255, 0.94);
    color: #1B1400;
}
.scanbar--serie-ok .serialmode { border-color: rgba(0, 0, 0, 0.25); color: #3A2C00; }

.scanbar--serie-hs {
    background: linear-gradient(180deg, #C42B2B 0%, #A11F1F 100%);
    box-shadow: 0 0 0 3px rgba(196, 43, 43, 0.32);
}
.scanbar--serie-hs .scanbar__label { color: #FFE7E7; }
.scanbar--serie-hs .scanbar__input { background: rgba(255, 255, 255, 0.94); color: #2A0A0A; }

/* Panne appliquée aux HS scannés en série */
.serialfault {
    display: flex;
    align-items: center;
    gap: 11px;
    margin: 9px 0 0;
    padding: 11px 14px;
    border: 1px solid var(--alert);
    border-radius: 9px;
    background: var(--alert-bg);
    flex-wrap: wrap;
}
.serialfault__label {
    font-size: 12px;
    font-weight: 700;
    color: var(--alert);
}
.serialfault .input { flex: 1 1 280px; min-width: 0; }

/* Mode « pannes en série » : orange, distinct du jaune « aucune panne » */
.serialmode--tech:has(input:checked) { background: var(--wait); color: #2A1C00; }

.scanbar--serie-tech {
    background: linear-gradient(180deg, #E08A00 0%, #C77400 100%);
    box-shadow: 0 0 0 3px rgba(224, 138, 0, 0.32);
}
.scanbar--serie-tech .scanbar__label { color: #3A2400; }
.scanbar--serie-tech .scanbar__input { background: rgba(255, 255, 255, 0.94); color: #2A1A00; }
.scanbar--serie-tech .serialmode { border-color: rgba(0, 0, 0, 0.25); color: #3A2400; }

/* La barre rouge du tri « ne s'allume pas » (écran /bacs/eteints) :
   l'appareil est éteint, il part en attribution sans test. */
.scanbar--serie-off {
    background: linear-gradient(180deg, #C8432B 0%, #A8321E 100%);
    box-shadow: 0 0 0 3px rgba(200, 67, 43, 0.32);
}
.scanbar--serie-off .scanbar__label { color: #FFE9E4; }
.scanbar--serie-off .scanbar__input { background: rgba(255, 255, 255, 0.94); color: #3A0E06; }
.scanbar--serie-off .serialmode { border-color: rgba(255, 255, 255, 0.35); color: #FFE9E4; }

/* Pannes retenues pour la série : visibles tant que le mode est actif */
.serialfaults {
    margin: 9px 0 0;
    padding: 12px 14px;
    border: 1px solid var(--wait);
    border-radius: 9px;
    background: var(--wait-bg);
}
.serialfaults__head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-bottom: 9px;
    flex-wrap: wrap;
}
.serialfaults__label {
    font-size: 12px;
    font-weight: 700;
    color: var(--wait);
}
.serialfaults__count {
    font-size: 11.5px;
    color: var(--text-soft);
}
/* Le panneau de série contient la même grille que la fiche : il suit donc
   la même règle de hauteur. Deux limites différentes pour un même contenu
   donnaient deux comportements selon l'endroit où l'on coche. */
.serialfaults .faultgroups {
    max-height: max(240px, calc(100vh - 480px));
}

@media (max-height: 800px) {
    .serialfaults .faultgroups { max-height: calc(100vh - 400px); }
}

/* ==================================================== Demande de confirmation
   La fenêtre du navigateur bloque l'onglet, ignore le thème et annonce le nom
   de domaine — elle paraît venir d'ailleurs, juste avant un geste qu'on ne
   peut pas défaire. Celle-ci reste dans l'application. */

.modal__box--ask {
    max-width: 460px;
    padding: 24px;
    text-align: left;
}
.askbox__text {
    margin: 0 0 20px;
    font-size: 15px;
    line-height: 1.5;
    color: var(--text);
}
.askbox__actions {
    display: flex;
    justify-content: flex-end;
    gap: 9px;
}

/* Le bouton d'action porte la couleur du risque : vert pour un enregistrement,
   rouge pour ce qui ne se défait pas. */
.askbox__actions .btn--stop { min-width: 120px; }
.askbox__actions .btn--go { min-width: 120px; }

/* Titre de la fenêtre de confirmation : elle doit se reconnaître comme
   venant de l'application, et non du navigateur. */
.askbox__title {
    margin: 0 0 9px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--text-dim);
}
.askbox__title--danger { color: var(--alert); }

/* ══════════════════════════════════════════════════ Adaptation à l'écran

   L'atelier travaille sur des écrans très différents : un portable de 1280,
   un poste de scan en 1920, une tablette posée près du bac. Les points de
   rupture existants s'arrêtaient à 1000 px — entre les deux, les tableaux
   débordaient et il fallait faire défiler pour lire une ligne entière.

   Le principe retenu : réduire d'abord ce qui est décoratif — marges,
   corps de texte, colonnes accessoires — avant de faire défiler. Un
   défilement horizontal dans un tableau se remarque mal, et une colonne
   qu'on n'a pas vue vaut une colonne absente. */

/* ---- Écrans larges : le contenu ne s'étire pas indéfiniment ---- */
/* Écrans larges : le contenu s'aligne sur le menu, il ne se centre pas.
   Centrer chaque carte creusait une bande vide entre le menu et le contenu —
   l'écran paraissait cassé alors qu'il était seulement large. Une borne haute
   empêche les lignes de s'étirer au point qu'on perde l'œil en les lisant. */
@media (min-width: 1900px) {
    /* Tous les blocs de premier niveau, et non une liste de classes : une
       alerte, un bandeau, un écran à venir se retrouvaient hors de la borne
       et traversaient l'écran alors que les cartes s'arrêtaient avant. Deux
       largeurs sur une même page se voient immédiatement. */
    .content > * {
        max-width: 2100px;
        margin-left: 0;
        margin-right: auto;
    }
}

/* ---- Entre 1100 et 1400 : on resserre avant de faire défiler ---- */
@media (max-width: 1400px) {
    .table--dense th,
    .table--dense td { padding-left: 7px; padding-right: 7px; }

    .filterbar__field { flex: 1 1 150px; }
    .stockgrid { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
}

@media (max-width: 1200px) {
    .table th,
    .table td { font-size: 12.5px; }

    .imei { font-size: 12px; padding: 0 3px; }

    /* Deux colonnes de scan côte à côte deviennent trop étroites pour
       lire un modèle et sa couleur : elles passent l'une sous l'autre. */
    .scancols { grid-template-columns: minmax(0, 1fr); }

    .techpick { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
    .gradepick { max-width: none; }
}

/* ---- Sous 1000 : les colonnes accessoires s'effacent ----
   Elles restent dans l'export, qui n'a pas de contrainte de largeur. */
@media (max-width: 1000px) {
    .table [data-optional],
    .table--dense [data-optional] { display: none; }

    .card__head { flex-wrap: wrap; gap: 8px; }
    .card__head .actions { width: 100%; }
}

/* ---- Tablette : les cibles s'agrandissent, le texte reste lisible ---- */
@media (max-width: 820px) {
    .scanbar { flex-wrap: wrap; }
    .scanbar__input { flex: 1 1 100%; order: 2; }
    .scanbar__label { order: 1; }

    .btn--lg { padding: 12px 18px; }
    .chipbtn { padding: 7px 12px; }

    .exportpair { flex-direction: column; align-items: flex-start; }
    .exportpair__group + .exportpair__group {
        padding-left: 0;
        border-left: 0;
        padding-top: 7px;
        border-top: 1px solid var(--line);
        width: 100%;
    }
}

/* ---- Le tableau ne défile qu'en dernier recours, et le dit ---- */
.table-wrap { position: relative; }
.table-wrap::after {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 26px;
    pointer-events: none;
    opacity: 0;
    transition: opacity .15s;
    background: linear-gradient(to right, rgba(255, 255, 255, 0), var(--card));
}
.table-wrap--scrolls::after { opacity: 1; }

/* Correction d'un grade : les deux autres lettres, à portée de clic.
   Se tromper de bac arrive ; retrouver l'appareil dans le stock pour le
   regrader coûte plus cher que l'erreur elle-même. */
.regrade { display: inline-flex; gap: 4px; }
.regrade__btn {
    min-width: 30px;
    padding: 4px 0;
    justify-content: center;
    font-weight: 700;
}
.regrade__btn--a:hover { border-color: var(--signal); background: var(--signal-bg); color: #2F5A00; }
.regrade__btn--b:hover { border-color: var(--wait);   background: var(--wait-bg);   color: #6A4B00; }
.regrade__btn--c:hover { border-color: var(--alert);  background: var(--alert-bg);  color: var(--alert); }

/* Mode regradage : la barre entière passe au jaune. Le même signal que
   « aucune panne » au test — on ne se demande jamais dans quel mode on est,
   la couleur le dit d'un bout à l'autre de l'atelier. */
.serialmode--fix:has(input:checked) { background: #F5C400; color: #3A2C00; }

.scanbar--regrade {
    background: linear-gradient(180deg, #F5C400 0%, #E0AF00 100%);
    box-shadow: 0 0 0 3px rgba(245, 196, 0, 0.35);
}
.scanbar--regrade .scanbar__label { color: #3A2C00; }
.scanbar--regrade .scanbar__input {
    background: rgba(255, 255, 255, 0.94);
    color: #1B1400;
}
.scanbar--regrade .serialmode { border-color: rgba(0, 0, 0, 0.25); color: #3A2C00; }

/* Reste à récupérer, dans la barre de scan des pièces */
.partscan__left {
    display: inline-flex;
    align-items: baseline;
    gap: 5px;
    padding: 0 12px;
    color: #E8F2F6;
    font-size: 12.5px;
    white-space: nowrap;
}
.partscan__left strong { font-size: 19px; font-weight: 700; }

/* Ce que le technicien a sur sa table : la panne d'abord, l'ancienneté ensuite */
/* La panne passe à la ligne : sur la même, elle chassait le modèle hors du
   champ visible, et le technicien ne savait plus de quel appareil il s'agit. */
.scanlist__item:has(.benchfaults) { flex-wrap: wrap; }
.benchparts {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 12px; font-weight: 600; color: var(--wait);
    background: var(--wait-bg); border: 1px solid #EFD4A0;
    border-radius: 6px; padding: 2px 8px; margin-left: 6px;
}
.benchfaults {
    flex: 1 1 100%;
    order: 3;
    margin-top: 2px;
    padding-left: 2px;
    font-size: 12px;
    color: var(--wait);
    font-weight: 600;
}
.benchage { order: 2; }
.benchage {
    margin-left: auto;
    font-size: 11.5px;
    color: var(--text-dim);
    white-space: nowrap;
}

/* Passages en atelier : « T » une fois, « T2 » deux fois.
   Discret mais repérable — c'est un signal, pas une alerte. */
.techbadge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 21px;
    height: 17px;
    padding: 0 4px;
    margin-left: 3px;
    border-radius: 5px;
    background: var(--wait-bg);
    border: 1px solid var(--wait);
    color: var(--wait);
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: .02em;
    vertical-align: middle;
}

/* Choix du sous-traitant : des vignettes, pas un menu déroulant.
   Ils sont peu nombreux, et ce que chacun détient se lit d'un coup. */
.subpick {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 7px;
    margin-top: 8px;
}
.subpick__item {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 11px 14px;
    border: 1px solid var(--line);
    border-radius: 9px;
    background: var(--card);
    text-decoration: none;
    transition: border-color .12s, background .12s;
}
.subpick__item:hover { border-color: var(--cyan); }
.subpick__name { font-size: 14px; font-weight: 700; color: var(--text); }
.subpick__item.is-selected {
    border-color: var(--signal);
    background: var(--signal-bg);
    box-shadow: inset 0 0 0 1px var(--signal);
}

/* Vignette de sous-traitant employée comme bouton : elle doit se comporter
   comme le lien qu'elle remplace, pas comme un bouton de formulaire. */
button.subpick__item {
    width: 100%;
    text-align: left;
    cursor: pointer;
    font: inherit;
}

/* Consigne d'un appareil du lot : elle se lit d'un coup d'œil et se corrige
   sur place, sans quitter la liste ni ouvrir de fiche. */
.worktext {
    flex: 1 1 220px;
    min-width: 0;
    margin-left: auto;
    padding: 5px 9px;
    border: 1px solid transparent;
    border-radius: 7px;
    background: var(--wait-bg);
    color: var(--wait);
    font-size: 12.5px;
    font-weight: 600;
    font-family: inherit;
}
.worktext:hover { border-color: var(--wait); }
.worktext:focus {
    border-color: var(--cyan);
    background: var(--card);
    color: var(--text);
    outline: none;
}
.worktext.is-saved { border-color: var(--signal); }

/* Ligne déjà scannée : on la montre au lieu de la faire chercher.
   Le clignotement s'arrête de lui-même — un surlignage permanent
   s'accumulerait au fil des scans jusqu'à ne plus rien dire. */
@keyframes flash-ligne {
    0%   { background: var(--wait-bg); box-shadow: inset 3px 0 0 var(--wait); }
    70%  { background: var(--wait-bg); box-shadow: inset 3px 0 0 var(--wait); }
    100% { background: transparent;    box-shadow: none; }
}
.is-flash { animation: flash-ligne 1.6s ease-out; }

@media (prefers-reduced-motion: reduce) {
    .is-flash { animation: none; background: var(--wait-bg); }
}

/* Passage en réparation externe : distinct du badge d'atelier, car ce qui a
   été fait l'a été dehors — une panne qui persiste se réclame. */
.techbadge--ext {
    background: var(--info-bg);
    border-color: var(--cyan);
    color: var(--cyan);
}

/* Badge d'une entrée de menu : poussé à droite, sans écarter le libellé */
.nav__badge { margin-left: auto; flex: none; }

/* Niveau de gravité d'une panne : N1 léger, N2 moyen, N3 lourd.
   Les trois couleurs des feux de circulation — on les lit sans réfléchir. */
.sevbadge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 24px;
    height: 18px;
    padding: 0 5px;
    margin-left: 4px;
    border-radius: 5px;
    border: 1px solid;
    font-size: 10.5px;
    font-weight: 800;
    vertical-align: middle;
}
.sevbadge--n1 { background: var(--signal-bg); border-color: var(--signal); color: #2F5A00; }
.sevbadge--n2 { background: var(--wait-bg);   border-color: var(--wait);   color: #6A4B00; }
.sevbadge--n3 { background: var(--alert-bg);  border-color: var(--alert);  color: var(--alert); }

/* Choix du niveau : quatre vignettes, la couleur avant le mot */
.sevpick { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.sevpick__item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 11px;
    border: 1px solid var(--line);
    border-radius: 8px;
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
}
.sevpick__item:has(input:checked) { border-width: 2px; padding: 5px 10px; }
.sevpick__item--n1:has(input:checked) { border-color: var(--signal); background: var(--signal-bg); }
.sevpick__item--n2:has(input:checked) { border-color: var(--wait);   background: var(--wait-bg); }
.sevpick__item--n3:has(input:checked) { border-color: var(--alert);  background: var(--alert-bg); }
.sevpick__item--n0:has(input:checked) { border-color: var(--cyan);   background: var(--info-bg); }

/* Récapitulatif de clôture, montré dans la confirmation.
   Trois colonnes côte à côte : on lit les trois tas d'un regard, sans
   défiler — c'est le dernier moment pour corriger. */
/* Une seule règle de largeur : celle-ci fixait 940 px et écrasait les
   1560 px déclarés plus haut, sans que rien ne le signale. La variante
   large vaut pour tout le monde — les fiches qui la demandent ont des
   tableaux à montrer. */
.modal__box--large {
    /* La largeur de base est de 420 px : la variante doit la relever
       explicitement, sinon elle reste bornée par elle. */
    max-width: min(1560px, 96vw);
    text-align: left;
}

.recapcards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
    gap: 10px;
    margin-top: 4px;
}
.recapcard {
    border: 1px solid var(--line);
    border-top: 3px solid var(--line);
    border-radius: 9px;
    background: var(--card);
    overflow: hidden;
}
.recapcard--alert  { border-top-color: var(--alert); }
.recapcard--wait   { border-top-color: var(--wait); }
.recapcard--signal { border-top-color: var(--signal); }

.recapcard__head {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 11px;
    border-bottom: 1px solid var(--line);
}
.recapcard__count { font-size: 21px; font-weight: 800; line-height: 1; }
.recapcard__list {
    max-height: 240px;
    overflow-y: auto;
    margin: 0;
    padding: 6px 11px 9px;
    list-style: none;
}
.recapcard__list li {
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding: 4px 0;
    border-bottom: 1px solid var(--line-soft, rgba(0,0,0,.05));
}
.recapcard__list li:last-child { border-bottom: 0; }

.askbox__detail { margin-top: 12px; }

/* Grille des droits : les droits en lignes, les rôles en colonnes.
   L'en-tête reste visible en défilant — sur trente lignes, on ne sait
   plus quelle colonne on coche. */
.rolegrid thead th { position: sticky; top: 0; z-index: 2; background: var(--card); }
.rolegrid__head { text-align: center; white-space: nowrap; padding: 8px 12px; }
.rolegrid__head .small { display: block; font-weight: 500; }
.rolegrid__head .chipbtn { margin-top: 4px; }
.rolegrid__cell { text-align: center; }
.rolegrid__box { display: inline-flex; padding: 5px; cursor: pointer; }
.rolegrid__box input { width: 17px; height: 17px; cursor: pointer; }
.rolegrid__group td { background: var(--bg-soft, rgba(0,0,0,.03)); }
.rolegrid tbody tr:hover td { background: var(--info-bg); }

/* Raccourcis de stock : deux filtres sous l'écran qu'ils filtrent.
   Un liseré plutôt qu'un fond plein — ce sont des vues du stock, pas
   des écrans à part, et les peindre entièrement les mettrait au même
   rang que le reste du menu. */
.nav__link--on,
.nav__link--stop { padding-left: 15px; }
.nav__link--on   { box-shadow: inset 3px 0 0 var(--signal); }
.nav__link--stop { box-shadow: inset 3px 0 0 var(--alert); }
.nav__link--on .nav__label   { color: #BEE87A; }
.nav__link--stop .nav__label { color: #FFA9A0; }

/* Ma journée : une carte par tâche, le nombre d'abord.
   C'est le nombre qu'on cherche en arrivant — « combien m'attendent » —
   pas le libellé, qu'on connaît déjà. */
.todogrid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 10px;
}
.todocard {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 15px 17px;
    border: 1px solid var(--line);
    border-left: 4px solid var(--line);
    border-radius: 10px;
    background: var(--card);
    text-decoration: none;
    transition: border-color .12s, transform .12s;
}
.todocard:hover { transform: translateY(-1px); border-color: var(--cyan); }
.todocard--stop { border-left-color: var(--alert); }
.todocard--wait { border-left-color: var(--wait); }
.todocard--info { border-left-color: var(--cyan); }

.todocard__count {
    flex: none;
    min-width: 46px;
    font-size: 30px;
    font-weight: 800;
    line-height: 1;
    text-align: center;
    color: var(--text);
}
.todocard__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.todocard__title { font-size: 14px; color: var(--text); }
.todocard__detail { font-size: 12.5px; color: var(--text-dim); }

/* Raccourcis de stock, en haut de l'écran qu'ils filtrent.
   Le liseré devient un fond plein une fois choisi : on doit savoir
   laquelle des trois vues on regarde sans lire l'adresse. */
.stockshort { display: flex; flex-wrap: wrap; gap: 8px; }
.stockshort__item {
    padding: 8px 16px;
    border: 1px solid var(--line);
    border-radius: 8px;
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text);
    text-decoration: none;
    transition: background .12s, border-color .12s;
}
.stockshort__item:hover { border-color: var(--cyan); }
.stockshort__item.is-selected { border-color: var(--cyan); background: var(--info-bg); }

.stockshort__item--pss { border-color: var(--signal); color: #2F5A00; }
.stockshort__item--pss.is-selected { background: var(--signal-bg); border-color: var(--signal); }

.stockshort__item--hs { border-color: var(--alert); color: var(--alert); }
.stockshort__item--hs.is-selected { background: var(--alert-bg); border-color: var(--alert); }

/* Les actions d'un côté, les vues du stock de l'autre : ce sont deux gestes
   différents — appliquer des filtres, ou changer de vue. */
.actions--split {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
}
.actions__group { display: inline-flex; gap: 8px; }
.actions--split .stockshort__item { padding: 7px 14px; font-size: 13px; }

/* L'import prend l'espace libre à droite des trois grades.
   La grille de base est bornée à 560 px : la variante s'en affranchit,
   sans quoi le bouton reste collé aux vignettes. */
.gradepick--withaction {
    display: flex;
    align-items: stretch;
    gap: 9px;
    max-width: none;
}
.gradepick--withaction .gradepick__item { flex: 0 0 175px; }
.gradepick__action { margin-left: auto; align-self: center; flex: none; }

/* Déclaration des pièces posées : les prévues en évidence, le catalogue
   replié. Un technicien pose ce qui était prévu neuf fois sur dix. */
.partshead { display: flex; gap: 9px; align-items: baseline; text-align: left; margin: 2px 0 12px; }

.partsprev { display: flex; flex-direction: column; gap: 6px; text-align: left; }
.partsprev .checkline {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 12px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--card);
    font-size: 13px;
    cursor: pointer;
}
.partsprev .checkline:has(input:checked) { border-color: var(--signal); background: var(--signal-bg); }
.partschip:has(input:checked)            { border-color: var(--cyan);   background: var(--info-bg); }
.partsprev .checkline input,
.partschip input { width: 17px; height: 17px; flex: none; cursor: pointer; }

.partsmore { margin-top: 12px; text-align: left; }
.partsmore > summary {
    cursor: pointer;
    padding: 7px 11px;
    border: 1px dashed var(--line);
    border-radius: 8px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text-dim);
}
.partsmore[open] > summary { margin-bottom: 8px; color: var(--text); }
.partsmore__search { margin-bottom: 8px; padding: 6px 10px; font-size: 12.5px; }

/* Une grille dense d'étiquettes plutôt que des cartes empilées : le
   technicien doit voir tout le catalogue sans défiler, sinon il coche la
   première pièce qui passe au lieu de la bonne. */
.partsmore__body {
    /* Assez haut pour tenir le catalogue courant sans défiler : le
       technicien doit voir toutes les familles d'un regard, sinon il coche
       la première pièce qui passe au lieu de la bonne. */
    max-height: min(52vh, 460px);
    overflow-y: auto;
    padding-right: 4px;
}

/* La fenêtre des pièces s'élargit : les étiquettes tiennent alors sur
   moins de lignes, et le catalogue entier entre dans l'écran. */
/* La déclaration des pièces n'a pas besoin de toute la largeur : au-delà,
   les étiquettes s'éparpillent et l'œil parcourt plus qu'il ne lit. */
.modal__box--large:has(.partsmore) { width: min(1120px, 94vw); }

/* Le diagnostic du technicien : la fenêtre s'élargit et les pièces se
   rangent sur trois colonnes — on balaie les familles d'un coup d'œil. */
#demande-piece .modal__box { max-width: none; width: min(1120px, 94vw); }
#demande-piece .faultgroups { grid-template-columns: repeat(3, minmax(0, 1fr)); }
#demande-piece .faultgroup__items { max-height: 52vh; overflow-y: auto; }
@media (max-width: 900px) {
    #demande-piece .faultgroups { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 600px) {
    #demande-piece .faultgroups { grid-template-columns: 1fr; }
}

.partsfam { margin-bottom: 9px; }
.partsfam__title {
    margin: 0 0 4px;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--text-dim);
}
.partsfam__grid { display: flex; flex-wrap: wrap; gap: 4px; }
.partsfam[hidden] { display: none; }

/* Combien d'exemplaires : discret, à droite de la pièce. */
.partsqty { width: 54px; margin-left: auto; padding: 4px 6px; text-align: center; font-size: 12.5px; }

/* Mappage : reconnu en vert, à décider en orange. On cherche ce qui reste
   à trancher, pas ce qui est déjà juste. */
.maprow--ok   > td:first-child { box-shadow: inset 3px 0 0 var(--signal); }
.maprow--todo > td:first-child { box-shadow: inset 3px 0 0 var(--wait); }
.maprow--ok   > td { background: var(--signal-bg); }
.maprow--ok .tag,
.maprow--todo .tag { margin-left: 6px; vertical-align: middle; }

/* La destination d'un tas : c'est ce qu'on cherche en vidant le bac.
   En petit gris, elle se lisait après le titre ; elle se lit maintenant
   avec lui. */
.recapcard__wording { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.recapcard__dest {
    font-size: 12.5px;
    font-weight: 700;
    color: var(--cyan);
    white-space: nowrap;
}

/* Caractéristique manquante : la testeuse a le téléphone en main, c'est le
   seul moment où la question se règle en trois secondes. Un appareil sans
   modèle part au gradage et s'y retrouve invendable. */
.input--manquant {
    border-color: var(--wait);
    background: var(--wait-bg);
}
.input--manquant:focus { border-color: var(--cyan); background: var(--card); }
.lastscan__field.is-manquant > span { color: var(--wait); font-weight: 700; }
.lastscan__field.is-manquant > span::after { content: ' — à renseigner'; font-weight: 500; }

/* Modèle absent du référentiel : la valeur est là, mais ne correspond à rien
   de connu. Bleu et non orange — ce n'est pas un oubli, c'est un choix à
   confirmer : soit une faute de frappe, soit un modèle à déclarer. */
.input--inconnu {
    border-color: var(--cyan);
    background: var(--info-bg);
}
.input--inconnu:focus { background: var(--card); }
.lastscan__field.is-inconnu > span { color: var(--cyan); font-weight: 700; }
.lastscan__field.is-inconnu > span::after { content: ' — hors référentiel'; font-weight: 500; }

/* Modèle en sommeil : il reste consultable, mais n'est plus proposé.
   Estompé plutôt que caché — on doit pouvoir le retrouver pour le réveiller. */
.row--dormant > td { opacity: .58; }
.row--dormant:hover > td { opacity: 1; }


/* Étiquette compacte : la case et le nom, rien d'autre. Une carte par pièce
   faisait défiler sur quatre écrans pour trente références. */
.partschip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 9px;
    border: 1px solid var(--line);
    border-radius: 7px;
    background: var(--card);
    font-size: 12px;
    line-height: 1.2;
    cursor: pointer;
    white-space: nowrap;
}
.partschip input { width: 14px; height: 14px; flex: none; cursor: pointer; }
.partschip:has(input:checked) { border-color: var(--cyan); background: var(--info-bg); font-weight: 600; }
.partschip[hidden] { display: none; }

/* Écriture resserrée : plus de pièces par ligne, moins de défilement.
   Le technicien lit des noms courts qu'il connaît par cœur. */
.partschip { padding: 4px 8px; font-size: 11.5px; gap: 5px; }
.partschip input { width: 13px; height: 13px; }
.partsfam { margin-bottom: 7px; }
.partsfam__title { font-size: 9.5px; margin-bottom: 3px; }
.partsfam__grid { gap: 3px; }

/* Dans une fenêtre, l'écriture se resserre : chaque ligne gagnée est une
   ligne qu'on n'a pas à faire défiler. Les valeurs restent lisibles —
   réduire davantage ferait plisser les yeux, ce qui coûte plus que ça ne
   rapporte. */
.modal__box .table--dense td,
.modal__box .table--dense th { padding: 5px 8px; font-size: 12px; }
.modal__box .field { margin-bottom: 9px; }
.modal__box .field > label { font-size: 11px; }
.modal__box .field__hint { font-size: 11.5px; margin-top: 3px; }
.modal__box h2 { font-size: 16px; }
.modal__box h3, .modal__box .faultsheet__legend { font-size: 11px; margin-bottom: 5px; }
.modal__box .input { padding: 6px 10px; font-size: 13px; }
.modal__box .card__body { padding: 12px 14px; }
.modal__box .card__head { padding: 9px 14px; }

/* La zone qui défile occupe toute la hauteur disponible : le contenu
   utilise l'écran plutôt que de s'arrêter à une valeur arbitraire. */
.modal__box > .modal__content { flex: 1 1 auto; }


/* Les boutons d'une fenêtre gardent leur taille : sur 1560 px, un bouton
   étiré sur toute la largeur devient une barre qu'on ne reconnaît plus. */
.modal__box .actions { justify-content: flex-start; }
.modal__box .actions > .btn { flex: 0 0 auto; }

/* =============================================================================
   Adaptation à la résolution
   -----------------------------------------------------------------------------
   Les écrans de l'atelier vont du portable 1366 au grand écran de bureau. Un
   réglage unique fait défiler les uns et laisse les autres vides.
   Ces règles ne touchent que les espacements et les tailles secondaires : les
   valeurs qu'on lit — IMEI, modèles, quantités — gardent leur corps.
   ========================================================================== */

/* Portable : chaque pixel vertical compte. */
@media (max-height: 800px) {
    .shell { padding: 4px; }
    .card { margin-bottom: 8px; }
    .card__head { padding: 8px 12px; }
    .card__body { padding: 11px 13px; }
    .table td, .table th { padding: 6px 9px; }
    .table--dense td, .table--dense th { padding: 4px 8px; }
    .field { margin-bottom: 8px; }
    .topbar { padding: 7px 12px; }
    .metric { padding: 9px 12px; }
    .modal__box { max-height: calc(100vh - 24px); padding: 16px; }
}

/* Écran étroit : le menu se resserre plutôt que de manger la liste. */
@media (max-width: 1400px) {
    :root { --nav-w: 168px; }
    .nav__link { padding: 5px 8px; font-size: 12.5px; }
    .nav__group-title { font-size: 9.5px; }
}

/* Grand écran : on desserre, la place existe. */
@media (min-width: 1800px) and (min-height: 950px) {
    .card__body { padding: 16px 18px; }
    .table td, .table th { padding: 9px 12px; }
}

/* Un tableau ne pousse jamais la page : il défile dans son cadre, et
   l'en-tête reste lisible pendant qu'on parcourt les lignes. */
.table-wrap { overflow-x: auto; }
.table-wrap > .table { min-width: 100%; }

/* Liste de famille dans le tableau : discrète, elle ne doit pas concurrencer
   la désignation. Un liseré vert confirme l'enregistrement. */
.famsel { padding: 3px 7px; font-size: 12px; max-width: 190px; border-color: transparent; background: transparent; }
.famsel:hover { border-color: var(--line); background: var(--card); }
.famsel.is-saved { border-color: var(--signal); background: var(--signal-bg); }

/* Régime de TVA : il décide de la facture, donc il se lit de loin.
   Deux teintes franches — les confondre coûte devant le comptable. */
.vatbadge {
    display: inline-flex;
    align-items: center;
    min-width: 34px;
    height: 18px;
    padding: 0 6px;
    margin-left: 4px;
    border-radius: 5px;
    border: 1px solid;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: .03em;
    vertical-align: middle;
}
.vatbadge--tva   { background: var(--info-bg);   border-color: var(--cyan);  color: var(--cyan); }
.vatbadge--marge { background: #F3EAFB;          border-color: #8B5CF6;      color: #6D28D9; }
.vatbadge--export {
    background: var(--wait-bg);
    border-color: var(--wait);
    color: var(--wait);
}
.vatbadge--mixte { background: var(--wait-bg);   border-color: var(--wait);  color: #6A4B00; }

/* Choix du régime : deux vignettes, la teinte du badge correspondant. */
.vatpick { display: flex; gap: 6px; margin-top: 3px; }
.vatpick__item {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 11px;
    border: 1px solid var(--line);
    border-radius: 8px;
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
}
.vatpick__item--tva:has(input:checked)   { border-color: var(--cyan); background: var(--info-bg); }
.vatpick__item--marge:has(input:checked) { border-color: #8B5CF6;     background: #F3EAFB; }

/* Un raccourci portant un badge : le badge garde sa couleur propre, le
   bouton reste sobre — deux teintes qui se disputent ne se lisent plus. */
.stockshort__item .vatbadge { margin-left: 5px; }

/* Correction de stock sur la ligne : trois champs serrés, pour qu'un
   inventaire se fasse sans quitter le tableau. */
.stockadj { display: flex; gap: 4px; align-items: center; margin: 0; }
.stockadj .input { padding: 3px 7px; font-size: 12px; }
.stockadj select { max-width: 82px; }
.stockadj input[type="number"] { max-width: 62px; text-align: center; }
.stockadj input[type="text"] { max-width: 170px; }
.qty--off { opacity: .5; }

/* Un avertissement qui porte sur des données, non sur un geste : il reste
   à l'écran tant que l'écart n'est pas régularisé. */
.callout {
    padding: 9px 12px;
    border-radius: 8px;
    border: 1px solid var(--line);
    margin: 0;
    font-size: 13px;
    line-height: 1.45;
}
.callout--stop { border-color: var(--stop); background: var(--stop-bg); }

/* Onglets : trois chemins distincts pour un même geste. L'onglet actif porte
   la couleur, les autres restent sobres — deux teintes vives se disputent. */
.tabs { display: flex; gap: 4px; flex-wrap: wrap; }
.tabs__item {
    padding: 7px 16px;
    border: 1px solid var(--line);
    border-radius: 8px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-dim);
    background: var(--card);
    text-decoration: none;
}
.tabs__item:hover { border-color: var(--cyan); color: var(--cyan); text-decoration: none; }
.tabs__item.is-selected {
    background: var(--info-bg);
    border-color: var(--cyan);
    color: var(--cyan);
}

/* Un numéro de facture attribué par l'application : il se lit, ne se saisit
   pas. Le monospace le distingue d'un texte libre. */
.invoicenum {
    margin: 0;
    padding: 6px 10px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--paper);
    font-family: var(--mono);
    font-size: 13px;
    font-weight: 700;
}

/* =============================================================================
   La facture
   -----------------------------------------------------------------------------
   Même disposition que le modèle papier. Elle s'imprime depuis le navigateur :
   pas de générateur PDF à maintenir, et l'écran montre exactement ce qui
   sortira.
   ========================================================================== */
/* La facture occupe la hauteur d'une page A4 : le pied se colle en bas meme
   avec une seule ligne. Sans cela, les mentions legales remontent contre le
   tableau et la page parait inachevee. */
.invoice {
    max-width: 800px;
    min-height: 1050px;
    margin: 0 auto;
    padding: 24px;
    background: #FFF;
    border: 1px solid var(--line);
    border-radius: 10px;
    font-size: 12.5px;
    color: #111;
    display: flex;
    flex-direction: column;
}

/* Le pied se pose en bas, quelle que soit la longueur du tableau. */
.invoice__foot { margin-top: auto; }

/* La facture USA : le bas de page d'un bloc — le total, à droite et pas
   plus large que lui, juste au-dessus des mentions. */
.invoice__end { margin-top: auto; }
.invoice__totals--usa { width: auto; min-width: 300px; margin-left: auto; margin-bottom: 14px; }
.invoice__totals--usa th { white-space: nowrap; }
.invoice__usafoot { border-top: 1px solid #CBD5E0; padding-top: 10px; }

/* La facture USA : chaque colonne du tableau est centrée — en-têtes et
   valeurs, description comprise. */
.invoice__lines--usa th,
.invoice__lines--usa td { text-align: center; }
.invoice__top { display: flex; justify-content: space-between; gap: 24px; margin-bottom: 20px; }
/* Le logo porte un sous-titre en petits caracteres : trop reduit, il devient
   illisible a l'impression, ou l'on n'a pas le recours du zoom. */
.invoice__logo { max-height: 74px; max-width: 260px; margin-bottom: 10px; }
.invoice__name { margin: 0 0 2px; font-size: 13.5px; }
.invoice__line { margin: 0; line-height: 1.45; }
.invoice__meta { min-width: 320px; }
.invoice__title { margin: 0 0 10px; font-size: 30px; font-weight: 300; text-align: right; letter-spacing: .02em; }
.invoice__grid { width: 100%; border-collapse: collapse; }
.invoice__grid th, .invoice__grid td { border: 1px solid #CBD5E0; padding: 4px 8px; text-align: left; }
.invoice__grid th { background: #F4F6F8; font-size: 11.5px; width: 55%; }

.invoice__parties { display: flex; gap: 0; margin-bottom: 18px; }
.invoice__party { flex: 1; border: 1px solid #CBD5E0; padding: 8px 10px; }
.invoice__party + .invoice__party { border-left: 0; }
.invoice__partyhead { margin: 0 0 6px; font-weight: 700; font-size: 11.5px; }

.invoice__lines { width: 100%; border-collapse: collapse; margin-bottom: 18px; }
.invoice__lines th { background: #E8ECF0; padding: 6px 8px; font-size: 11.5px; }
.invoice__lines td { padding: 6px 8px; border-bottom: 1px solid #EDF1F5; }
.invoice__warn { color: #B45309; font-size: 11px; }

.invoice__totals { width: 100%; border-collapse: collapse; margin-bottom: 12px; }
/* Les montants a droite, comme sur toute facture : les unites s'alignent et
   deux totaux se comparent d'un coup d'oeil. La colonne « Code » suit, pour
   que chaque valeur reste sous son en-tete. */
.invoice__totals th,
.invoice__totals td { padding: 5px 8px; text-align: right; }
.invoice__totals th { background: #E8ECF0; font-size: 11px; }
.invoice__totals td { border-bottom: 1px solid #EDF1F5; }

.invoice__legal { margin: 6px 0 0; font-size: 10.5px; color: #444; line-height: 1.5; text-align: center; }
.invoice__legal--strong { font-weight: 700; color: #111; }
.invoice__actions { max-width: 800px; margin: 14px auto 0; display: flex; gap: 8px; }

/* À l'impression, seule la facture sort : ni menu, ni boutons. */
@media print {
    /* Sans cette regle, le navigateur economise l'encre : il ecarte les fonds
       et les images, logo compris. Sur une facture, le logo fait partie de
       l'identite de l'entreprise et doit sortir. */
    * {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    .nav, .topbar, .noprint, .flash { display: none !important; }
    .shell, .main { display: block; padding: 0; }
    /* Des marges declarees plutot que celles du navigateur : sans elles, le
       bord droit se decoupe et l'IBAN sort de la feuille. */
    @page {
        size: A4 portrait;
        /* Quinze millimetres a droite : dix ne suffisaient pas, l'IBAN et la
           colonne « TVA » se decoupaient encore. Les imprimantes reservent
           une marge physique que la declaration ne couvre pas toujours. */
        margin: 12mm 15mm;
    }

    .invoice {
        /* Une marge interieure plutot qu'une largeur reduite : « max-width »
           laissait les cellules de tableau coller au bord, et la derniere
           lettre du BIC comme la premiere de la reference s'y decoupaient.
           Le retrait s'applique au contenu, cellules comprises. */
        max-width: none;
        border: 0;
        border-radius: 0;
        padding: 0 4mm;
        /* La hauteur de la zone imprimable : le pied touche le bas de la
           feuille, pas celui d'un cadre a l'ecran. */
        min-height: 25cm;
        /* Un point de moins : sur une A4 moins ses marges, la largeur utile
           tombe a 180 mm et les colonnes de droite y tenaient tout juste. */
        font-size: 11px;

        /* La largeur bornee : sans elle, un tableau large deborde de la zone
           imprimable au lieu de se resserrer. */
        width: 100%;
        max-width: 180mm;
        overflow: hidden;
    }

    /* Les tableaux se resserrent au lieu de deborder. */
    .invoice table {
        width: 100%;
        table-layout: fixed;
    }

    .invoice td,
    .invoice th {
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* L'IBAN ne se coupe pas : il se replie sous la banque si besoin. */
    .invoice__bank { word-break: break-word; }

    /* Rien ne depasse : une cellule trop large replie son contenu au lieu de
       pousser le tableau hors de la feuille. */
    .invoice table { table-layout: auto; width: 100%; }
    .invoice__bank { word-break: break-all; }
    body { background: #FFF; }
}

/* Le bouton de création pousse à droite des onglets : il ne fait pas partie
   du choix, il ouvre autre chose. */
.tabs__spacer { flex: 1 1 auto; }

/* Les coordonnees bancaires : c'est ce que le client cherche pour payer. */
/* Les coordonnees bancaires sous « Net a payer » : c'est le montant qu'on
   vient de lire, et le compte ou le verser se trouve juste dessous. */
.invoice__bank {
    margin: 10px 0 6px;
    text-align: right;
    font-size: 11.5px;
    color: #111;
}
/* L'IBAN ne se coupe pas au milieu — un numero de compte tronque ne se
   recopie pas — mais la ligne entiere peut passer a la suivante. */
.invoice__iban {
    font-family: var(--mono);
    font-weight: 700;
    margin: 0 6px;
    white-space: nowrap;
}
.invoice__bank { word-spacing: normal; overflow-wrap: break-word; }
.invoice__page { margin: 14px 0 0; text-align: right; font-size: 10.5px; color: #666; }

/* La mention de TVA sur marge : encadree, car c'est elle qui rend la facture
   reguliere. Noyee dans le pied de page, un controleur la cherche. */
.invoice__margenote {
    margin: 10px 0 8px;
    padding: 8px 12px;
    border: 1px solid #333;
    border-radius: 4px;
    font-size: 11.5px;
    font-weight: 700;
    color: #111;
    text-align: center;
}

/* =============================================================================
   Boutons de ligne — écran de vente
   -----------------------------------------------------------------------------
   Une grille à cinq colonnes fixes, une par geste. Chaque bouton occupe sa
   place, qu'elle soit remplie ou non : une vente facturée n'a ni « Reprendre »
   ni « Supprimer », mais ses trois boutons restent sous ceux de la ligne du
   dessus.
   ========================================================================== */
.saleactions {
    /* « inline-grid » garde la cellule a sa taille : en « grid », elle
       s'etalait sur toute la ligne et recouvrait les colonnes voisines. */
    display: inline-grid;
    /* Sept places : Rouvrir, Ouvrir, Facture, Detail, Copier, Excel,
       Supprimer. Chacune tient sa colonne, occupee ou non. */
    grid-template-columns: repeat(6, 88px);
    gap: 5px;
    align-items: center;
}

/* Une place, occupee ou vide : c'est elle qui tient la colonne. */
.saleactions__slot { display: flex; }

/* Le formulaire ne compte pas dans la grille : seul son bouton s'y range. */
.saleactions form { display: contents; }

.saleactions .chipbtn {
    justify-content: center;
    width: 100%;
    white-space: nowrap;
}
.saleactions .chipbtn { white-space: nowrap; }


/* =============================================================================
   Poste de vente — deux colonnes
   -----------------------------------------------------------------------------
   Le scan a gauche, le recapitulatif chiffre a droite. On voit la quantite
   monter et l'on pose le prix sans changer d'ecran : le geste de scan et
   celui de chiffrage se repondent.
   ========================================================================== */
.salepost {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(320px, 1fr);
    gap: 12px;
    align-items: start;
}

.salepost__scan,
.salepost__prix { margin: 0; }

/* Le recapitulatif suit le defilement : sur un lot de cinquante appareils,
   la liste de scan devient longue et les prix sortiraient de l'ecran. */
.salepost__prix { position: sticky; top: 12px; }

/* En dessous de 1100 px, les deux colonnes s'empilent : cote a cote, chacune
   deviendrait trop etroite pour son tableau. */
@media (max-width: 1100px) {
    .salepost { grid-template-columns: minmax(0, 1fr); }
    .salepost__prix { position: static; }
}

/* Le total du recapitulatif : c'est le montant de la facture, il se lit d'un
   coup d'oeil sans additionner les lignes. */
.recaptotal {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    border-top: 2px solid var(--line);
    background: var(--paper);
}
.recaptotal__label {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-dim);
}
.recaptotal__value { font-size: 18px; font-weight: 700; font-family: var(--mono); }

/* Les choix d'une vente, en tete et en petit : ils se revisent sans quitter
   l'ecran de scan. */
.salehead { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; margin: 0; }
.salehead__field { display: flex; flex-direction: column; gap: 3px; min-width: 150px; }
.salehead__field--wide { flex: 1 1 240px; }
.salehead__field > span {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--text-dim);
}
.salehead .input { padding: 4px 8px; font-size: 12.5px; }

/* Les gestes du bac en face de la testeuse : on choisit qui teste et l'on
   confie dans le meme mouvement, sans faire defiler la liste des scans. */
.binaction--inline {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--line);
}
.binaction--inline .btn { min-width: 0; }

/* Trois imports cote a cote : ajouter, retirer, chiffrer. Empiles, ils
   repoussaient la liste hors de l'ecran. */
.impbar { display: flex; flex-direction: column; gap: 8px; }

/* =============================================================================
   Aide de l'ecran
   -----------------------------------------------------------------------------
   Un bouton discret en tete de page, un panneau de questions repliees. Tout
   afficher ferait un mur de texte qu'on ne lit pas ; replie, on ouvre celle
   qui nous occupe.
   ========================================================================== */
/* Le bouton flottant : en bas a droite, il ne gene aucun tableau et reste
   atteignable sans remonter la page. Le libelle n'apparait qu'au survol :
   un rond seul intrigue, un rond qui s'explique rassure. */
.helpfab {
    position: fixed;
    right: 18px;
    bottom: 18px;
    z-index: 60;
    display: flex;
    align-items: center;
    gap: 0;
    height: 42px;
    padding: 0 13px;
    border-radius: 999px;
    border: 1px solid var(--line);
    background: var(--card);
    box-shadow: 0 3px 14px rgba(16, 32, 48, .16);
    color: var(--text-dim);
    font-size: 16px;
    font-weight: 700;
    cursor: pointer;
    transition: gap .16s ease, color .16s ease, border-color .16s ease;
}
.helpfab:hover {
    gap: 7px;
    border-color: var(--cyan);
    color: var(--cyan);
}
.helpfab__label {
    max-width: 0;
    overflow: hidden;
    font-size: 13px;
    white-space: nowrap;
    transition: max-width .16s ease;
}
.helpfab:hover .helpfab__label { max-width: 60px; }

.helpitem {
    border-bottom: 1px solid var(--line);
    padding: 2px 0;
}
.helpitem > summary {
    padding: 9px 4px;
    cursor: pointer;
    font-weight: 600;
    font-size: 13.5px;
    list-style: none;
}
.helpitem > summary::before {
    content: '+';
    display: inline-block;
    width: 16px;
    color: var(--cyan);
    font-weight: 700;
}
.helpitem[open] > summary::before { content: '−'; }
.helpitem > summary::-webkit-details-marker { display: none; }

.helpitem__answer {
    margin: 0 0 12px;
    padding: 0 4px 0 20px;
    font-size: 13px;
    line-height: 1.6;
    color: var(--text-dim);
}

/* Le cycle d'un appareil : un schema vaut mieux qu'un paragraphe pour dire ou
   va quoi. Il se replie sur les petits ecrans plutot que de deborder. */
.helpflow {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    padding: 14px 4px 14px 20px;
    font-size: 12px;
}
.helpflow__step {
    padding: 5px 11px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper);
    white-space: nowrap;
}
.helpflow__step--ok { border-color: var(--go); background: var(--go-bg); }
.helpflow__step--stop { border-color: var(--stop); background: var(--stop-bg); }
.helpflow__arrow { color: var(--text-dim); }

.helpflow__branch { display: flex; flex-direction: column; gap: 6px; }
.helpflow__line { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.helpflow__label {
    min-width: 84px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--text-dim);
}

/* =============================================================================
   Service apres-vente
   -----------------------------------------------------------------------------
   La fiche du retour : ce que l'application sait deja du client et de son
   adresse. On lit, on ne ressaisit pas — retaper une adresse a chaque retour
   fait des erreurs sur les colis.
   ========================================================================== */
.savsheet { border-top: 1px solid var(--line); }

.savsheet__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 12px;
    margin-bottom: 12px;
}
.savsheet__field { display: flex; flex-direction: column; gap: 2px; }
.savsheet__field--wide { grid-column: span 2; }
.savsheet__field > span:first-child {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--text-dim);
}
.savsheet__field strong { font-size: 14px; }

/* Le badge SAV : cet appareil appartient a un client. Il traverse les memes
   bacs que le stock, et le confondre ferait vendre deux fois le meme
   telephone. */
.savbadge {
    display: inline-block;
    margin-left: 4px;
    padding: 1px 6px;
    border-radius: 999px;
    background: #7C3AED;
    color: #FFF;
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: .04em;
    vertical-align: middle;
}

/* Le motif du client sur la fiche du technicien : le test dit ce qu'on a
   mesure, le client dit ce qu'il a vecu. Les deux se completent, et la
   couleur du SAV les distingue. */
.benchsav {
    display: block;
    margin-top: 4px;
    padding: 5px 9px;
    border-left: 3px solid #7C3AED;
    border-radius: 0 4px 4px 0;
    background: #F5F0FF;
    font-size: 12px;
    color: #3B2A63;
}
.benchsav strong { margin-right: 6px; font-family: var(--mono); font-size: 11px; }

/* Le SAV en surbrillance : un client attend son telephone, un appareil de
   stock attend un acheteur qui n'existe pas encore. La bordure gauche suffit
   a le reperer sans crier. */
.scanlist__item--sav {
    border-left: 3px solid #EF9F27;
    background: #FAEEDA;
    padding-left: 9px;
}
@media (prefers-color-scheme: dark) {
    .scanlist__item--sav { background: #412402; border-left-color: #FAC775; }
}
.grading__row--sav td { background: #FAEEDA; }
@media (prefers-color-scheme: dark) {
    .grading__row--sav td { background: #412402; }
}

/* Le badge d'ecart : cet appareil n'a pas ete vu au dernier inventaire. Il se
   leve au premier scan ordinaire. */
.gapbadge {
    display: inline-block;
    margin-left: 4px;
    padding: 1px 6px;
    border-radius: 999px;
    background: #A32D2D;
    color: #FFF;
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: .04em;
    vertical-align: middle;
}

/* Le depot en cours d'inventaire : visible en gros pendant tout le scan, pour
   qu'on ne se trompe pas de rayon. */
.invdepot { display: flex; align-items: flex-end; gap: 14px; margin: 0; }
.invdepot__now {
    padding: 5px 14px;
    border-radius: var(--radius);
    background: var(--go-bg);
    border: 1px solid var(--go);
    font-family: var(--mono);
    font-size: 15px;
    font-weight: 700;
    letter-spacing: .04em;
}

/* Les deux colonnes de l'inventaire : ce qu'on a scanne a gauche, ce qui
   reste a trouver a droite. La seconde se vide a mesure. */
.invcols {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    align-items: start;
}
.invcols__list { max-height: 460px; overflow-y: auto; }

@media (max-width: 1100px) {
    .invcols { grid-template-columns: minmax(0, 1fr); }
}

/* Les depots en cartes : on voit d'un coup ou il reste a passer, et combien.
   Une liste deroulante cacherait ce qui compte — le nombre restant. */
.invstores { display: flex; flex-wrap: wrap; gap: 8px; }

.invstore {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 132px;
    padding: 9px 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--card);
    text-decoration: none;
    color: inherit;
}
.invstore:hover { border-color: var(--cyan); }

.invstore--on { border-color: var(--go); background: var(--go-bg); border-width: 2px; }
.invstore--done { opacity: .55; }

.invstore__label { font-size: 12px; font-weight: 600; }
.invstore__rest { font-size: 21px; font-weight: 700; font-family: var(--mono); line-height: 1.1; }
.invstore--done .invstore__rest { color: var(--go); }
.invstore__total { font-size: 10.5px; color: var(--text-dim); }

/* Le bouton de legende, colle a la recherche : les badges se lisent partout,
   mais leur sens s'oublie. */
.badgebtn {
    padding: 5px 11px;
    border-radius: var(--radius);
    border: 1px solid var(--line);
    background: var(--card);
    color: var(--text-dim);
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
}
.badgebtn:hover { border-color: var(--cyan); color: var(--cyan); }

/* La legende : chaque badge en face de son sens. */
.badgelist { display: flex; flex-direction: column; gap: 2px; }
.badgelist__row {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 9px 4px;
    border-bottom: 1px solid var(--line);
    text-align: left;
    font-size: 13px;
    line-height: 1.6;
    color: var(--text-dim);
}
.badgelist__row:last-child { border-bottom: 0; }
.badgelist__row > span:last-child { flex: 1; }

/* Ce que l'appareil a connu avant de partir chez le client : une panne qui
   revient apres reparation n'est pas la meme chose qu'une panne neuve. */
.savpast {
    margin: 10px 0 12px;
    padding: 10px 12px;
    border-left: 3px solid #EF9F27;
    border-radius: 0 var(--radius) var(--radius) 0;
    background: #FAEEDA;
}
@media (prefers-color-scheme: dark) {
    .savpast { background: #412402; }
}
.savpast__block + .savpast__block { margin-top: 9px; }
.savpast__title {
    display: block;
    margin-bottom: 4px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: #854F0B;
}
@media (prefers-color-scheme: dark) {
    .savpast__title { color: #FAC775; }
}
.savpast__body { display: flex; flex-wrap: wrap; gap: 4px; }
.savpast__line { margin: 0; font-size: 12.5px; line-height: 1.6; }

/* La coupure du retour SAV : ce qui est au-dessus appartient au dossier, ce
   qui est en dessous a sa vie d'avant. */
.savsplit td {
    padding: 7px 10px;
    background: #F5F0FF;
    border-top: 2px solid #7C3AED;
    border-bottom: 1px solid #7C3AED;
    font-size: 11.5px;
    font-weight: 700;
    color: #3B2A63;
    text-align: center;
}
@media (prefers-color-scheme: dark) {
    .savsplit td { background: #26215C; color: #CECBF6; }
}
.savold td { opacity: .68; }

/* Les lignes qui portent le travail reel : ce qu'on a fait a l'appareil, pas
   ou il est alle. Une bordure gauche suffit a les distinguer sans crier. */
.savkey td:first-child { border-left: 3px solid transparent; }
.savkey td { font-weight: 500; }

.savkey--fix td:first-child { border-left-color: #D85A30; }
.savkey--fix td { background: #FAECE7; }

.savkey--tech td:first-child { border-left-color: #EF9F27; }
.savkey--tech td { background: #FAEEDA; }

.savkey--test td:first-child { border-left-color: #1D9E75; }
.savkey--test td { background: #E1F5EE; }

.savkey--ext td:first-child { border-left-color: #378ADD; }
.savkey--ext td { background: #E6F1FB; }

@media (prefers-color-scheme: dark) {
    .savkey--fix td  { background: #4A1B0C; }
    .savkey--tech td { background: #412402; }
    .savkey--test td { background: #04342C; }
    .savkey--ext td  { background: #042C53; }
}

/* La legende des couleurs : sans elle, on voit des lignes colorees sans
   savoir ce qu'elles distinguent. */
.savlegend { display: flex; flex-wrap: wrap; gap: 5px; }
.savlegend__item {
    padding: 2px 9px;
    border-left: 3px solid;
    border-radius: 0 3px 3px 0;
    font-size: 11px;
    font-weight: 600;
}
.savlegend__item--tech { border-color: #EF9F27; background: #FAEEDA; color: #854F0B; }
.savlegend__item--fix  { border-color: #D85A30; background: #FAECE7; color: #993C1D; }
.savlegend__item--test { border-color: #1D9E75; background: #E1F5EE; color: #0F6E56; }
.savlegend__item--ext  { border-color: #378ADD; background: #E6F1FB; color: #185FA5; }

@media (prefers-color-scheme: dark) {
    .savlegend__item--tech { background: #412402; color: #FAC775; }
    .savlegend__item--fix  { background: #4A1B0C; color: #F5C4B3; }
    .savlegend__item--test { background: #04342C; color: #9FE1CB; }
    .savlegend__item--ext  { background: #042C53; color: #B5D4F4; }
}

/* Les deux gestes d'une ligne de technicien : cote a cote, dans une colonne
   qui ne pousse pas le tableau hors de l'ecran. */
.techacts { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }

/* Le retrait d'un technicien reste visible : cette liste sert justement a
   corriger une attribution, et cacher le geste jusqu'au survol le rendrait
   introuvable pour qui vient le chercher. */
.table tbody tr .techacts .chipbtn--danger { opacity: 1; margin-left: 0; }

/* Un en-tete qu'on peut trier : la fleche dit dans quel sens, le curseur dit
   qu'on peut cliquer. */
.sortable { cursor: pointer; user-select: none; }
.sortable:hover { color: var(--cyan); }
.sortable__mark { font-size: 9px; opacity: .55; }

/* Le choix actif dans une barre de filtres : sans marque, on ne sait plus ce
   qu'on regarde apres deux clics. */
.chipbtn--on {
    border-color: var(--go);
    background: var(--go-bg);
    color: var(--go);
    font-weight: 700;
}

/* Un bloc repliable qui a l'air d'un bouton : replie, un simple titre ne dit
   pas qu'on peut cliquer dessus. */
.foldbtn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 7px 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--card);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    list-style: none;
}
.foldbtn::-webkit-details-marker { display: none; }
.foldbtn:hover { border-color: var(--cyan); color: var(--cyan); }
.foldbtn::before { content: '▸'; font-size: 10px; opacity: .6; }
details[open] > .foldbtn::before { content: '▾'; }

/* La batterie en mode serie : comme les autres modes, elle ne se colore
   qu'une fois cochee. Un fond pose d'emblee effacait son libelle. */
.serialmode--batt:has(input:checked) { background: var(--cyan); color: #FFF; }

/* La barre du mode batterie : meme traitement que le mode jaune — fond
   franc, champ clair, libelles lisibles. Un simple fond colore laissait le
   texte se noyer dedans. */
.scanbar--serie-batt {
    background: linear-gradient(180deg, #16B5D0 0%, #0E8FA6 100%);
    box-shadow: 0 0 0 3px rgba(22, 181, 208, 0.32);
}
.scanbar--serie-batt .scanbar__label { color: #04333C; }
.scanbar--serie-batt .scanbar__input {
    background: rgba(255, 255, 255, 0.94);
    color: #04333C;
}
.scanbar--serie-batt .serialmode { border-color: rgba(0, 0, 0, 0.25); color: #04333C; }

/* Le badge de batterie pleine : seuls les 100% sont marques, puisque c'est ce
   qui change le produit vendu. */
.battbadge {
    display: inline-block;
    margin-left: 4px;
    padding: 1px 6px;
    border-radius: 999px;
    background: #1D9E75;
    color: #FFF;
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: .02em;
    vertical-align: middle;
}

/* Deux boutons colles : le meme geste, avec ou sans la batterie pleine. Les
   separer laisserait croire a deux actions sans rapport. */
.btnpair { display: inline-flex; }
.btnpair > .btn:first-child { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.btnpair > .btn:last-child  { border-top-left-radius: 0; border-bottom-left-radius: 0; margin-left: -1px; }

/* Le cyan du theme : il se distingue du vert voisin sans sortir de la
   palette. Meme taille que son jumeau — deux boutons de tailles differentes
   se liraient comme deux actions d'importance inegale. */
.btn--batt {
    background: var(--cyan);
    border-color: var(--cyan);
    color: #FFF;
}
.btn--batt:hover { background: var(--cyan-vivid); border-color: var(--cyan-vivid); }

/* Un champ refuse : le rouge dit qu'il faut relire avant de rescanner. */
.input--stop {
    border-color: var(--alert);
    background: var(--alert-bg);
}

/* Le motif du refus, sous le champ : on scanne les suivants sans avoir a
   fermer une fenetre. */
.field__hint--stop {
    margin: 4px 0 0;
    color: var(--alert);
    font-weight: 600;
    max-width: 220px;
}

/* Une commande qu'il reste a servir : le fond jaune la distingue de celles
   qui attendent seulement leur facture. */
.row--todo > td { background: #FDF6DC; }
.row--todo:hover > td { background: #FAEDC2; }

/* Le numero de suivi, en gros : on le relit a distance pour le rapprocher de
   l'etiquette collee sur le carton. */
.tracking {
    display: inline-block;
    padding: 3px 8px;
    border-radius: var(--radius);
    background: var(--card-alt);
    font-family: var(--mono);
    font-size: 15px;
    font-weight: 700;
    letter-spacing: .04em;
    color: var(--ink);
}

/* Les prestations cochees sur une ligne d'envoi : plusieurs par appareil, en
   ligne pour ne pas etirer la liste. */
.worklist { display: inline-flex; flex-wrap: wrap; gap: 4px; margin-left: 8px; }
.worklist.is-saved { outline: 2px solid var(--signal); outline-offset: 2px; border-radius: var(--radius); }

.workchip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--card);
    font-size: 11.5px;
    cursor: pointer;
}
.workchip:has(input:checked) {
    border-color: var(--cyan);
    background: var(--cyan);
    color: #FFF;
    font-weight: 600;
}
.workchip input { margin: 0; }

/* Le mode serie des prestations : cyan comme le reste du module, distinct des
   modes du bac de test. */
.serialmode--tech:has(input:checked) { background: var(--cyan); color: #FFF; }

/* Une prestation deja demandee, en lecture : on la relit sans pouvoir la
   changer par megarde. Le choix se fait au scan. */
.workchip--fait { border-color: var(--cyan); background: var(--cyan-bg); color: var(--cyan); font-weight: 600; }

/* La colonne ou la douchette ecrira : deux champs de scan cote a cote, on
   doit voir lequel est actif avant de scanner. */
.scancol--actif { box-shadow: 0 0 0 2px var(--cyan); }
.scancol--actif .scanbar { background: linear-gradient(180deg, #0B2A3A, #123B4F); }

/* Un trait entre deux appareils : on lit d'un coup ce qui a ete pose sur
   celui qu'on cherche. */
.row--sep > td { border-top: 2px solid var(--line); }

/* Une piece posee dans la liste d'un appareil : plusieurs se suivent, un
   filet les separe sans les eloigner. */
.posee { padding: 3px 0; }
.posee + .posee { border-top: 1px dashed var(--line); }

/* ============================================================================
   ETIQUETTE DYMO 30320 — 89 × 28 mm

   L'etiquette d'adresse : longue et fine. Le code-barres profite de la
   largeur, les lignes se resserrent en hauteur.

   L'impression passe par le navigateur : la DYMO s'y declare comme une
   imprimante ordinaire.
   ========================================================================= */

.etiquette {
    /* Les dimensions viennent du format choisi : chaque rouleau DYMO a les
       siennes, posees a la volee. */
    padding: 1mm 2mm;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    background: #FFF;
    color: #000;
    font-family: var(--sans);
    text-align: center;
}

.etiquette--apercu { border: 1px dashed var(--line); }

.etiquette__sku {
    font-size: 9pt;
    font-weight: 700;
    font-family: var(--mono);
    letter-spacing: .01em;
    line-height: 1.05;
}

.etiquette__desi {
    font-size: 6.5pt;
    line-height: 1;
}

/* Le code-barres se centre plutot que de s'etirer : etire, ses barres
   deviennent trop larges et l'etiquette perd sa place pour le texte. */
/* Le code-barres garde sa taille : etire, ses barres se deforment legerement
   et la douchette hesite. Il est genere a la bonne largeur. */
.etiquette__code { display: block; flex: 0 1 auto; min-width: 0; text-align: center; }
.etiquette__code svg { max-width: 100%; height: auto; display: block; }

.etiquette__imei {
    font-size: 8pt;
    font-family: var(--mono);
    letter-spacing: .08em;
}

/* A l'ecran, seule la version d'apercu se montre. */
.etiquette--print { display: none; }

@media print {
    /* Seule l'etiquette sort : le reste de l'ecran n'a rien a faire sur un
       rouleau de 89 mm.

       L'etiquette vit au fond de la mise en page, pas en enfant de « body » :
       masquer les enfants directs l'emportait avec le reste. On vide donc la
       page, puis on la ressort en position absolue.

       Le tout SCOPE a la presence d'une etiquette : ces regles globales
       vidaient AUSSI la facture a l'impression — page blanche, PDF vide.
       Sans etiquette sur la page, rien d'ici ne s'applique. */
    body:has(.etiquette--print) * { visibility: hidden !important; }

    body:has(.etiquette--print) .etiquette--print,
    body:has(.etiquette--print) .etiquette--print * { visibility: visible !important; }

    /* Les deux modeles sont rendus ; seul celui que le script a marque sort. */
    .etiquette--print { display: none !important; }

    .etiquette--print[data-actif="1"] {
        display: flex !important;
        position: absolute !important;
        top: 0;
        left: 0;

        /* Les dimensions se redisent : « absolute » les fait retomber a zero
           si elles ne sont pas reaffirmees ici. */

        margin: 0;
        border: 0;
        page-break-after: always;
    }

    /* Rien d'autre ne doit pousser l'etiquette hors de la page. */
    html:has(.etiquette--print),
    body:has(.etiquette--print) {
        margin: 0 !important;
        padding: 0 !important;
        background: #FFF !important;
    }

    /* La taille de page et la marge zero de l'etiquette vivent dans la
       balise style de l'ecran des etiquettes, posee avec le format choisi :
       « @page » ne se scope pas, et le declarer ici ecrasait les marges de
       la facture sur toutes les pages. */
}


/* Les quatre modeles cote a cote : on choisit en voyant, pas en lisant un
   intitule. */
.etiquettes {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    justify-content: center;
}

.etiquette__lien {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    padding: 6px;
    border: 2px solid transparent;
    border-radius: var(--radius);
    text-decoration: none;
}
.etiquette__lien:hover { border-color: var(--line); }
.etiquette__lien.is-choisi { border-color: var(--cyan); background: var(--cyan-bg); }



/* « IMEI : » a gauche du code-barres : l'intitule dit ce que sont ces barres,
   sans prendre une ligne entiere. */
.etiquette__bloc {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2mm;
    width: 100%;
}

.etiquette__label {
    font-size: 7pt;
    font-weight: 700;
    letter-spacing: .04em;
    white-space: nowrap;
}

/* Le double code : deux codes-barres, l'un sous l'autre. Les lignes se
   resserrent pour que les deux tiennent. */
.etiquette--double .etiquette__sku { font-size: 8pt; }

.etiquette--double .etiquette__imei { font-size: 7pt; letter-spacing: .04em; }
.etiquette--double .etiquette__bloc { gap: 1.5mm; }
.etiquette--double .etiquette__label { font-size: 6pt; }

/* Les petits rouleaux : moins de 22 mm de haut, tout se resserre. Sans cela
   le texte deborde et l'etiquette sort tronquee. */
.etiquette--court { padding: 1mm 2mm; }
.etiquette--court .etiquette__sku { font-size: 7pt; }
.etiquette--court .etiquette__desi { font-size: 5.5pt; }
.etiquette--court .etiquette__label { font-size: 5pt; }
.etiquette--court .etiquette__imei { font-size: 6pt; letter-spacing: .02em; }
.etiquette--court .etiquette__bloc { gap: 1mm; }

/* Ce qu'une colonne compte, sous son intitule : « attente » et « reparation »
   se confondent sans un mot d'explication. */
.colhint {
    display: block;
    margin-top: 1px;
    font-size: 9.5px;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    color: var(--muted);
    line-height: 1.15;
}

/* Un bouton qui efface se voit avant d'etre survole : le rouge previent, il
   ne recompense pas la curiosite. */
.chipbtn--danger {
    border-color: var(--alert);
    color: var(--alert);
    font-weight: 600;
}
.chipbtn--danger:hover { background: var(--alert); color: #FFF; }

/* Une perte se lit en rouge : un chiffre negatif se rate trop facilement en
   parcourant une colonne. */
.text--alert { color: var(--alert); }

/* ---- Les cartes du tableau de bord ------------------------------------- */

/* Un chiffre par carte : le gerant lit les totaux d'un regard, avant de
   descendre dans le detail. */
.statgrid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 10px;
}

/* La puce de tendance : le chiffre d'abord, la nouvelle en petit a cote.
   Vert quand ca va dans le bon sens, rouge sinon — et c'est tout, pas de
   troisieme couleur a interpreter. */
.tendance {
    display: inline-block;
    margin-left: 8px;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 600;
    vertical-align: middle;
}
.tendance--bon     { background: var(--signal-bg); color: #35590A; }

/* Le raccourci de periode choisi : on voit d'un coup d'oeil sur quoi on
   regarde les chiffres. */
.chipbtn.is-choisi { border-color: var(--cyan); background: var(--cyan-bg); font-weight: 700; }

/* Le prix par modele, deplie dans la cellule : la fourchette resume, le
   detail dit qui coute quoi — un ecran d'iPhone 11 n'est pas celui d'un 14. */
.prixfold summary {
    cursor: pointer;
    list-style: none;
    text-decoration: underline dotted;
    text-underline-offset: 3px;
}
.prixfold summary::-webkit-details-marker { display: none; }
.prixfold__liste {
    margin: 6px 0 2px;
    padding: 6px 8px;
    list-style: none;
    text-align: left;
    background: var(--card-2);
    border: 1px solid var(--line);
    border-radius: 6px;
    font-size: 12px;
    min-width: 190px;
}
.prixfold__liste li {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 2px 0;
}
.tendance--mauvais { background: var(--alert-bg); color: var(--alert); }

.statcard {
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 12px 14px;
    background: var(--card);
}

.statcard__nombre {
    font-size: 26px;
    font-weight: 800;
    color: var(--cyan);
    line-height: 1.1;
}

.statcard__libelle {
    font-size: 12.5px;
    font-weight: 600;
    margin-top: 3px;
}

.statcard__detail {
    font-size: 11px;
    color: var(--muted, #6B7C8A);
    margin-top: 2px;
}

/* ---- La couleur des volets du tableau de bord --------------------------- */

/* Une couleur par volet : l'oeil retrouve l'onglet avant de lire son nom.
   La pastille est toujours visible ; l'onglet choisi prend sa couleur en
   fond clair et en bordure. */

.tabs__item { position: relative; padding-left: 22px; }

.tabs__item::before {
    content: '';
    position: absolute;
    left: 9px;
    top: 50%;
    transform: translateY(-50%);
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--pastille, #9AA8B4);
}

.tabs__item--performance   { --pastille: #0E8FA6; }
.tabs__item--fournisseurs  { --pastille: #7C4DBE; }
.tabs__item--soustraitants { --pastille: #C97B1E; }
.tabs__item--stock         { --pastille: #46760A; }
.tabs__item--rentabilite   { --pastille: #B8860B; }
.tabs__item--clients       { --pastille: #2563A8; }
.tabs__item--modeles       { --pastille: #6B7C8A; }

.tabs__item.is-selected {
    border-color: var(--pastille, var(--cyan));
    background: color-mix(in srgb, var(--pastille, #0E8FA6) 10%, #FFFFFF);
    color: #16323F;
}

/* Les cartes du volet portent la meme couleur, en filet gauche. */
.statcard { border-left: 3px solid var(--pastille-volet, var(--cyan)); }

.volet--performance   { --pastille-volet: #0E8FA6; }
.volet--fournisseurs  { --pastille-volet: #7C4DBE; }
.volet--soustraitants { --pastille-volet: #C97B1E; }
.volet--stock         { --pastille-volet: #46760A; }
.volet--rentabilite   { --pastille-volet: #B8860B; }
.volet--clients       { --pastille-volet: #2563A8; }
.volet--modeles       { --pastille-volet: #6B7C8A; }

/* Le rappel des colonnes d'import marketplace : replie par defaut, le
   preparateur l'ouvre la premiere fois puis n'en a plus besoin. */
.mkt-colonnes { margin: 10px 0 14px; }

.mkt-colonnes summary {
    cursor: pointer;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--cyan);
}

.mkt-colonnes code {
    font-family: var(--mono, monospace);
    font-size: 11.5px;
    background: #F0F4F6;
    padding: 1px 5px;
    border-radius: 4px;
}
