/* Quick filters on list pages — one factored look, identical to the /comptabilite
   period selector: each control carries its label ABOVE it (`.filter-sel` mirrors a
   `.field`), and the whole row bottom-aligns (`align-items: end`) so the labelled
   controls and the (full-height, not btn-sm) buttons sit on the same baseline. */
.filters { display: flex; gap: 16px; align-items: end; flex-wrap: wrap; margin: -2px 0 14px; }
.filter-sel { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
/* Weight the LABEL only (mirror of `.field > span`) — never the container, or the
   bold would cascade into the date/select value text (the « graisse » that made the
   filter dates look heavier than the comptabilite ones). */
.filter-sel > span { font-size: var(--fs-13); font-weight: var(--fw-semibold); color: var(--ink-2); }
.filter-sel select { width: auto; padding: 6px 10px; }
/* Date fields sized like the comptabilite period inputs (.field-sm) instead of the
   native intrinsic width, so every Du/Au box matches across the app. */
.filter-sel input[type="date"], .filter-period input[type="date"] { width: var(--field-sm); }
/* Period filter: the « Du »/« Au » words sit inline between the date boxes
   (`Du [date] Au [date]`) instead of stacked above, trimming the wasted vertical
   band the labelled layout left empty. */
.filter-period { display: flex; align-items: center; gap: 8px; }
.filter-period > span { font-size: var(--fs-13); font-weight: var(--fw-semibold); color: var(--ink-2); }
/* Match the combobox input's vertical padding (6px) so the box height lines up and
   the centered checkbox content sits on the input's vertical center, not its baseline. */
.filter-chk { display: flex; align-items: center; gap: 7px; padding: 6px 0; font-size: var(--fs-13); font-weight: var(--fw-normal); color: var(--ink-2); cursor: pointer; }
.filter-chk input { width: auto; }

.searchbar { display: flex; gap: 8px; margin-bottom: 14px; }
.searchbar input { max-width: 420px; }

/* quick stock movement form — stacked lines for readability:
   1) type + qté  2) motif  3) prix + validation */
.quick-move { display: flex; flex-direction: column; gap: 10px; }
.quick-move .qm-line { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.quick-move .qm-qty { flex: 1; min-width: 90px; }
.quick-move .price-free { flex: 1; min-width: 130px; }
.quick-move .qm-line .btn { margin-left: auto; }

/* selects/blocks sized to their content (e.g. price pickers), capped to width.
   Reusable across the app wherever a control should hug its text. */
.price-select, .w-content { width: auto; max-width: 100%; }
.line-form { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; padding-top: 16px; border-top: 1px solid var(--line); }
.line-form .field { margin: 0; }
/* Add-article block: hosted in a subblock panel at the top of the lines card, so
   it owns its own separation — drop the line-form's own top border/padding. */
.line-add { margin-bottom: 16px; }
/* « Ligne libre » nature bar (PLAN_NATURES_ARTICLES lot 2): quick-kind buttons + a
   nature <select>, above the add-line form. Dimmed (is-muted) while a product is chosen
   (its kind is inherited) — clicking a quick button clears the product and re-activates it. */
.line-kinds { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 10px; }
.line-kinds.is-muted { opacity: .5; }
.line-kinds .lk-label { color: var(--muted); font-size: .85em; margin-right: 2px; }
.line-kinds select { flex: 0 0 auto; max-width: 200px; }
/* One row when it fits: the Article field flexes to absorb the slack while the others
   keep fixed widths, and « + Ajouter » is pinned to the right edge (margin-left:auto) so
   its position never moves when fields toggle (Libellé hides / Tarif shows / PUHT hides).
   Wraps (not nowrap) so the inline catalogue-picker button + the pricing fields drop to a
   second line on a narrow viewport rather than crushing the Article field to nothing; the
   field keeps a usable min-width so it never collapses, and the picker button stays glued
   to its right. */
.line-add .line-form { padding-top: 0; border-top: 0; }
.line-add .line-form > .field { flex: 0 0 150px; min-width: 0; }
.line-add .line-form [data-lf-product] { flex: 1 1 220px; min-width: 200px; }
.line-add .line-form [data-lf-label],
.line-add .line-form [data-lf-tariff] { flex-basis: 190px; }
.line-add .line-form .field:has([data-qty]) { flex-basis: 56px; }
/* When a pack is active, Qté = « Conditionnement » × « Cartons » : driven by the form
   and locked read-only, so it reads as muted/non-editable rather than a normal input. */
.line-add .line-form input[data-qty][readonly] { background: #f4f4f5; color: var(--muted); cursor: not-allowed; }
/* « Conditionnement » (units per carton/lot) — wide enough for its label, narrower than
   the default 150px so it doesn't crowd the row. */
.line-add .line-form [data-lf-packfield] { flex: 0 0 124px; }
/* TVA select holds only « XX % » → as narrow as the value + caret. */
.line-add .line-form .field:has([name="vat_rate"]) { flex: 0 0 64px; }
.line-add .line-form [data-lf-price] { flex-basis: 110px; }
.line-add .line-form [data-lf-priceunit] { flex: 0 0 200px; }
/* Submit area pinned to the right edge so its position never moves as fields toggle. */
.line-add .line-form .line-add-actions,
.line-add .line-form button[type="submit"] { margin-left: auto; flex: 0 0 auto; }
/* No per-row height override: the shared --control-h pins every input/select/combo
   (global rule above) and every submit is a .btn (min-height: --control-h), so the
   whole add-line row sits at the one site-wide height and bottom-aligns by itself.
   Fused « Tarif / Prix » is a value-combobox (.combo + .combo-input = the € input);
   it inherits the combobox styles below — no dedicated rules needed. */
/* Add-line submit area (devis + commande, identical): the « Ajouter » gradient
   primary submit plus the optional speech-bubble « comment » submit. Only the comment
   is icon-only (.line-icon-btn): square, width = the shared control height. */
.line-add-actions { display: inline-flex; gap: 6px; align-items: flex-end; }
.line-icon-btn { flex: 0 0 auto; width: var(--control-h); padding: 0; font-size: var(--fs-16); line-height: 1; }
/* Catalogue-picker trigger docked right of the « Article » field: icon-only, the glyph
   filled with the brand gradient (Orchidée) via the mask (like .tile-ic .ic). */
.line-pick-btn .ic { width: 1.15em; height: 1.15em; background: var(--brand-grad); }
/* « Ajouter au catalogue » trigger inline in a free quote line's label cell: a small
   borderless icon button (orchid glyph via .line-pick-btn), quiet until hovered. Smaller
   than the form-row .line-icon-btn — it lives among text in a table row, not on a control row. */
.line-cat-btn { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; padding: 0; border: 0; border-radius: 6px; background: none; cursor: pointer; line-height: 1; }
.line-cat-btn:hover { background: var(--brand-wash); }
/* Article picker: fixed width — never grow into the space freed when the
   « Libellé » field hides on selection, nor stretch for a long label. */
.line-form [data-lf-product] { flex: 0 0 560px; max-width: 100%; }

/* Searchable comboboxes — one type-to-filter UI for every long choice list
   (clients, articles, fournisseurs, familles…). The native <select> stays as the
   form control but is hidden once enhanced; the .combo-input drives the search
   and the popup lists at most 5 suggestions. See app.js initCombobox. */
.combo { position: relative; display: block; width: 100%; }
.combo-native { display: none; }
.combo-input { width: 100%; text-overflow: ellipsis; }
/* Fixed (not absolute) so the popup escapes every scroll/overflow ancestor
   (table-wrap, inline-form card…) instead of being clipped inside its block —
   left/top/width are set from the input's viewport rect by app.js placeCombo. */
.combo-pop {
  position: fixed; z-index: 50;
  margin: 0; padding: 4px; list-style: none; background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-pop);
  max-height: 260px; overflow-y: auto;
}
.combo-pop[hidden] { display: none; }
.combo-opt { padding: 8px 10px; border-radius: 6px; cursor: pointer; font-size: var(--fs-14); }
.combo-opt:hover, .combo-opt.active { background: var(--brand-wash); }
/* info rows: empty / "refine" / floor hint / transient "Recherche…" loader (no spinner — chrome stays static) */
.combo-empty, .combo-more, .combo-loading { padding: 8px 10px; font-size: var(--fs-12); color: var(--muted); }
/* « Kit » marker on a kit suggestion in the article picker. */
.combo-tag { margin-left: 6px; padding: 1px 6px; border-radius: 6px; background: var(--info-wash); color: var(--info); font-size: var(--fs-11); vertical-align: middle; }
/* filters & line-form keep their content-hugging width on the combo too */
.filter-sel .combo, .line-form .price-select ~ .combo { width: auto; }
.filter-sel .combo-input { width: auto; min-width: 150px; padding: 6px 10px; }
/* Chip picker (product form « Équivalents / substituts ») : a remote combobox whose
   picks become removable pills. */
.chip-picker { display: flex; flex-direction: column; gap: 8px; }
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chips:empty { display: none; }
.chip-tag { display: inline-flex; align-items: center; gap: 6px; padding: 3px 5px 3px 11px;
  border: 1px solid var(--line); border-radius: 999px; background: var(--brand-wash);
  color: var(--ink); font-size: var(--fs-13); }
.chip-x { border: 0; background: none; cursor: pointer; color: var(--muted);
  font-size: var(--fs-15); line-height: 1; padding: 0 3px; border-radius: 999px; }
.chip-x:hover { color: var(--bad); }
.chip-picker .combo { max-width: 360px; }
.veh-form { display: flex; gap: 6px; margin-top: 10px; flex-wrap: wrap; }
.veh-form input { width: auto; flex: 1; min-width: 80px; }

/* compact inline date editor (order expected delivery) + reception inputs */
.inline-date { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.inline-date input { width: auto; margin: 0; }
.recv-table input[type=number] { width: 110px; margin: 0; }
/* supplier delivery-note (BL) capture above the reception lines */
.recv-bl { margin-bottom: 16px; }
/* avoir partiel: per-line credit quantities (same shape as .recv-table) */
.avoir-table input[type=number] { width: 110px; margin: 0; }
.avoir-table input[type=checkbox] { width: auto; margin: 0 6px 0 0; }
.kit-credit { display: inline-flex; align-items: center; white-space: nowrap; }

/* misc */
.empty { text-align: center; padding: 30px 20px; color: var(--muted); }
.empty p { margin-bottom: 14px; }
/* Ancre d'état vide (ui.emptyState {icon}) : glyphe du domaine en grand, teinté muet
   (couleur héritée via currentColor) et adouci → la zone vide est « habitée », pas nue. */
.empty-ic { margin-bottom: 14px; }
.empty-ic .ic { width: 40px; height: 40px; opacity: .55; }
/* in-context banner — used for errors (read where the action happened).
   Success/info feedback goes to bottom-right toasts instead. */
.flash { display: flex; align-items: center; gap: 9px; padding: 10px 16px; border-radius: var(--radius);
  margin-bottom: 14px; font-size: var(--fs-14); font-weight: var(--fw-medium); border-left: 4px solid transparent; }
.flash::before { font-size: var(--fs-15); line-height: 1; }
.flash-success { background: var(--ok-wash); color: var(--ok-d); border-left-color: var(--ok); }
.flash-success::before { content: "\2713"; }
.flash-error { background: var(--bad-wash); color: var(--bad-d); border-left-color: var(--bad); }
.flash-error::before { content: "\26A0"; }
.flash-info { background: var(--info-wash); color: var(--info); border-left-color: var(--info); }
.flash-info::before { content: "\2139"; }
.flash-warn { background: var(--warn-wash); color: var(--warn-d); border-left-color: var(--warn); }
.flash-warn::before { content: "\26A0"; }
.desc { margin-top: 10px; color: var(--muted); white-space: pre-wrap; }

/* auth */
/* Aizawa attractor hero behind the auth card (public/fx/aizawa.js): a fixed
   canvas paints its own deep-violet background + orbiting « Orchidée » glow,
   the white card floats above it. Fallback (no JS): the canvas stays dark. */
.fx-aizawa { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 0; display: block; background: #080410; }

/* Idle screen-saver overlay on app pages (public/app.js initVeille): after
   inactivity it covers everything (above sidebar/content/toasts/modal) with the
   same Aizawa attractor; the first gesture wakes it. Sits dark + transparent
   until armed, fades in on `.veille-on`, captures the wake gesture only then. */
.veille { position: fixed; inset: 0; z-index: 1000; background: #080410; opacity: 0; transition: opacity .4s ease; pointer-events: none; }
.veille[hidden] { display: none; }
.veille-on { opacity: 1; pointer-events: auto; }

body.centered { position: relative; }
body.centered .auth-box { position: relative; z-index: 1; box-shadow: 0 24px 60px rgba(8, 4, 16, 0.5); }
.auth-box { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius-card); padding: 28px; width: 360px; box-shadow: var(--shadow); }
.auth-box h2 { margin: 4px 0 6px; text-align: center; }
.auth-box p { text-align: center; }
.auth-box form { margin-top: 14px; display: flex; flex-direction: column; gap: 12px; }

/* pagination */
.pager { display: flex; gap: 12px; align-items: center; justify-content: center; margin-top: 16px; }

/* tab bar (sibling list views) */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); margin-bottom: 14px; flex-wrap: wrap; }
.tabs .tab { display: inline-flex; align-items: center; gap: 7px; padding: 8px 13px; color: var(--muted);
  border-bottom: 2px solid transparent; margin-bottom: -1px; font-size: var(--fs-14); font-weight: var(--fw-medium); }
.tabs .tab:hover { color: var(--ink); }
.tabs .tab.active { color: var(--brand-d); border-bottom-color: var(--brand); }
.tab-count { background: var(--chip); color: var(--muted); border-radius: 999px; padding: 1px 8px; font-size: var(--fs-12); font-weight: var(--fw-semibold); }
.tabs .tab.active .tab-count { background: var(--brand-wash); color: var(--brand-d); }

/* Inline add/confirm form: field(s) + submit on one row, button to the RIGHT of
   its field (design rule). Used app-wide (categories, RH, projets, factures
   fournisseur…). The submit is a direct flex child after the field, aligned to its
   bottom; greyed until valid via [data-gate]/.btn:disabled (app.js initGatedSubmit). */
.inline-add { display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap; }
.inline-add input { width: auto; flex: 1; min-width: 180px; }
.inline-add .field { margin: 0; min-width: 0; }
/* A sized field (.field-lg…) keeps its width; an unsized one falls back to 220px. */
.inline-add > .field:not([class*="field-"]) { flex: 0 1 220px; }
.inline-add.card { max-width: 640px; }

/* Block text selection / I-beam cursor on UI chrome; keep it where copy/typing matters */
body { -webkit-user-select: none; -ms-user-select: none; user-select: none; }
input, textarea, select, [contenteditable], td, code, pre {
  -webkit-user-select: text; -ms-user-select: text; user-select: text;
}

