/* matos-local.css — matos-only CSS that hasn't been lifted to shared.
 *
 * After Phase 2c (2026-06-20), this is the only matos-owned stylesheet.
 * Everything else loads through the three shared entry files
 * (shared-base / shared-desktop / shared-mobile).
 *
 * What lives here:
 *  - Tokens + base typography (matos-specific overrides on top of shared)
 *  - App-shell layout (grid, topbar, sidebar, main)
 *  - Button / badge / banner extensions
 *  - Container/location compositions (matos-specific entity chrome)
 *  - Label pipeline (label-batch, paper-stock picker, label preview)
 *  - Scanner sheet styles (.m-scanner, .m-viewfinder, .m-vf-*)
 *  - matos-specific install-prompt + bottom-sheet content layouts
 *  - Aperçu dashboard-specific layouts
 *  - Mobile shell (.m-topbar, .m-bottombar, .m-scroll)
 *  - Desktop shell (.d-app, .d-sidebar, .d-main, etc.)
 *
 * Anything in here that becomes shared in a future phase should be
 * lifted out and the import in shared/style/_entry/* updated.
 *
 * Source: consolidated from matos-shared.css + matos-mobile.css +
 *         matos-desktop.css on 2026-06-20 (Phase 2c Task 4).
 *
 * 2026-06-21 (Wave 5): the wholesale :root token shadow block that
 * re-declared ~36 tokens identical to shared/style/_base/tokens.css was
 * deleted. matos now picks up newer shared tokens (--surface-card /
 * --text flip, --d-sidebar-w, refreshed dark-mode --g3/--g4) instead of
 * being pinned to a 2026-05 snapshot. The block's claim of being a
 * "first-paint hedge" was false: shared-base.css loads BEFORE
 * matos-local.css in index.html (tests/css-split-contract.test.js
 * enforces). Only --fs-base survives as a matos-only token.
 */

/* ═══════════════════════════════════════════════════════════════════════
   §1 — matos-shared (all-viewport rules)
   Formerly css/matos-shared.css
   ═══════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════
   matos-shared.css — tokens, base typography, and components used at
   ALL viewport widths.

   Loaded BEFORE matos-mobile.css and matos-desktop.css in the cascade so
   mobile / desktop sheets can override pieces without losing the shared
   base. See index.html for the load order.

   Per the Camp v2 Style Guide §19, matos's three breakpoints are:
     - phone:   max-width 639px      (matos-mobile.css)
     - tablet:  640-959px            (sidebar shown, no density yet)
     - desktop: ≥ 960px              (matos-desktop.css)

   Tokens live in shared/style/tokens.css (loaded earlier as vendor); only
   domain-functional matos-local tokens that shared cannot provide are
   declared in :root below. Visual tokens (--y, --bk, --g1..4, --sp-*,
   --fs-*, --shadow-*, --radius-*, etc.) come from /vendor/style/tokens.css.
   ─────────────────────────────────────────────────────────────────────── */

/* ── matos-local tokens not in shared ─────────────────────────────────── */
/* 2026-06-21 (Wave 5 cleanup): the wholesale :root shadow block that
   re-declared ~36 tokens identical to shared/style/_base/tokens.css was
   deleted. That block pinned matos to a snapshot of shared and prevented
   newer shared tokens (--surface-card / --text auto-flip, --d-sidebar-w,
   refreshed dark-mode --g3 / --g4, etc.) from reaching matos. The
   first-paint "hedge" comment was inaccurate: shared-base.css is already
   loaded BEFORE matos-local.css in index.html (verified via
   tests/css-split-contract.test.js), so the tokens are present at first
   paint via the canonical cascade.

   The deprecated --sb-w (236px) was dropped here too — Wave 4B already
   pointed .d-app at shared's --d-sidebar-w (248px).

   --fs-base survives below: it's matos-only (no shared equivalent) and
   consumed by an .empty-camp h3 rule + js/pages/categories.js. Divergent
   --lh-normal (matos 1.4 vs shared 1.5) was unused in matos and removed
   along with the block. */
:root {
  --fs-base: 0.875rem;
  /* --y is identical to shared/style/_base/tokens.css. It is re-declared
     here ONLY because tests/css-split-contract.test.js#L33 asserts that
     matos-local.css contains `--y: #ffce00` as a static contract guard
     (the test was written when matos owned its own token table). The
     value MUST match shared — if shared ever rebrands, update both. */
  --y: #ffce00;
}

@media (prefers-color-scheme: dark) {
  :root {
    --purple: #a78bfa;
    --fg-info: #93c5fd;
  }
  /* Dark-mode body text: shared/style/base.css sets `color: var(--bk)` on
     body, but `--bk` is the always-dark accent token and does NOT flip in
     dark mode. Pair with --g4 for legible body-text contrast. */
  body {
    color: var(--g4);
  }
}

/* ── Base typography ──────────────────────────────────────────────────── */
h1,
h2,
h3 {
  font-family: var(--serif);
  font-weight: 400;
  margin: 0 0 var(--sp-3) 0;
}

h1 {
  font-size: var(--fs-3xl);
  letter-spacing: -0.5px;
}

h2 {
  font-size: var(--fs-2xl);
}

h3 {
  font-size: var(--fs-xl);
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font-family: var(--sans);
  font-size: inherit;
  cursor: pointer;
  border: none;
  background: none;
  color: inherit;
  padding: 0;
  /* iOS Safari paints a gray flash on every tap. Kill the OS overlay so
   * the UI doesn't look "stuttery" on touch devices. */
  -webkit-tap-highlight-color: transparent;
}

input,
select,
textarea {
  font-family: var(--sans);
  font-size: inherit;
  -webkit-tap-highlight-color: transparent;
}

a,
.m-bb-item,
.m-scanfab,
.btn,
.m-input,
.m-select,
[role='button'] {
  -webkit-tap-highlight-color: transparent;
}

/* ── App shell — desktop grid skeleton ────────────────────────────────── */
/* Mobile overrides live in matos-mobile.css; the grid below is the
 * desktop / tablet default (sidebar left, content right). */
.app-shell {
  display: grid;
  grid-template-columns: 236px 1fr;
  grid-template-rows: 1fr;
  min-height: 100vh;
  min-height: 100svh;
  min-height: 100dvh;
}

/* Pre-bootstrap skeleton — painted by js/main.js#paintSkeleton before
 * the auth + i18n round-trips so the viewport isn't white for the
 * full cold-start latency. Removed by clearSkeleton() when buildShell()
 * paints the real chrome. The keyframes used to be inline-injected via
 * a <style> element, which CSP `style-src 'self'` blocked (2026-06-02
 * cross-browser e2e pass surfaced it). Now baked into the canonical
 * stylesheet so no inline style injection is needed. */
.app-skeleton {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: var(--wh, #fff);
  color: var(--bk, #111);
  font-family: var(--serif, 'DM Serif Display', Georgia, serif);
  z-index: 1;
  pointer-events: none;
}
.app-skeleton-wordmark {
  font-size: 3rem; /* oversized wordmark display — no fs-* token covers 3rem */
  line-height: 1;
  letter-spacing: -0.01em;
  opacity: 0.85;
  animation: matos-skeleton-pulse 1.4s ease-in-out infinite;
}
@keyframes matos-skeleton-pulse {
  0%,
  100% {
    opacity: 0.55;
    transform: scale(0.99);
  }
  50% {
    opacity: 0.95;
    transform: scale(1);
  }
}

/* Sidebar footer overrides — shared provides the base; these adjust
   matos-specific deviations. The sidebar itself is desktop-only in
   matos (hidden in matos-mobile.css). */
.app-shell .sidebar .sb-user {
  padding: 0.75rem 0.85rem;
  border-top: 1px solid var(--bk3);
}
.app-shell .sidebar .sb-user .u-av {
  width: 32px;
  height: 32px;
  font-size: var(--fs-sm);
}
.app-shell .sidebar .sb-copyright {
  padding: 0.5rem 0.85rem 0.6rem;
}

.app-shell .main {
  grid-column: 2;
  grid-row: 1;
  padding: var(--sp-5);
  overflow-y: auto;
  /* Grid items default to `min-width: auto`, which resolves to the
   * content's max-content size. Combined with a `1fr` track, that lets
   * any descendant with intrinsic max-content > viewport (e.g. a
   * `.m-chips` strip with `overflow-x: auto` whose chip buttons sum
   * past the available width) blow the grid track past the container,
   * triggering horizontal scroll. Pinning `min-width: 0` here makes
   * the column shrink to the container and lets descendants with
   * their own scroll/overflow handling do their job. Mobile Chercher
   * surfaced this with the long 6-chip Statut filter row at 390px.
   * 2026-06-02. */
  min-width: 0;
}

/* ── Buttons (shared/style/buttons.css layer + matos-local extensions) ── */
/* Base .btn / .btn-* group rules deleted 2026-06-20: identical to
 * shared/style/_components/buttons.css. Individual color + size rules
 * also deleted (identical). .btn-sm deleted (identical).
 *
 * INTENTIONAL OVERRIDES kept below:
 * .btn-lg  — matos uses padding: 11px 18px; shared uses 10px 18px.
 * .btn-md  — matos uses padding: 8px 14px; shared uses 7px 14px.
 * .btn-gh.on — matos uses light g1 surface + dark border (toggle-active
 *   reads as "pressed" not "selected"); shared uses full-dark surface.
 * .btn-gh:active — matos adds explicit bg feedback; shared relies on opacity.
 * .btn-block — width: 100% helper; not in shared. */
.btn-lg { font-size: var(--fs-md); padding: 11px 18px; }
.btn-md { font-size: var(--fs-md); padding: 8px 14px; }
.btn-gh:active { background: var(--g1); }
.btn-gh.on { background: var(--g1); border-color: var(--bk); color: var(--bk); font-weight: 700; }
.btn-block { width: 100%; }

/* Icon button — small square, used for the item-edit-fields del button. */
.btn-icon {
  width: 32px;
  height: 32px;
  border: 1px solid var(--g2);
  border-radius: var(--radius-xs);
  background: transparent;
  cursor: pointer;
  color: var(--g4);
  display: grid;
  place-items: center;
  flex-shrink: 0;
  transition:
    background var(--dur-chip),
    color var(--dur-chip),
    border-color var(--dur-chip);
}
.btn-icon:hover {
  background: var(--g1);
  color: var(--red);
  border-color: var(--red);
}

/* ── Badges / pills (shared/style/badges.css layer + matos-local) ────── */
/* .badge / .badge-* / .tag-chip / .tag-chip-sm base rules deleted 2026-06-20:
 * identical copies of shared/style/badges.css — shared loads first via the
 * /vendor/style/_entry/*.css entry files so shared's rules are canonical. */

/* .tag-chip {} deleted 2026-06-20: subset of shared/style/_components/badges.css
 * (matos rule was missing gap: 4px). Shared covers all needed properties.
 * NOTE: .tag-chip remains in compound selectors (.creer-tabs .tag-chip etc.)
 * below; test allowlist covers this selector.
 *
 * INTENTIONAL OVERRIDE: .tag-chip-sm — matos uses padding: 2px var(--sp-2)
 * (= 2px 0.5rem); shared uses padding: var(--sp-05) var(--sp-1h) (= 0.1rem
 * 0.375rem). The matos padding gives a slightly taller, wider chip for the
 * table-row context. */
.tag-chip-sm {
  padding: 2px var(--sp-2);
  font-size: var(--fs-xs);
  border-radius: var(--radius-xs);
}

/* .tp-pill and .tp-pill.* deleted 2026-06-20: identical copies of
 * shared/style/_components/badges.css. */

.countdown-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--g1);
  border: 1px dashed var(--g4);
  border-radius: var(--radius-xs);
  padding: 3px 8px;
  font-size: var(--fs-xs);
  color: var(--g4);
}
.countdown-chip.soon { border-color: var(--green); color: var(--fg-success); }
.countdown-chip.late { border-color: var(--red); color: var(--fg-error); background: var(--bg-error); }

/* ── Banners (shared/style/banners.css layer + matos-local overrides) ── */
/* .sg-banner / .sg-banner-warn / .sg-banner-error / .sg-banner-success base
 * rules deleted 2026-06-20: identical to shared/style/banners.css.
 * .sg-banner strong also deleted (identical).
 * .sg-banner-info override deleted 2026-06-21: drift from shared's blue
 * --fg-info — Style Guide §2 says status banners stay consistent across
 * the suite, so the shared blue now cascades through. */

/* matos-local — bug fix: ensure [hidden] beats shared's display:flex.
   shared/style/banners.css sets display:flex on .sg-banner; the [hidden]
   attribute has equal specificity and loses to a later rule. */
.sg-banner[hidden] {
  display: none;
}

/* ── Relecture LEDs (Camp v2 Style Guide §08) ──────────────────────────── */
/* Base shape + ok / warn / bad variants promoted to
 * @suite/lib/style/status-led.css (`.suite-status-led`). Markup now carries
 * `class="suite-status-led led <variant>"` (compose-don't-rename) so any
 * existing test or JS hook keyed on `.led` keeps working.
 * `.led.field` (matos-specific field-blue variant for items currently out
 * in the field) stays local because it doesn't map to the suite primitive's
 * `.info` semantic. */
.led.field { background: var(--blue); border-color: var(--blue); }

/* ── Mono code ────────────────────────────────────────────────────────── */
.mono {
  font-family: var(--mono);
  font-size: 0.9em;
  color: var(--g4);
}

/* ── Forms (matos-local form layout) ──────────────────────────────────── */
/* .fm-field {} base rule deleted 2026-06-20: identical to
 * shared/style/_components/forms.css. Child rules below are intentional
 * overrides (e.g. label color: --g4 vs shared's --text). */

.fm-field label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--g4);
}

.fm-field input,
.fm-field select,
.fm-field textarea {
  padding: var(--sp-3);
  border: 1px solid var(--g2);
  border-radius: var(--radius-sm);
  background: var(--wh);
  font-size: var(--fs-md);
  width: 100%;
}

.fm-field input:focus,
.fm-field select:focus,
.fm-field textarea:focus {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
}

/* ── Item card / row ──────────────────────────────────────────────────── */
.item-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3);
  border-bottom: 1px solid var(--g2);
  cursor: pointer;
  transition: background var(--dur-chip);
}

.item-row:hover {
  background: var(--g1);
}

.item-row .name {
  flex: 1;
  font-weight: 500;
}

.item-row .code {
  font-family: var(--mono);
  font-size: 0.85em;
  color: var(--g4);
}

/* Matched-query highlight. */
mark {
  background: rgb(var(--y-rgb) / 25%);
  color: inherit;
  border-radius: 2px;
  padding: 0 1px;
}

/* ── Page wrap (max-width containers) ─────────────────────────────────── */
/* All page wrappers inherit the main scroll's max-width (1180px on desktop)
   so every page fills the same column. The three `.content-*` aliases are
   kept so existing page code and the content-width source-grep test stay
   green; they no longer narrow form pages. */
.page-wrap,
.content-default,
.content-extra-wide {
  margin: 0 auto;
}

/* ── Modal: search-list pattern (used by item-pick etc.) ─────────────── */
.modal-hint {
  margin: 0 0 var(--sp-3) 0;
  font-size: var(--fs-sm);
  color: var(--g4);
}
.modal-search {
  width: 100%;
  padding: var(--sp-3);
  border: 1px solid var(--g2);
  border-radius: var(--radius-sm);
  font-size: var(--fs-md);
  font-family: inherit;
  background: var(--wh);
  margin-bottom: var(--sp-3);
}
.modal-search:focus-visible {
  outline: none;
  border-color: var(--bk);
  box-shadow: 0 0 0 3px var(--focus-ring);
}
.modal-list {
  max-height: 50vh;
  overflow-y: auto;
  border: 1px solid var(--g2);
  border-radius: var(--radius-sm);
  margin-bottom: var(--sp-3);
}
.modal-list-empty {
  padding: var(--sp-4);
  text-align: center;
  color: var(--g4);
  font-size: var(--fs-sm);
}
.modal-list-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  padding: var(--sp-3);
  border: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
  border-bottom: 1px solid var(--g2);
  font: inherit;
  color: inherit;
}
.modal-list-row:last-child {
  border-bottom: 0;
}
.modal-list-row:hover {
  background: var(--g1);
}
.modal-list-row:focus-visible {
  outline: 2px solid var(--y);
  outline-offset: -2px;
}
.modal-list-row .name {
  flex: 1;
  font-weight: 500;
}
.modal-list-row .code {
  font-size: var(--fs-xs);
  color: var(--g4);
}
.modal-list-row.busy {
  opacity: 0.5;
  pointer-events: none;
}
/* ── Put-away page ─────────────────────────────────────────────────────── */
.putaway-progress-bar {
  background: var(--g1);
  height: 8px;
  border-radius: var(--radius-pill);
  overflow: hidden;
  margin: var(--sp-2) 0 var(--sp-2) 0;
}
.putaway-progress-fill {
  background: var(--bk);
  height: 100%;
  border-radius: var(--radius-pill);
  transition: width var(--dur-normal);
}
.putaway-counters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
}
.putaway-pill {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--sp-2);
  border-radius: var(--radius-pill);
  background: var(--g1);
  color: var(--g4);
  font-size: var(--fs-xs);
  font-weight: 600;
}
.putaway-pill.todo {
  background: var(--bk);
  color: var(--white);
}
.putaway-pill.flag-ranger {
  background: var(--bg-success);
  color: var(--green);
}
.putaway-pill.flag-reparer {
  background: var(--bg-warn);
  color: var(--amber);
}
.putaway-pill.flag-incomplet {
  background: var(--bg-warn);
  color: var(--amber);
}
.putaway-pill.flag-autre {
  background: var(--g1);
  color: var(--g4);
}

.putaway-list {
  padding: 0;
  margin-bottom: var(--sp-3);
}
.putaway-list-head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3);
  border-bottom: 1px solid var(--g2);
}
.putaway-list-title {
  flex: 1;
  margin: 0;
  font-size: var(--fs-md);
  font-family: var(--sans);
  font-weight: 600;
}
.putaway-bulk {
  min-height: auto;
  padding: var(--sp-1) var(--sp-3);
  font-size: var(--fs-sm);
}
.putaway-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3);
  border-bottom: 1px solid var(--g2);
}
.putaway-row:last-child {
  border-bottom: 0;
}
.putaway-row.done {
  background: var(--bg-success);
}
.putaway-row.busy {
  opacity: 0.5;
  pointer-events: none;
}
/* putaway-row-text / -name / -sub rules removed 2026-06-20 (P2b cluster D):
   putaway-session.js migrated to m-card-list / m-card-l1 / m-card-l2. */
.putaway-row-actions {
  display: flex;
  gap: var(--sp-1);
}
.putaway-flag-btn {
  width: 44px;
  height: 44px;
  border: 1px solid var(--g2);
  border-radius: var(--radius-xs);
  background: var(--wh);
  cursor: pointer;
  font-size: var(--fs-md);
  display: grid;
  place-items: center;
  transition:
    background var(--dur-chip),
    border-color var(--dur-chip);
}
.putaway-flag-btn:hover {
  background: var(--g1);
}
.putaway-flag-btn.primary:hover {
  background: var(--bg-success);
  border-color: var(--green);
}
.putaway-flag-btn.warn:hover {
  background: var(--bg-warn);
  border-color: var(--amber);
}
.putaway-undo {
  min-height: auto;
  padding: var(--sp-1) var(--sp-2);
  font-size: var(--fs-xs);
}
.putaway-actions {
  margin-top: var(--sp-3);
}
.putaway-actions .btn {
  width: 100%;
}

/* ── Item history (collapsible) ───────────────────────────────────────── */
.item-history-card {
  margin-top: var(--sp-4);
  border: 1px solid var(--g2);
  border-radius: var(--radius-md);
  background: var(--wh);
  padding: 0;
}
.item-history-summary {
  padding: var(--sp-3) var(--sp-4);
  cursor: pointer;
  font-weight: 600;
  list-style: none;
  user-select: none;
}
.item-history-summary::-webkit-details-marker {
  display: none;
}
.item-history-summary::before {
  content: '▸';
  display: inline-block;
  width: 1em;
  transition: transform var(--dur-chip);
  color: var(--g4);
}
.item-history-card[open] .item-history-summary::before {
  transform: rotate(90deg);
}
.item-history-list {
  padding: 0 var(--sp-4) var(--sp-3);
  display: flex;
  flex-direction: column;
}
.item-history-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--sp-3);
  padding: var(--sp-2) 0;
  border-top: 1px solid var(--g2);
  font-size: var(--fs-sm);
}
.item-history-ts {
  font-family: var(--mono);
  font-size: var(--fs-xs);
  color: var(--g4);
}
.item-history-label {
}
.item-history-actor {
  font-size: var(--fs-xs);
  color: var(--g4);
}

/* ── Status meta card ─────────────────────────────────────────────────── */
.status-meta {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  margin-bottom: var(--sp-4);
}
.status-meta-ic {
  font-size: 1.3rem; /* icon glyph — 1.3rem between --fs-md and --fs-lg; no exact token */
  flex-shrink: 0;
}
.status-meta-text {
  flex: 1;
}
.status-meta-title {
  font-weight: 600;
}
.status-meta-sub {
  font-size: var(--fs-sm);
  color: var(--g4);
  margin-top: 2px;
}

/* ── Shelf detail ─────────────────────────────────────────────────────── */
.shelf-level-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: var(--sp-4) 0 var(--sp-2) 0;
}
.shelf-level-num {
  background: var(--g1);
  border-radius: var(--radius-pill);
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: var(--fs-xs);
}
.shelf-level-lbl {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--g4);
  font-weight: 600;
}
.shelf-level-empty {
  padding: var(--sp-3);
  color: var(--g4);
  font-style: italic;
  font-size: var(--fs-sm);
  background: var(--g1);
  border-radius: var(--radius-sm);
  margin-bottom: var(--sp-2);
}
.shelf-boxes {
  padding: 0;
  margin-bottom: var(--sp-2);
}
.shelf-box-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.shelf-box-ic {
  font-size: 1.3rem; /* icon glyph — 1.3rem between --fs-md and --fs-lg; no exact token */
  flex-shrink: 0;
}
.shelf-box-text {
  flex: 1;
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  min-width: 0;
}
.shelf-box-text .name {
  font-weight: 600;
}
.shelf-row-chev {
  color: var(--g4);
  font-size: var(--fs-lg);
}
.shelf-loose-lbl {
  font-size: var(--fs-xs);
  color: var(--g4);
  margin: var(--sp-2) 0 var(--sp-1) var(--sp-2);
}

/* ── Item edit page ────────────────────────────────────────────────────── */
.edit-head {
  margin-bottom: var(--sp-3);
}
.edit-h1 {
  margin: var(--sp-2) 0 0 0;
  font-family: var(--serif);
  font-size: var(--fs-2xl);
}
.edit-section {
  margin-bottom: var(--sp-3);
}
.edit-h2 {
  margin: 0 0 var(--sp-3) 0;
  font-family: var(--serif);
  font-size: var(--fs-lg);
  font-weight: 400;
}
.edit-hint {
  margin: var(--sp-1) 0 0 0;
  font-size: var(--fs-sm);
  color: var(--g4);
  line-height: 1.4;
}
.edit-readonly-line {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--sp-2) 0;
  border-top: 1px solid var(--g2);
  margin-top: var(--sp-3);
}
.edit-readonly-line .lbl {
  font-size: var(--fs-sm);
  color: var(--g4);
}
.edit-readonly-line .val {
  font-weight: 600;
}

.edit-loc-tabs {
  display: flex;
  gap: var(--sp-1);
  margin: var(--sp-2) 0;
  background: var(--g1);
  border-radius: var(--radius-sm);
  padding: var(--sp-1);
}
.edit-loc-tab {
  flex: 1;
  padding: var(--sp-2);
  background: transparent;
  border: 0;
  border-radius: var(--radius-xs);
  cursor: pointer;
  color: var(--g4);
  font: inherit;
  transition:
    background var(--dur-chip),
    color var(--dur-chip);
}
.edit-loc-tab.active {
  background: var(--surface-card);
  color: var(--text);
  font-weight: 600;
  box-shadow: var(--shadow-sm);
}
.edit-loc-body {
  margin-top: var(--sp-2);
}
.edit-loc-grid {
  display: grid;
  grid-template-columns: 1fr 80px;
  gap: var(--sp-2);
}

.edit-status-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-2);
}
.edit-status-tile {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border: 1px solid var(--g2);
  border-radius: var(--radius-sm);
  background: var(--wh);
  cursor: pointer;
  transition:
    background var(--dur-chip),
    border-color var(--dur-chip);
}
.edit-status-tile:hover {
  background: var(--g1);
}
.edit-status-tile.active {
  border-color: var(--y);
  background: var(--wh);
  box-shadow: 0 0 0 2px var(--y) inset;
}
.edit-status-tile input[type='radio'] {
  display: none;
}
.edit-status-tile .ic {
  font-size: var(--fs-lg);
}
.edit-status-tile .lbl {
  font-weight: 600;
}
.edit-status-meta {
  margin-top: var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.edit-status-meta:empty {
  display: none;
}

.edit-parts-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
}
.edit-parts-row {
  display: grid;
  /* CK-6 (2026-05-20): qty + expiry columns dropped from parts editor.
     Layout is now [tick] [name] [delete]. */
  grid-template-columns: 32px 1fr 32px;
  align-items: center;
  gap: var(--sp-2);
}
.edit-parts-row input[type='text'] {
  padding: var(--sp-2);
  border: 1px solid var(--g2);
  border-radius: var(--radius-xs);
  font: inherit;
  min-width: 0;
}
.edit-parts-tick {
  width: 32px;
  height: 32px;
  border: 2px solid var(--g3);
  border-radius: var(--radius-xs);
  background: var(--wh);
  cursor: pointer;
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--green);
  display: grid;
  place-items: center;
  flex-shrink: 0;
  transition:
    background var(--dur-chip),
    border-color var(--dur-chip);
}
.edit-parts-tick.ok {
  background: var(--green);
  color: var(--white);
  border-color: var(--green);
}
.edit-parts-add {
  display: flex;
  gap: var(--sp-2);
}
.edit-parts-add input {
  flex: 1;
}

.edit-retire-reason {
  width: 100%;
  margin: var(--sp-2) 0;
  padding: var(--sp-3);
  border: 1px solid var(--g2);
  border-radius: var(--radius-sm);
  font: inherit;
  background: var(--wh);
}

/* The sticky save bar covers later content (e.g. archive button) when
   scrolled near the bottom. Add bottom margin on the danger section
   equal to the bar's height + sticky offset; mobile bumps this in
   matos-mobile.css to clear the bottom nav. */
.edit-danger {
  margin-bottom: calc(80px + env(safe-area-inset-bottom));
}

/* Label pipeline v2 (Stage 1,
2026-06-12): the @media print stylesheet
   block that used to drive labels-batch + etiquette print runs has
   been removed. The SPA no longer calls window.print() — operators now
   open a server-side PDF via /api/v1/inventory/labels/batch.pdf and
   the OS print dialog runs on the PDF viewer {
  max-width: 880px;
  margin: 0 auto;
  padding: var(--sp-3);
}
.lbl-batch-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-3);
}
.lbl-batch-head h1 {
  margin: 0;
}
.lbl-batch-print {
  flex-shrink: 0;
}
.lbl-cell {
  position: relative;
  display: grid;
  grid-template-columns: 88px 1fr;
  gap: var(--sp-2);
  align-items: center;
  padding: var(--sp-2);
  border: 1px dashed var(--g3);
  border-radius: var(--radius-xs);
  background: var(--wh);
}
.lbl-stock-picker {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1, 0.25rem);
  font-size: var(--fs-sm, 0.875rem);
}
.lbl-stock-picker select {
  padding: var(--sp-1) var(--sp-2);
  border: 1px solid var(--g2);
  border-radius: 6px;
}
/* WCAG 2.1 SC 2.4.7: native <summary> does not inherit the suite-wide
   focus-ring selectors, so keyboard navigation to "Options avancées"
   shows no indicator without this rule. */
.lbl-advanced summary:focus-visible {
  outline: 3px solid var(--y);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
/* @media print block that hid .lbl-stock-picker removed in Stage 1 of
   the label-pipeline-v2 cutover — the on-screen picker stays visible
   during PDF generation so the operator can re-confirm before the
   click, and there's no print event to suppress anything for. */

/* Phase 8 (Task 8.1): inline PDF preview iframe revealed by the Aperçu PDF
   button. Sits between the header/controls and the HTML grid. The iframe
   fills the available width at 70 vh so the operator can read the labels
   at scale without leaving the page. */
.lbl-pdf-preview {
  margin: var(--sp-3) 0;
  border: 1px solid var(--g2);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--surface-card);
}
.lbl-pdf-preview iframe {
  width: 100%;
  height: 70vh;
  border: 0;
  display: block;
}

/* Bottom-sheet body content — matos-local pieces left over after the
   2026-06-12 sweep that retired shared/style/bottom-sheet.css Layer 2.
   The sheet chrome is delegated to @suite/lib/bottom-sheet (.suite-sheet-*)
   and the row list adopts .suite-list / .suite-list-row from
   @suite/lib/style/list. What's left below has no shared primitive yet:
     - create-sheet group header (a section label, not a row)
     - filter-sheet toolbar (multi-select + create CTAs, above the list)
     - filter-sheet footer (apply CTA, below the list) */
.matos-create-sheet-group-header {
  padding: var(--sp-2) var(--sp-4) var(--sp-1);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--g4);
  letter-spacing: 0.4px;
  text-transform: uppercase;
}
.matos-filter-sheet-toolbar {
  display: flex;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
}
.matos-filter-sheet-footer {
  padding: var(--sp-3) var(--sp-4);
}

/* ── Skip-to-content link (a11y) ──────────────────────────────────────── */
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: var(--bk);
  color: var(--white);
  padding: var(--sp-2) var(--sp-4);
  z-index: 10000;
  text-decoration: none;
  border-radius: 0 0 var(--radius-sm) 0;
}
.skip-link:focus {
  top: 0;
}

/* ── Photo strip + lightbox (used on mobile + desktop) ─────────────── */
.photo-strip {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: var(--sp-2);
}
.photo-tile {
  position: relative;
  border: 1px solid var(--g2);
  border-radius: var(--radius-sm);
  overflow: hidden;
  padding: 0;
  background: var(--g1);
  cursor: pointer;
  aspect-ratio: 1 / 1;
  transition: transform var(--dur-fast);
}
.photo-tile:hover {
  transform: scale(1.02);
}
.photo-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.photo-tile-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.65), transparent);
  color: var(--white);
  padding: var(--sp-2);
  font-size: var(--fs-xs);
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.photo-tile-cover-badge {
  position: absolute;
  top: var(--sp-1);
  left: var(--sp-1);
  background: var(--y);
  color: var(--bk);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1;
  padding: 2px var(--sp-1);
  border-radius: var(--radius-xs);
  pointer-events: none;
}
.photo-lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.85);
  z-index: 1000;
  display: grid;
  place-items: center;
  padding: var(--sp-4);
}
.photo-lightbox-inner {
  max-width: min(90vw, 900px);
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
}
.photo-lightbox-inner img {
  max-width: 100%;
  max-height: 70vh;
  object-fit: contain;
  background: var(--wh);
  border-radius: var(--radius-sm);
}
.photo-lightbox-caption {
  color: var(--white);
  font-size: var(--fs-md);
  text-align: center;
  cursor: text;
  padding: var(--sp-1) var(--sp-2);
  border-radius: var(--radius-xs);
  min-width: 60%;
  outline: none;
  transition: background var(--dur-chip);
}
.photo-lightbox-caption:hover,
.photo-lightbox-caption:focus-visible {
  background: rgba(255, 255, 255, 0.08);
}
.photo-lightbox-caption-empty {
  color: var(--g3);
  font-style: italic;
}
.photo-lightbox-caption-input {
  width: 100%;
  padding: var(--sp-1) var(--sp-2);
  border-radius: var(--radius-xs);
  border: 1px solid var(--g3);
  background: var(--wh);
  color: var(--bk);
  font-size: var(--fs-md);
  text-align: center;
}
.photo-lightbox-meta {
  color: var(--g3);
  font-size: var(--fs-sm);
}
.photo-lightbox-actions {
  display: flex;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
}

/* ── QR-scan success flash ────────────────────────────────────────────── */
.qr-flash {
  position: fixed;
  inset: 0;
  z-index: 1100;
  background: var(--wh);
  pointer-events: none;
  opacity: 0;
  transform: scale(1);
  will-change: transform, opacity;
}

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

/* ── /lieux page ──────────────────────────────────────────────────────── */
/* Inherits .main.m-scroll's 1180px desktop cap. The fixed 720px cap that
   used to live here made the locations list feel narrower the wider the
   viewport got — past 720px the page stopped growing while the sidebar +
   surrounding chrome kept expanding. */
.loc-wrap {
  margin: 0 auto;
}
/* ── Checkout sortir/rentrer full-screen modals ───────────────────────── */
.matos-modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 1000;
}
.matos-modal-fullscreen {
  position: fixed;
  inset: 0;
  background: var(--wh);
  z-index: 1001;
  display: flex;
  flex-direction: column;
  overscroll-behavior: contain;
}
.matos-modal-header {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3);
  border-bottom: 1px solid var(--g2);
  flex-shrink: 0;
}
.matos-modal-header h2 {
  flex: 1;
  margin: 0;
  font-size: var(--fs-lg, 1.125rem);
  font-weight: var(--fw-bold, 700);
}
.matos-modal-close {
  background: transparent;
  border: none;
  font-size: var(--fs-xl);
  cursor: pointer;
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  color: var(--g4);
  flex-shrink: 0;
}
.matos-modal-close:hover {
  background: var(--g1);
}
.matos-modal-close:focus-visible {
  outline: 2px solid var(--y);
  outline-offset: 2px;
}
.matos-modal-body {
  flex: 1;
  overflow-y: auto;
  padding: var(--sp-3);
  -webkit-overflow-scrolling: touch;
}
.matos-modal-loading {
  color: var(--g4);
  font-size: var(--fs-sm);
  margin: 0;
}
.matos-modal-note {
  font-size: var(--fs-sm);
  color: var(--g4);
  margin: 0 0 var(--sp-3);
}
.matos-modal-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 52px;
  padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--g2);
  cursor: default;
}
.matos-modal-row:last-child {
  border-bottom: none;
}
.matos-modal-item-name {
  flex: 1;
  font-size: var(--fs-base);
}
.matos-modal-qty {
  color: var(--g4);
  font-size: var(--fs-sm);
  white-space: nowrap;
}
.matos-modal-return-row {
  border-bottom: 1px solid var(--g2);
  padding-bottom: var(--sp-2);
  margin-bottom: var(--sp-1);
}
.matos-modal-return-row:last-child {
  border-bottom: none;
  margin-bottom: 0;
}
.matos-modal-return-row .matos-modal-row {
  border-bottom: none;
  padding-bottom: 0;
}
.matos-modal-flag-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-1);
  padding: var(--sp-1) 0 var(--sp-2) calc(20px + var(--sp-2));
}
.matos-modal-flag-label {
  font-size: var(--fs-xs, 0.75rem);
  color: var(--g4);
  white-space: nowrap;
}
.matos-modal-flag-btn {
  font-size: var(--fs-xs, 0.75rem);
  padding: 4px 10px;
}
.matos-modal-flag-btn.is-active {
  background: var(--bk);
  color: var(--wh);
  border-color: var(--bk);
}
.matos-modal-parts-hint {
  font-size: var(--fs-xs, 0.75rem);
  color: var(--g4);
  padding: 0 0 var(--sp-1) calc(20px + var(--sp-2));
  margin: 0;
  font-style: italic;
}
.matos-modal-footer {
  padding: var(--sp-3);
  padding-bottom: calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--g2);
  flex-shrink: 0;
}
.matos-modal-footer .btn {
  width: 100%;
}

/* ── Plus overflow page ──────────────────────────────────────────────── */
.matos-plus-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3);
  min-height: 56px;
  text-decoration: none;
  color: var(--text);
  border-bottom: 1px solid var(--g2);
}
.matos-plus-row:active {
  background: var(--g1);
}

/* ── Créer hub tabs ────────────────────────────────────────────────────── */
.creer-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
  margin-bottom: var(--sp-3);
}

.creer-tabs .tag-chip {
  min-height: 36px;
  padding: 0 var(--sp-3);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  text-decoration: none;
  transition:
    background-color var(--dur-chip),
    color var(--dur-chip);
}

.creer-tabs .tag-chip.is-active {
  background: var(--y);
  color: var(--bk);
  font-weight: 600;
}

.creer-panel {
  margin-top: var(--sp-2);
}

/* ── Sidebar user-block dropdown ───────────────────────────────────────── */
.sb-user {
  position: relative;
  cursor: pointer;
}

/* ── Aperçu home page ─────────────────────────────────────────────────── */
.apercu-host {
  padding: var(--sp-3);
}
.apercu-hero {
  margin-bottom: var(--sp-4);
}
.apercu-hero h1 {
  margin: 0 0 var(--sp-1);
}
.apercu-hero-stats {
  color: var(--g4);
  margin: 0;
}
.apercu-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-4);
}
.apercu-tile-wide {
  grid-column: 1 / -1;
}
.apercu-tile {
  padding: var(--sp-3);
}
.apercu-tile h2 {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-md, 16px);
}
.apercu-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.apercu-list li {
  padding: var(--sp-1) 0;
}
.apercu-list a {
  text-decoration: none;
  color: inherit;
}
.apercu-list a:hover {
  text-decoration: underline;
}
.apercu-empty {
  color: var(--g4);
  font-style: italic;
  margin: 0;
}
.apercu-cta {
  display: inline-block;
  margin-top: var(--sp-2);
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--y);
  text-underline-offset: 3px;
  text-decoration-thickness: 2px;
}
.apercu-cta:hover {
  text-decoration-thickness: 3px;
}
.apercu-time {
  color: var(--g4);
  font-size: var(--fs-md);
}
.apercu-action-row {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
}
.apercu-action-row-secondary {
  margin-top: var(--sp-2);
}

/* sg-card — neutral card surface used by Aperçu tiles + redesign blocks. */
.sg-card {
  background: var(--surface-card);
  border: 1px solid var(--g2);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}

/* ── matos-app container (shared base; mobile sets overflow/height) ──── */
.matos-app {
  position: relative;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--wh);
  color: var(--text);
  font-family: var(--sans);
  font-size: var(--fs-md);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}
.matos-app *,
.matos-app *::before,
.matos-app *::after {
  box-sizing: border-box;
}
.matos-app h1,
.matos-app h2,
.matos-app h3 {
  font-family: var(--serif);
  font-weight: 400;
  margin: 0;
}
.matos-app button {
  font-family: var(--sans);
  cursor: pointer;
  border: none;
  background: none;
  color: inherit;
}
.matos-app .mono {
  font-family: var(--mono);
}

/* ── Generic layout helpers used on every page ────────────────────────── */
.m-eyebrow {
  font-size: var(--fs-xs); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--g4); font-weight: 700;
}
.m-h1 { font-family: var(--serif); font-size: var(--fs-3xl); line-height: 1; letter-spacing: -0.01em; color: var(--text); }
.m-h2 { font-family: var(--serif); font-size: var(--fs-xl); line-height: 1.1; color: var(--text); }
.m-section-hd {
  display: flex; align-items: baseline; justify-content: space-between;
  margin: var(--sp-5) 0 var(--sp-2h);
}
.m-section-hd:first-child { margin-top: 0; }
.m-section-title { font-family: var(--serif); font-size: var(--fs-lg); color: var(--text); }
.m-section-link { font-size: var(--fs-sm); color: var(--g4); font-weight: 600; }
.m-muted { color: var(--g4); }

/* ── Search pill / input (used on both mobile + desktop pages) ───────── */
/* Background uses `--wh` (the flipping page-surface token), not `--white`,
 * so the pill flips to the dark surface automatically in dark mode. */
.m-search {
  display: flex; align-items: center; gap: var(--sp-2);
  background: var(--wh); border: 1px solid var(--g2);
  border-radius: var(--radius-pill); padding: 10px var(--sp-4);
  color: var(--g4); font-size: var(--fs-md); width: 100%;
}
.m-search.field { border-radius: var(--radius-sm); }
.m-search input {
  border: none; outline: none; background: none; flex: 1;
  font-family: var(--sans); font-size: var(--fs-md); color: var(--text); min-width: 0;
}

/* ── Stat band (dashboard) ─────────────────────────────────────────────── */
.m-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-2h);
  margin-top: var(--sp-4);
}
.m-stat {
  background: var(--wh); border: 1px solid var(--g2);
  border-radius: var(--radius-md); padding: var(--sp-3) var(--sp-3h);
  box-shadow: var(--shadow-sm);
}
.m-stat-num {
  font-family: var(--serif); font-weight: 700; font-size: var(--fs-3xl); line-height: 1;
  color: var(--text); font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
}
.m-stat-num.sm { font-size: var(--fs-2xl); }
.m-stat-label {
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--g4); margin-top: 6px;
}
/* .m-stat-bar + .m-stat-bar > i moved to @suite/lib/style/stat.css as
 * .suite-stat-bar; matos markup composes via class="suite-stat-bar m-stat-bar"
 * so the per-app class still resolves for any selector that targets it. */

/* ── Attention rows ────────────────────────────────────────────────────── */
.m-attention { padding: var(--sp-1) 0; }
.m-att-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-3h);
  border-bottom: 1px solid var(--g1);
  width: 100%; text-align: left;
}
.m-att-row:last-child { border-bottom: none; }
.m-att-ic {
  width: 38px; height: 38px; border-radius: var(--radius-sm);
  display: grid; place-items: center; font-size: var(--fs-xl); flex-shrink: 0;
}
.m-att-ic.err { background: var(--bg-error); }
.m-att-ic.warn { background: var(--bg-warn); }
.m-att-ic.info { background: var(--bg-info); }
.m-att-body { flex: 1; min-width: 0; }
.m-att-count { display: block; font-family: var(--sans); font-size: var(--fs-xl); line-height: 1; color: var(--text); }
.m-att-label { display: block; font-size: var(--fs-sm); color: var(--g4); margin-top: 3px; }
.m-att-row .chev { color: var(--g3); font-size: var(--fs-lg); }
.m-att-empty {
  display: flex; align-items: center; gap: 8px;
  padding: var(--sp-4); color: var(--fg-success); font-size: var(--fs-md);
}

/* ── Generic list rows (À venir / activité) ────────────────────────────── */
.m-feed { list-style: none; padding: 0; margin: 0; }
.m-feed-row {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-3) 0; border-bottom: 1px solid var(--g1);
}
.m-feed-row:last-child { border-bottom: none; }
.m-feed-ic { font-size: var(--fs-lg); width: 22px; text-align: center; flex-shrink: 0; }
.m-feed-main { flex: 1; min-width: 0; }
.m-feed-text { display: block; font-size: var(--fs-md); color: var(--text); }
.m-feed-text b { font-weight: 600; }
/* 2026-06-02 a11y: timestamp body text was on `--g3` (#b8b5ab on white
 * = 2.05:1, fails WCAG AA). Body text needs `--g4` (#6e6b62 on white =
 * 5.4:1, AA-pass). `--g3` stays the hairline / disabled-control token
 * where 2:1 is intentional. */
.m-feed-time { display: block; font-size: var(--fs-xs); color: var(--g4); margin-top: 2px; }

/* ── Item card (Chercher: cards — shared between mobile + desktop) ────── */
.m-item-card {
  display: flex; align-items: center; gap: var(--sp-3);
  background: var(--wh); border: 1px solid var(--g2);
  border-radius: var(--radius-md); padding: var(--sp-3); box-shadow: var(--shadow-sm);
  width: 100%; text-align: left;
}
.m-item-thumb {
  width: 46px; height: 46px; border-radius: var(--radius-sm);
  background: var(--g1); display: grid; place-items: center;
  font-size: var(--fs-2xl); flex-shrink: 0;
}
.m-item-main { flex: 1; min-width: 0; }
.m-item-name { display: block; font-weight: 600; font-size: var(--fs-md); color: var(--text); }
.m-item-meta {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin-top: 4px; font-size: var(--fs-sm); color: var(--g4);
}
.m-item-code { font-family: var(--mono); font-size: var(--fs-xs); color: var(--g4); }
.m-item-loc { display: inline-flex; align-items: center; gap: 3px; }
.m-item-trail { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; flex-shrink: 0; }
.m-item-qty { font-family: var(--sans); font-size: var(--fs-lg); color: var(--text); line-height: 1; }

/* Filter chips */
.m-chips { display: flex; gap: var(--sp-2); overflow-x: auto; padding-bottom: var(--sp-1); margin: var(--sp-3) 0; scrollbar-width: none; }
.m-chips::-webkit-scrollbar { display: none; }
.m-chip {
  flex-shrink: 0; padding: 6px 12px; border-radius: var(--radius-pill);
  border: 1px solid var(--g2); background: var(--surface-card); color: var(--g4);
  font-size: var(--fs-sm); font-weight: 600; white-space: nowrap;
}
.m-chip.on { background: var(--bk); color: var(--white); border-color: var(--bk); }
.m-filter-row { display: flex; align-items: center; gap: var(--sp-2h); margin-top: var(--sp-2h); }
.m-filter-lbl { flex-shrink: 0; width: 58px; font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--g4); }
.m-filter-row .m-chips { margin: 0; flex: 1; min-width: 0; }
.m-chip-sm { padding: 5px 11px; font-size: var(--fs-sm); }

/* ── Item detail ───────────────────────────────────────────────────────── */
.m-detail-hd { margin-bottom: var(--sp-4); }
.m-detail-name { font-family: var(--serif); font-size: var(--fs-3xl); line-height: 1.05; color: var(--text); margin-bottom: var(--sp-2); }
.m-detail-meta { display: flex; align-items: center; gap: var(--sp-2h); flex-wrap: wrap; }
/* .m-card-block composes onto @suite/lib/style/card.css `.suite-card`
 * (Tier H Step 1, 2026-06-12). The base border / radius / background /
 * hover-shadow comes from `.suite-card`. The overrides below are the
 * matos-specific extras: the tighter `--sp-3h` padding (matos cards
 * stack denser than the suite default), the always-on `--shadow-sm`
 * (`.suite-card` only shadows on hover), and the per-card bottom
 * margin used for mobile stacking.
 *
 * The surface `background` was stripped 2026-06-13: pinning
 * `var(--white)` (the never-flipping pure-white token) over the
 * shared `.suite-card`'s `var(--wh)` reintroduced the bright-white-
 * island bug in dark mode. Letting `.suite-card`'s flipping surface
 * through makes dark mode work for free.
 *
 * Every matos call-site that names this class also stamps `suite-card`
 * so the cascade picks up the shared primitive first. */
.m-card-block {
  box-shadow: var(--shadow-sm);
  padding: var(--sp-3h);
  margin-bottom: var(--sp-3);
}
.m-card-block h3 {
  font-family: var(--sans); font-size: var(--fs-xs); font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--g4);
  margin-bottom: var(--sp-2h);
}
.m-loc-path { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font-size: var(--fs-md); }
.m-loc-seg { color: var(--g4); }
.m-loc-seg.last { color: var(--text); font-weight: 600; }
.m-loc-sep { color: var(--g3); }
.m-loc-box {
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--g1); border-radius: var(--radius-xs); padding: 3px 8px;
  font-family: var(--mono); font-size: var(--fs-sm); color: var(--text);
}

/* Parts checklist (used on item-detail, mobile + desktop). */
.m-parts { list-style: none; padding: 0; margin: 0; }
.m-part {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2h) 0; border-bottom: 1px solid var(--g1);
}
.m-part:last-child { border-bottom: none; }
.m-part-name { flex: 1; font-size: var(--fs-md); }
.m-part.off .m-part-name { color: var(--g4); }

/* Qty counter (Camp guide inv-counter). */
.m-counter { display: grid; grid-template-columns: 56px 1fr 56px; align-items: center; justify-items: center; padding: var(--sp-4) 0 var(--sp-2); }
.m-counter .num { font-family: var(--serif); font-size: 52px; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -2px; } /* counter display, tabular numerals */
.m-counter button { width: 56px; height: 56px; border-radius: var(--radius-md); font-size: var(--fs-2xl); font-weight: 600; display: grid; place-items: center; }
.m-counter .plus { background: var(--green); color: var(--white); box-shadow: var(--shadow-md); }
.m-counter .minus { background: var(--g1); color: var(--text); }

/* Sticky action bar */
.m-actionbar {
  display: flex; gap: var(--sp-2h); margin-top: var(--sp-4);
}
.m-actionbar .btn-g, .m-actionbar .btn-gh, .m-actionbar .btn-b { flex: 1; padding: 12px; }

/* ── Sorties / checkout cards ──────────────────────────────────────────── */
/* .m-co-card composes onto @suite/lib/style/card.css `.suite-card`
 * (Tier H Step 1, 2026-06-12). Same arrangement as `.m-card-block`:
 * matos-specific extras are the tighter padding, always-on base
 * shadow, and a denser bottom margin for the checkout scroll list.
 * The `.late` modifier paints a red left rail (the
 * `.suite-card--alert` amber variant is the wrong colour here).
 *
 * The surface `background` was stripped 2026-06-13 for the same reason
 * as `.m-card-block`: `.suite-card`'s `var(--wh)` already flips for
 * dark mode and pinning `var(--white)` here would re-introduce the
 * bright-white-island regression. */
.m-co-card {
  box-shadow: var(--shadow-sm);
  padding: var(--sp-3h);
  margin-bottom: var(--sp-2h);
}
.m-co-card.late { border-left: 3px solid var(--red); }
.m-co-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-2); }
.m-co-title { font-family: var(--sans); font-size: var(--fs-md); color: var(--text); line-height: 1.1; }
.m-co-dest { font-size: var(--fs-sm); color: var(--g4); margin-top: 3px; }
.m-co-items { font-size: var(--fs-sm); color: var(--g4); margin-top: var(--sp-2h); padding-top: var(--sp-2h); border-top: 1px solid var(--g1); }

/* Items strip: flex-wrap row of compact chips. Shared between mobile +
   desktop checkout cards. */
.m-co-items-strip {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin-top: var(--sp-2h); padding-top: var(--sp-2h);
  border-top: 1px solid var(--g1);
}
.m-co-item-chip {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--g1); color: var(--text);
  border-radius: var(--radius-pill);
  padding: 3px 9px;
  font-size: var(--fs-sm); line-height: 1.3;
  max-width: 200px;
}
.m-co-item-chip-name {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 160px;
}
.m-co-item-chip-qty { color: var(--g4); font-variant-numeric: tabular-nums; }
.m-co-item-chip-more {
  text-decoration: none;
  background: transparent; color: var(--g4);
  border: 1px dashed var(--g2);
}
.m-co-item-chip-more:hover { background: var(--g1); color: var(--text); }
.m-co-notes {
  font-size: var(--fs-sm); color: var(--g4); font-style: italic;
  margin-top: var(--sp-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.m-co-foot { display: flex; align-items: center; justify-content: space-between; margin-top: var(--sp-3); gap: var(--sp-2); }

/* ── Scanner (mounted as full-screen overlay on mobile; also reusable) ── */
.m-scanner { position: absolute; inset: 0; background: #0c0c0c; color: var(--white); display: flex; flex-direction: column; z-index: 60; }
.m-scanner-top { padding: calc(env(safe-area-inset-top, 0px) + var(--sp-4)) var(--sp-4) var(--sp-3); display: flex; align-items: center; justify-content: space-between; }
.m-scanner-title { font-family: var(--sans); font-size: var(--fs-lg); color: var(--white); }
.m-scanner-close { width: 36px; height: 36px; border-radius: 50%; background: rgba(255,255,255,0.12); color: var(--white); display: grid; place-items: center; font-size: var(--fs-lg); }
.m-viewfinder { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-5); padding: var(--sp-4); }
.m-vf-box { width: 230px; height: 230px; position: relative; border-radius: var(--radius-lg); overflow: hidden; background: #000; }
.m-vf-box > video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.m-vf-box::before, .m-vf-box::after,
.m-vf-box > i::before, .m-vf-box > i::after {
  content: ""; position: absolute; width: 38px; height: 38px; border: 4px solid var(--y); z-index: 1;
}
.m-vf-box::before { top: 0; left: 0; border-right: none; border-bottom: none; border-top-left-radius: 14px; }
.m-vf-box::after { top: 0; right: 0; border-left: none; border-bottom: none; border-top-right-radius: 14px; }
.m-vf-box > i::before { bottom: 0; left: 0; border-right: none; border-top: none; border-bottom-left-radius: 14px; }
.m-vf-box > i::after { bottom: 0; right: 0; border-left: none; border-top: none; border-bottom-right-radius: 14px; }
.m-vf-scanline { position: absolute; left: 10px; right: 10px; height: 2px; background: var(--y); box-shadow: 0 0 12px 2px rgb(var(--y-rgb) / 60%); top: 50%; animation: m-scan 2.2s ease-in-out infinite; z-index: 1; pointer-events: none; }
@keyframes m-scan { 0%,100% { top: 14%; } 50% { top: 86%; } }
.m-scanner-hint { color: rgba(255,255,255,0.7); font-size: var(--fs-md); text-align: center; max-width: 240px; }
.m-scanner-manual-link { background: transparent; border: 0; color: var(--y); font-size: var(--fs-sm); padding: 4px 8px; text-decoration: underline; cursor: pointer; }
.m-scanner-manual { width: min(360px, 88vw); }
.m-scanner-manual-form { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; justify-content: center; }
.m-scanner-manual-form input { padding: var(--sp-2) var(--sp-3); border: 1px solid var(--g2); border-radius: 6px; min-width: 200px; font-family: var(--mono); background: var(--wh); color: var(--bk); }
.m-scanner-modes { display: flex; gap: var(--sp-2); justify-content: center; padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 40px); }
.m-scanner-mode { padding: 8px 14px; border-radius: var(--radius-pill); border: 1px solid rgba(255,255,255,0.25); color: rgba(255,255,255,0.8); font-size: var(--fs-sm); font-weight: 600; }
.m-scanner-mode.on { background: var(--y); color: var(--bk); border-color: var(--y); }

/* .m-sheet* removed 2026-06-12: scanner-sheet + return-sheet migrated to
 * @suite/lib/bottom-sheet (commit 7fec822); no remaining consumers in JS
 * or HTML. The canonical `.suite-sheet-*` rules live in
 * @suite/lib/style/bottom-sheet.css. */

/* Plus screen list */
.m-plus-list { background: var(--wh); border: 1px solid var(--g2); border-radius: var(--radius-md); overflow: hidden; }
.m-plus-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3h) var(--sp-3h); border-bottom: 1px solid var(--g1); width: 100%; text-align: left; font-size: var(--fs-md); }
.m-plus-row:last-child { border-bottom: none; }
.m-plus-row .ic { font-size: var(--fs-xl); width: 24px; text-align: center; }
.m-plus-row .chev { margin-left: auto; color: var(--g3); }

/* Density */
.matos-app.dense .m-feed-row { padding: 7px 0; }
.matos-app.dense .m-att-row { padding: var(--sp-2h) var(--sp-3); }
.matos-app.dense .m-item-card { padding: var(--sp-2h); }
.matos-app.dense .m-section-hd { margin: var(--sp-4) 0 var(--sp-2); }

/* Status indicator — banner mode strip */
.m-status-banner {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 8px; border-radius: var(--radius-xs);
  font-size: var(--fs-sm); font-weight: 600;
}
.m-status-banner.available { background: var(--bg-success); color: var(--fg-success); }
.m-status-banner.incomplete, .m-status-banner.low { background: var(--bg-warn); color: var(--fg-warn); }
.m-status-banner.repair { background: var(--bg-error); color: var(--fg-error); }
.m-status-banner.field { background: var(--bg-info); color: var(--blue); }
.m-status-led { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-sm); color: var(--g4); }

/* ═══════════════════════════════════════════════════════════════════════
   Revue annuelle (used on mobile + desktop with desktop overrides)
   ═══════════════════════════════════════════════════════════════════════ */
.m-review-cta {
  display: flex; align-items: center; gap: var(--sp-3);
  background: var(--bk); color: var(--white);
  border-radius: var(--radius-md); padding: var(--sp-3h);
  width: 100%; text-align: left; box-shadow: var(--shadow-md);
}
.m-review-cta .ic {
  width: 44px; height: 44px; border-radius: var(--radius-sm);
  background: var(--y); color: var(--bk); display: grid; place-items: center;
  font-size: var(--fs-2xl); flex-shrink: 0;
}
.m-review-cta-body { flex: 1; min-width: 0; }
.m-review-cta-title { font-family: var(--serif); font-size: var(--fs-lg); line-height: 1.1; }
.m-review-cta-sub { font-size: var(--fs-sm); color: var(--g3); margin-top: 3px; }
.m-review-cta .chev { color: var(--y); font-size: var(--fs-xl); }
.m-review-mini-bar { height: 4px; background: rgba(255,255,255,0.18); border-radius: 99px; overflow: hidden; margin-top: 8px; }
.m-review-mini-bar > i { display: block; height: 100%; background: var(--y); border-radius: 99px; }

.m-review { position: absolute; inset: 0; background: var(--wh); display: flex; flex-direction: column; z-index: 55; }
.m-review-top { flex-shrink: 0; padding: 52px var(--sp-4) var(--sp-3); background: var(--wh); border-bottom: 1px solid var(--g2); }
.m-review-top-row { display: flex; align-items: center; gap: var(--sp-3); }
.m-review-close { width: 34px; height: 34px; border-radius: 50%; background: var(--g1); color: var(--g4); display: grid; place-items: center; font-size: var(--fs-lg); flex-shrink: 0; }
.m-review-head { flex: 1; min-width: 0; }
.m-review-camp { font-family: var(--sans); font-size: var(--fs-md); color: var(--text); line-height: 1; }
.m-review-count { font-size: var(--fs-xs); color: var(--g4); font-weight: 600; margin-top: 2px; }
.m-review-progress { height: 6px; background: var(--g1); border-radius: 99px; overflow: hidden; margin-top: var(--sp-3); }
.m-review-progress > i { display: block; height: 100%; background: var(--green); border-radius: 99px; transition: width var(--dur-slow) ease; }

.m-review-body { flex: 1; overflow-y: auto; padding: var(--sp-4) var(--sp-4) 24px; }
.m-review-card-hd { display: flex; align-items: flex-start; gap: var(--sp-3); margin-bottom: var(--sp-3h); }
.m-review-thumb { width: 52px; height: 52px; border-radius: var(--radius-sm); background: var(--g1); display: grid; place-items: center; font-size: var(--fs-3xl); flex-shrink: 0; }
.m-review-name { font-family: var(--serif); font-size: 1.45rem; line-height: 1.05; color: var(--text); } /* between --fs-xl and --fs-2xl; no exact token */
.m-review-sub { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 5px; font-size: var(--fs-sm); color: var(--g4); }
.m-review-last { display: inline-flex; align-items: center; gap: 5px; font-size: var(--fs-sm); padding: 4px 9px; border-radius: var(--radius-pill); background: var(--g1); color: var(--g4); white-space: nowrap; }
.m-review-last.stale { background: var(--bg-warn); color: var(--fg-warn); }

.m-seg { display: flex; gap: var(--sp-2); }
.m-seg button {
  flex: 1; padding: 8px 4px; border-radius: var(--radius-sm);
  border: 1px solid var(--g2); background: var(--surface-card); color: var(--g4);
  font-size: var(--fs-sm); font-weight: 600; display: flex; flex-direction: column; align-items: center; gap: 3px;
}
.m-seg button .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--g3); }
.m-seg button.on { border-color: var(--bk); color: var(--text); background: var(--g1); }
.m-seg button.on.ok .dot { background: var(--green); }
.m-seg button.on.warn .dot { background: var(--y); }
.m-seg button.on.bad .dot { background: var(--red); }

.m-review-foot {
  flex-shrink: 0; padding: var(--sp-3) var(--sp-4) calc(var(--sp-3) + 22px);
  background: var(--wh); border-top: 1px solid var(--g2); box-shadow: 0 -4px 16px rgba(0,0,0,0.05);
}
.m-review-foot-row { display: flex; gap: var(--sp-2h); }
.m-review-foot .btn-g, .m-review-foot .btn-gh { padding: 13px; }
.m-review-foot .grow { flex: 1; }
.m-review-skip { display: block; width: 100%; text-align: center; margin-top: var(--sp-2h); font-size: var(--fs-sm); color: var(--g4); font-weight: 600; }

.m-review-edit-toggle {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%; padding: 11px; margin-top: var(--sp-2);
  border: 1px dashed var(--g3); border-radius: var(--radius-sm);
  background: var(--surface-card); color: var(--g4); font-size: var(--fs-md); font-weight: 600;
}
.m-review-edit-toggle.open { border-style: solid; border-color: var(--g2); color: var(--text); }

.m-review-done { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: var(--sp-6) var(--sp-5); }
.m-review-done .seal { width: 92px; height: 92px; border-radius: 50%; background: var(--y); color: var(--bk); display: grid; place-items: center; font-size: 46px; margin-bottom: var(--sp-4); box-shadow: var(--shadow-lg); } /* large celebratory icon — no fs-* token covers 46px */
.m-review-done h2 { font-family: var(--serif); font-size: var(--fs-3xl); line-height: 1.05; margin-bottom: var(--sp-2); }
.m-review-done p { color: var(--g4); font-size: var(--fs-md); max-width: 260px; margin: 0 auto var(--sp-5); }
.m-review-tally { display: flex; gap: var(--sp-3); width: 100%; margin-bottom: var(--sp-5); }
.m-review-tally .cell { flex: 1; background: var(--surface-card); border: 1px solid var(--g2); border-radius: var(--radius-md); padding: var(--sp-3) var(--sp-2); }
.m-review-tally .n { font-family: var(--serif); font-size: var(--fs-2xl); color: var(--text); line-height: 1; }
.m-review-tally .l { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--g4); margin-top: 5px; }

/* ═══════════════════════════════════════════════════════════════════════
   Cataloguer / Lieux / Catégories forms (used on every screen size)
   ═══════════════════════════════════════════════════════════════════════ */
.m-field { margin-bottom: var(--sp-3h); }
.m-field > label { display: block; font-size: var(--fs-sm); font-weight: 700; letter-spacing: 0.02em; color: var(--g4); margin-bottom: 6px; }
.m-input, .m-select {
  /* iOS Safari zoom-on-focus defence: raw 16px (not a token) so a future
     --fs-lg rebase can't accidentally drop below 16 and reintroduce the zoom. */
  width: 100%; font-family: var(--sans); font-size: 16px; color: var(--text);
  background: var(--surface-card); border: 1px solid var(--g2); border-radius: var(--radius-sm);
  padding: 11px var(--sp-3); outline: none; -webkit-appearance: none; appearance: none;
}
.m-input:focus, .m-select:focus { border-color: var(--bk); box-shadow: 0 0 0 3px var(--focus-ring); }
.m-input::placeholder { color: var(--g3); }
.m-select { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%236e6b62' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 14px center; padding-right: 34px; }
.m-field-hint { font-size: var(--fs-sm); color: var(--g4); margin-top: 5px; }
.m-type-toggle { display: flex; gap: var(--sp-2); }
.m-type-toggle .btn-gh { flex: 1; padding: 11px; }
.m-loc-grid { display: grid; grid-template-columns: 1fr 1fr 72px; gap: var(--sp-2); }
.m-dup-hint { margin-top: var(--sp-2); padding: var(--sp-2h) var(--sp-3); border-radius: var(--radius-sm); background: var(--bg-info); color: var(--g4); font-size: var(--fs-sm); }
.m-dup-hint b { color: var(--text); }
.m-dup-hint a { display: block; padding: 4px 0; color: var(--g4); text-decoration: none; border-bottom: 1px dotted var(--g3); }
.m-dup-hint a:last-child { border-bottom: none; }

/* Lieux */
.m-loc-section { display: flex; align-items: baseline; gap: 8px; margin: var(--sp-5) 0 var(--sp-2h); }
.m-loc-section:first-of-type { margin-top: var(--sp-4); }
.m-loc-section .nm { font-family: var(--serif); font-size: var(--fs-lg); color: var(--text); }
.m-loc-section .sub { font-size: var(--fs-sm); color: var(--g4); }
.m-shelf-row { display: flex; align-items: center; gap: var(--sp-3); padding: 11px var(--sp-3h); border-bottom: 1px solid var(--g1); width: 100%; text-align: left; }
.m-shelf-row:last-child { border-bottom: none; }
.m-shelf-row .nm { flex: 1; font-weight: 500; font-size: var(--fs-md); }
.m-shelf-row .chev { color: var(--g3); }

/* Catégories grid */
.m-cat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2h); }
.m-cat-tile { background: var(--surface-card); border: 1px solid var(--g2); border-radius: var(--radius-md); box-shadow: var(--shadow-sm); padding: var(--sp-3h); text-align: left; width: 100%; }
.m-cat-swatch { width: 46px; height: 46px; border-radius: var(--radius-sm); display: grid; place-items: center; font-size: var(--fs-3xl); margin-bottom: var(--sp-2h); }
.m-cat-name { font-weight: 600; font-size: var(--fs-md); color: var(--text); }
.m-cat-count { font-size: var(--fs-sm); color: var(--g4); margin-top: 2px; }
.m-bars { display: flex; flex-direction: column; gap: var(--sp-2h); }
.m-bar-row { display: grid; grid-template-columns: 84px 1fr 32px; gap: var(--sp-2); align-items: center; }
.m-bar-row .lbl { font-size: var(--fs-sm); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.m-bar-track { background: var(--g1); border-radius: 4px; height: 13px; overflow: hidden; }
.m-bar-track > i { display: block; height: 100%; background: var(--y); border-radius: 4px; }
.m-bar-row .val { font-size: var(--fs-sm); text-align: right; color: var(--g4); font-variant-numeric: tabular-nums; }

/* ═══════════════════════════════════════════════════════════════════════
   Caisses / contenants + return-reporting tags
   ═══════════════════════════════════════════════════════════════════════ */
.m-box-cap { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 8px; }
.m-box-cap .n { font-family: var(--serif); font-size: var(--fs-md); color: var(--text); }
.m-box-cap .x { font-size: var(--fs-sm); color: var(--g4); }
.m-box-meter { height: 6px; background: var(--g1); border-radius: 99px; overflow: hidden; }
.m-box-meter > i { display: block; height: 100%; background: var(--bk); border-radius: 99px; }

.m-content-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 10px var(--sp-1); border-bottom: 1px solid var(--g1); width: 100%; text-align: left;
}
.m-content-row:last-child { border-bottom: none; }
.m-content-thumb { width: 36px; height: 36px; border-radius: var(--radius-sm); background: var(--g1); display: grid; place-items: center; font-size: var(--fs-xl); flex-shrink: 0; }
.m-content-main { flex: 1; min-width: 0; }
.m-content-name { font-weight: 500; font-size: var(--fs-md); color: var(--text); }
.m-content-sub { font-size: var(--fs-xs); color: var(--g4); margin-top: 1px; }
.m-content-trail { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.m-content-qty { font-family: var(--serif); font-size: 1rem; color: var(--text); } /* 1rem = browser default; no matching fs-* token */
.m-verify-check {
  width: 26px; height: 26px; border-radius: 50%; border: 2px solid var(--g2);
  background: var(--surface-card); display: grid; place-items: center; color: transparent; flex-shrink: 0;
  font-size: var(--fs-md); font-weight: 700;
}
.m-verify-check.on { background: var(--green); border-color: var(--green); color: var(--white); }

.m-caisse-pill {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--bk); color: var(--white); border-radius: var(--radius-xs);
  padding: 2px 7px; font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.03em; text-transform: uppercase;
}

.m-tag-grid { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-2) 0 var(--sp-3); }
.m-tag {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 9px 13px; border-radius: var(--radius-pill);
  border: 1px solid var(--g2); background: var(--surface-card); color: var(--g4);
  font-size: var(--fs-md); font-weight: 600;
}
.m-tag.on { background: var(--bk); color: var(--white); border-color: var(--bk); }
.m-tag.on.warn { background: var(--bg-warn); color: var(--fg-warn); border-color: var(--y); }
.m-tag.on.bad { background: var(--bg-error); color: var(--fg-error); border-color: var(--red); }
.m-tag.on.ok { background: var(--bg-success); color: var(--fg-success); border-color: var(--green); }
.m-note-input {
  width: 100%; font-family: var(--sans); font-size: var(--fs-md); color: var(--text);
  background: var(--surface-card); border: 1px solid var(--g2); border-radius: var(--radius-sm);
  padding: 10px var(--sp-3); outline: none; resize: none; min-height: 60px;
}
.m-note-input:focus { border-color: var(--bk); box-shadow: 0 0 0 3px var(--focus-ring); }

/* ═══════════════════════════════════════════════════════════════════════
   Valeur & amortissement (amort card — shared)
   ═══════════════════════════════════════════════════════════════════════ */
.m-amort-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.m-amort-book { line-height: 1; }
.m-amort-book .n { font-family: var(--serif); font-size: var(--fs-3xl); color: var(--text); font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }
.m-amort-book .l { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--g4); margin-top: 4px; }
.m-amort-orig { text-align: right; font-size: var(--fs-sm); color: var(--g4); line-height: 1.3; }
.m-amort-orig b { color: var(--text); font-weight: 600; }
.m-amort-bar { height: 8px; background: var(--g1); border-radius: 99px; overflow: hidden; position: relative; }
.m-amort-bar > i { display: block; height: 100%; background: linear-gradient(90deg, var(--green), var(--amber)); border-radius: 99px; }
.m-amort-bar.done > i { background: var(--g3); }
.m-amort-scale { display: flex; justify-content: space-between; font-size: var(--fs-xs); color: var(--g4); margin-top: 6px; }
.m-amort-rows { margin-top: var(--sp-3); border-top: 1px solid var(--g1); padding-top: var(--sp-2h); }
.m-amort-row { display: flex; align-items: center; justify-content: space-between; padding: 5px 0; font-size: var(--fs-md); }
.m-amort-row .k { color: var(--g4); }
.m-amort-row .v { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.m-amort-add {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 13px; border: 1px dashed var(--g3); border-radius: var(--radius-sm);
  background: var(--surface-card); color: var(--g4); font-size: var(--fs-md); font-weight: 600; justify-content: center;
}

/* ═══════════════════════════════════════════════════════════════════════
   Créer hub + Réservation builder
   ═══════════════════════════════════════════════════════════════════════ */
.m-hub-group { margin-top: var(--sp-4); }
.m-hub-group:first-of-type { margin-top: var(--sp-2); }
.m-hub-glabel { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--g4); margin-bottom: var(--sp-2); }
.m-hub-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3h); border-bottom: 1px solid var(--g1); width: 100%; text-align: left; }
.m-hub-row:last-child { border-bottom: none; }
.m-hub-ic { width: 40px; height: 40px; border-radius: var(--radius-sm); background: var(--g1); display: grid; place-items: center; font-size: var(--fs-2xl); flex-shrink: 0; }
.m-hub-ic.y { background: var(--y); }
.m-hub-tx { flex: 1; min-width: 0; }
.m-hub-tx .nm { display: block; font-weight: 600; font-size: var(--fs-md); color: var(--text); }
.m-hub-tx .ds { display: block; font-size: var(--fs-sm); color: var(--g4); margin-top: 1px; }
.m-hub-row .chev { color: var(--g3); }

.m-picker { position: relative; }
.m-picker-results { border: 1px solid var(--g2); border-radius: var(--radius-sm); margin-top: var(--sp-1); overflow: hidden; background: var(--surface-card); }
.m-picker-result { display: flex; align-items: center; gap: var(--sp-2h); padding: 9px var(--sp-3); border-bottom: 1px solid var(--g1); width: 100%; text-align: left; }
.m-picker-result:last-child { border-bottom: none; }
.m-picker-result .ic { font-size: var(--fs-xl); }
.m-picker-result .nm { flex: 1; font-size: var(--fs-md); }
.m-picker-result .cd { font-family: var(--mono); font-size: var(--fs-xs); color: var(--g4); }
.m-picker-result .add { color: var(--green); font-weight: 700; font-size: var(--fs-xl); }

.m-cart { background: var(--surface-card); border: 1px solid var(--g2); border-radius: var(--radius-md); overflow: hidden; }
.m-cart-row { display: flex; align-items: center; gap: var(--sp-2h); padding: 10px var(--sp-3); border-bottom: 1px solid var(--g1); }
.m-cart-row:last-child { border-bottom: none; }
.m-cart-ic { font-size: var(--fs-xl); width: 26px; text-align: center; }
.m-cart-main { flex: 1; min-width: 0; }
.m-cart-name { font-size: var(--fs-md); font-weight: 500; color: var(--text); }
.m-cart-code { font-family: var(--mono); font-size: var(--fs-xs); color: var(--g4); }
.m-cart-rm { color: var(--g4); font-size: var(--fs-lg); width: 28px; height: 28px; display: grid; place-items: center; border-radius: var(--radius-xs); }
.m-qty-step { display: flex; align-items: center; gap: 0; border: 1px solid var(--g2); border-radius: var(--radius-sm); overflow: hidden; }
.m-qty-step button { width: 30px; height: 30px; display: grid; place-items: center; font-size: var(--fs-lg); background: var(--g1); color: var(--text); }
.m-qty-step .q { width: 30px; text-align: center; font-size: var(--fs-md); font-weight: 600; font-variant-numeric: tabular-nums; }
.m-cart-empty { padding: var(--sp-5) var(--sp-4); text-align: center; color: var(--g4); font-size: var(--fs-md); border: 1px dashed var(--g2); border-radius: var(--radius-md); }

.m-camp-opt { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3); border: 1px solid var(--g2); border-radius: var(--radius-sm); background: var(--surface-card); width: 100%; text-align: left; margin-bottom: var(--sp-2); }
.m-camp-opt.on { border-color: var(--bk); box-shadow: 0 0 0 2px var(--bk) inset; }
.m-camp-opt .nm { font-weight: 600; font-size: var(--fs-md); color: var(--text); }
.m-camp-opt .ds { font-size: var(--fs-sm); color: var(--g4); margin-top: 1px; }
.m-camp-opt .rd { width: 20px; height: 20px; border-radius: 50%; border: 2px solid var(--g2); flex-shrink: 0; }
.m-camp-opt.on .rd { border-color: var(--bk); background: radial-gradient(var(--bk) 38%, transparent 42%); }

.m-swatch-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.m-swatch { width: 40px; height: 40px; border-radius: var(--radius-sm); display: grid; place-items: center; font-size: var(--fs-2xl); border: 1px solid var(--g2); background: var(--surface-card); }
.m-swatch.on { border-color: var(--bk); box-shadow: 0 0 0 2px var(--bk) inset; }
.m-color-dot { width: 34px; height: 34px; border-radius: 50%; border: 2px solid transparent; }
.m-color-dot.on { border-color: var(--bk); }

/* ── Étiquette QR · Équipe · Réglages ─────────────────────────────────── */
.m-label-card { background: var(--surface-card); border: 1px solid var(--g2); border-radius: var(--radius-md); box-shadow: var(--shadow-sm); padding: var(--sp-5); text-align: center; }
.m-qr { width: 170px; height: 170px; margin: 0 auto var(--sp-3); border-radius: var(--radius-sm); display: grid; grid-template-columns: repeat(11, 1fr); grid-template-rows: repeat(11, 1fr); gap: 2px; padding: 8px; background: var(--white); border: 1px solid var(--g2); }
.m-qr i { background: var(--bk); border-radius: 1px; }
.m-qr i.o { background: transparent; }
.m-label-name { font-family: var(--serif); font-size: var(--fs-xl); color: var(--text); line-height: 1.1; margin-top: var(--sp-2); }
.m-label-code { font-family: var(--mono); font-size: var(--fs-md); color: var(--g4); margin-top: 4px; letter-spacing: 0.05em; }

.m-team-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-3h); border-bottom: 1px solid var(--g1); }
.m-team-row:last-child { border-bottom: none; }
.m-team-av { width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center; color: var(--white); font-size: var(--fs-md); font-weight: 700; flex-shrink: 0; }
.m-team-main { flex: 1; min-width: 0; }
.m-team-name { font-weight: 600; font-size: var(--fs-md); color: var(--text); }
.m-team-role { font-size: var(--fs-sm); color: var(--g4); margin-top: 1px; }

.m-set-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3h); border-bottom: 1px solid var(--g1); width: 100%; text-align: left; font-size: var(--fs-md); }
.m-set-row:last-child { border-bottom: none; }
.m-set-row .ic { font-size: var(--fs-xl); width: 24px; text-align: center; }
.m-set-row .val { margin-left: auto; color: var(--g4); font-size: var(--fs-md); }
.m-set-row .chev { color: var(--g3); margin-left: 6px; }
.m-toggle { width: 42px; height: 25px; border-radius: 99px; background: var(--g2); position: relative; flex-shrink: 0; transition: background var(--dur-normal); }
.m-toggle.on { background: var(--green); }
.m-toggle::after { content: ""; position: absolute; top: 2px; left: 2px; width: 21px; height: 21px; border-radius: 50%; background: var(--white); transition: transform var(--dur-normal); box-shadow: var(--shadow-sm); }
.m-toggle.on::after { transform: translateX(17px); }

.m-amort-mode { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-2h); }
.m-amort-mode button { flex: 1; padding: 8px; border-radius: var(--radius-sm); border: 1px solid var(--g2); background: var(--surface-card); color: var(--g4); font-size: var(--fs-sm); font-weight: 600; }
.m-amort-mode button.on { border-color: var(--bk); background: var(--g1); color: var(--text); }
.m-amort-preview { background: var(--g1); border-radius: var(--radius-sm); padding: var(--sp-2h) var(--sp-3); margin-top: var(--sp-2h); font-size: var(--fs-sm); color: var(--g4); }
.m-amort-preview b { color: var(--text); font-weight: 600; }

/* Multi-photo gallery — used on mobile + desktop item-detail / item-edit. */
.m-photo-grid { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.m-photo-grid image-slot { border-radius: var(--radius-sm); }
.m-photo-tile {
  display: block;
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: opacity var(--dur-normal);
}
.m-photo-tile:hover { opacity: 0.85; }
.m-photo-tile:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}
.m-photo-add {
  width: 92px; height: 92px; flex-shrink: 0;
  border: 1px dashed var(--g3); border-radius: var(--radius-sm);
  background: var(--surface-card); color: var(--g4);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  font-size: var(--fs-sm); font-weight: 600;
}
.m-photo-add .pl { font-size: var(--fs-2xl); line-height: 1; }
.m-photo-add:active { background: var(--g1); }
.m-photo-rm:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* item-detail top action bar wrapper */
.m-detail-actionbar-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
}

/* ── PWA install banner (shared chrome; mobile-tail positioning lives in
   matos-mobile.css; desktop top-right positioning lives in
   matos-desktop.css). ──────────────────────────────────────────────── */
.matos-install-banner {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + var(--sp-2));
  right: var(--sp-3);
  left: var(--sp-3);
  margin: 0 auto;
  max-width: 380px;
  background: var(--bk);
  color: var(--white);
  border-radius: 14px;
  box-shadow: var(--shadow-lg, 0 10px 30px rgba(0,0,0,0.25));
  z-index: 200;
  display: flex;
  align-items: stretch;
  overflow: hidden;
  font-size: var(--fs-md);
  -webkit-tap-highlight-color: transparent;
}
.matos-install-banner-accent {
  width: 5px;
  background: var(--y);
  flex-shrink: 0;
}
.matos-install-banner-main {
  flex: 1;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-2h);
  min-width: 0;
}
.matos-install-banner-body {
  flex: 1;
  min-width: 0;
  line-height: 1.4;
}
.matos-install-banner-title {
  font-weight: 600;
  font-size: var(--fs-md);
  margin-bottom: 2px;
}
.matos-install-banner-step {
  font-size: var(--fs-sm);
  color: rgba(255, 255, 255, 0.78);
  line-height: 1.45;
}
.matos-install-banner-cta {
  background: var(--y);
  color: var(--bk);
  padding: 8px 14px;
  border-radius: var(--radius-sm);
  font-weight: 700;
  font-size: var(--fs-md);
  border: 0;
  cursor: pointer;
  flex-shrink: 0;
  min-height: 36px;
  min-width: 44px;
  -webkit-tap-highlight-color: transparent;
}
.matos-install-banner-cta:active { transform: scale(0.97); }
.matos-install-banner-close {
  background: none;
  color: rgba(255, 255, 255, 0.78);
  border: 0;
  cursor: pointer;
  font-size: var(--fs-2xl);
  line-height: 1;
  padding: 0 14px;
  flex-shrink: 0;
  min-width: 44px;
  min-height: 44px;
  -webkit-tap-highlight-color: transparent;
}
.matos-install-banner-close:hover { color: var(--white); }

/* ── Dark-mode foreground overrides ─────────────────────────────────────
   --bk / --bk2 / --bk3 are non-flipping accent tokens. Explicit
   `color: var(--bk*)` on rules whose background flips in dark mode
   becomes dark-on-dark; the rules below re-route those text colours
   to --g4 (which flips) so contrast stays ≥ 4.5:1. */
@media (prefers-color-scheme: dark) {
  .photo-lightbox-caption-input {
    color: var(--g4);
  }
  .matos-plus-row {
    color: var(--g4);
  }
  .cmdk-trigger,
  .cmdk-trigger kbd {
    color: var(--g4);
  }
  .cmdk-palette,
  .cmdk-result {
    color: var(--g4);
  }
  .modal-search:focus-visible {
    border-color: var(--g4);
  }

  /* Desktop chrome — every serif title / stat / table cell that pinned
     `color: var(--bk)` is invisible in dark mode (--bk doesn't flip).
     Re-route to --g4 / --wh as appropriate. matos-desktop.css selectors
     covered: d-topbar-title, d-h1, d-sec-title, d-stat .n, d-card-hd .t,
     d-att .n, d-feed-row .tx, d-trow .nm/.qty, d-cmdk-item, .ph h2. */
  .d-topbar-title,
  .d-h1,
  .d-sec-title,
  .d-stat .n,
  .d-card-hd .t,
  .d-att .n,
  .d-feed-row .tx,
  .d-trow .nm,
  .d-trow .qty,
  .d-cmdk-item {
    color: var(--g4);
  }
  /* The .d-icon-btn pins `background: var(--white); color: var(--bk)`
     — --white doesn't flip, so the button is a bright white island
     on a dark page (functional but high-contrast). Soften it to a
     dark-surface variant matching the rest of the chrome. */
  .d-icon-btn {
    background: var(--g1);
    border-color: var(--g3);
    color: var(--g4);
  }
  .d-icon-btn:hover {
    background: var(--g2);
  }
  /* .d-select focus ring uses --bk for border-color — re-route. */
  .d-select:focus {
    border-color: var(--g4);
  }

  /* Mobile / shared chrome — same rationale as desktop block. */
  .edit-loc-tab.active,
  .creer-tabs .tag-chip.is-active,
  .apercu-cta {
    color: var(--g4);
  }

  /* Review screen — full-page overlay with `background: var(--wh)`
     (flips to dark). Its serif "camp name" + "item name" titles
     pin --bk → invisible. Re-route. */
  .m-review-camp,
  .m-review-name {
    color: var(--g4);
  }
  /* Review screen progress mini-bar — `rgba(255,255,255,0.18)` track
     is meant to read as "muted on dark CTA card". In light mode it's
     invisible (white-on-white). Use --g2 so the track is visible in
     BOTH modes while the yellow fill (--y) keeps its accent role. */
  .m-review-mini-bar {
    background: var(--g2);
  }

  /* Photo lightbox hover state — 8% white overlay disappears on dark.
     Bump to 15% so the hover affordance reads. */
  .photo-lightbox-caption:hover,
  .photo-lightbox-caption:focus-visible {
    background: rgba(255, 255, 255, 0.15);
  }
}

/* Light-mode-only progress bar track fix. --m-review-mini-bar's
   rgba(255,255,255,0.18) track is invisible against the off-white
   page background. Use --g2 for a visible muted track in both modes. */
@media (prefers-color-scheme: light) {
  .m-review-mini-bar {
    background: var(--g2);
  }
}

/* ── Dark-mode heading + border sweep (2026-06-13) ───────────────────────
   Two systemic bugs from a live dark-mode review:

   (a) Page H1 / section titles (`.m-h1`, `.m-h2`, `.m-section-title`)
       and several inside-card numerics pin `color: var(--bk)`. --bk
       doesn't flip, so dark serif text becomes invisible on the dark
       page surface. Re-route to --g4 (the flipping body-text token).

   (b) The surfaces that *did* pin `background: var(--white)` (the
       never-flipping pure-white token) are now updated at the source
       to use `var(--wh)` (the flipping page-surface token) — so they
       flip "for free" in dark mode. Composed cards (.m-card-block,
       .m-co-card) inherit the flipping surface from `.suite-card`.
       The earlier paper-over override (`background: var(--wh)` per
       class) was stripped because the base rules now carry --wh.

   The only structural override left for dark mode is lifting borders
   from --g2 → --g3 so the card edge stays visible on the dark surface
   (--g2 collides with the page background in dark mode). */
@media (prefers-color-scheme: dark) {
  /* Borders need to be lifted from --g2 → --g3 so the card edge stays
     visible against the dark page background. */
  .m-stat,
  .m-search,
  .m-item-card,
  .m-plus-list,
  .d-stat,
  .d-card,
  .d-panel,
  .d-block,
  .d-table,
  .d-search,
  .d-search:hover,
  .d-search .kbd,
  .d-searchbox,
  .d-select {
    border-color: var(--g3);
  }

  /* Inline buttons (.btn, .btn-gh) stay pure-white intentionally —
     they're tap targets that should stand out from the surface. */

  /* Headings + numerics pinned to --bk over a flipping surface */
  .m-h1,
  .m-h2,
  .m-section-title,
  .m-stat-num,
  .m-att-count,
  .m-feed-text,
  .m-search input,
  .matos-app {
    color: var(--g4);
  }
  /* The .m-att-row uses --g1 as its hairline border; in light mode
     that's a near-white separator on a white card, in dark mode that
     becomes the same dark gray as the card surface (invisible).
     Lift to --g2 so the row separators stay visible on either side. */
  .m-att-row,
  .m-feed-row {
    border-bottom-color: var(--g2);
  }
}

/* Selection footer — multi-select bulk-print + future bulk actions */
.selection-footer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: var(--bottom-bar-height, 0);
  background: var(--surface-card);
  border-top: 1px solid var(--g2);
  padding: var(--sp-2) var(--sp-4);
  display: flex;
  align-items: center;
  justify-content: space-between;
  z-index: 30;
}
.selection-footer[hidden] {
  display: none;
}
.selection-count {
  font-weight: 600;
}

/* ── Multi-page label editor (2026-06-17) ─────────────────────────────
   Compact cell grid replacing the SheetPicker + flat HTML preview. */
.lbl-page-editor {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin: var(--sp-3) 0;
}
.lbl-page {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.lbl-page-header {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--g4);
  margin: 0 0 var(--sp-1);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
/* Grid layout 2026-06-17: fixed cell HEIGHT instead of `1fr` columns.
   `repeat(N, 1fr)` made cell size depend on container width AND col
   count, so L7166 (2 cols, near-square) ballooned to ~380px-tall
   monsters while L7651 (5 cols) shrank to barely-readable. With
   `grid-auto-rows: var(--lbl-cell-h)` + `repeat(N, auto)` columns,
   every cell is the same fixed height (~110px) and width follows from
   the cell's own aspect-ratio. Stocks look consistent at a glance;
   page width grows naturally with more columns (horizontal scroll for
   the very-many-col stocks like L4731 7×27). */
.lbl-page-grid {
  --lbl-cell-h: 110px;
  display: grid;
  grid-template-columns: repeat(var(--lbl-cols, 3), auto);
  grid-auto-rows: var(--lbl-cell-h);
  gap: var(--sp-1);
  justify-content: start;
  max-width: 100%;
  overflow-x: auto;
}
/* Cells RESEMBLE the printed label: white paper background, the
   stock's actual aspect ratio, QR on one side + text stack on the
   other (side-by-side for wide cells, stacked for square/tall).
   Mirrors the PDF renderer's per-aspect layout choice. */
.lbl-page-grid .lbl-cell {
  background: #fff;
  color: var(--bk);
  border: 1px solid var(--g2);
  border-radius: var(--radius-xs);
  padding: var(--sp-1);
  cursor: pointer;
  /* Fixed height (set on the grid), width derived from aspect. */
  height: var(--lbl-cell-h);
  width: calc(var(--lbl-cell-h) * var(--lbl-aspect, 1));
  display: flex;
  align-items: stretch;
  gap: var(--sp-1);
  position: relative;
  font-family: inherit;
  overflow: hidden;
}
.lbl-page.is-side-by-side .lbl-page-grid .lbl-cell {
  flex-direction: row;
}
.lbl-page.is-stacked .lbl-page-grid .lbl-cell {
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.lbl-page-grid .lbl-cell.is-skipped {
  background: var(--g1);
  border-color: var(--g3);
}
.lbl-page-grid .lbl-cell.is-skipped::after {
  content: '✕';
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 28px; /* large cell X-out glyph — no fs-* token covers 28px */
  color: var(--red);
  pointer-events: none;
}
.lbl-page-grid .lbl-cell.is-empty {
  background: transparent;
  border: 1px dashed var(--g2);
  cursor: default;
}
/* QR slot — square, sits on the left in side-by-side, on top in stacked. */
.lbl-page-grid .lbl-cell-qr-wrap {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
}
.lbl-page.is-side-by-side .lbl-page-grid .lbl-cell-qr-wrap {
  height: 100%;
  width: auto;
}
.lbl-page.is-stacked .lbl-page-grid .lbl-cell-qr-wrap {
  width: 70%;
  max-height: 60%;
}
.lbl-page-grid .lbl-cell-qr {
  width: 100%;
  height: 100%;
  display: block;
}
/* Text/meta stack on the other side of the QR. */
.lbl-page-grid .lbl-cell-meta {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  gap: 1px;
}
.lbl-page.is-side-by-side .lbl-page-grid .lbl-cell-meta {
  align-items: flex-start;
  text-align: left;
}
.lbl-page-grid .lbl-cell-code {
  font-weight: 700;
  font-size: 11px; /* label-print millimeter-precision */
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.lbl-page-grid .lbl-cell-name {
  font-size: 9px; /* label-print millimeter-precision */
  display: block;
  opacity: 0.85;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* Per-cell +/− count controls. */
.lbl-cell-count {
  position: absolute;
  bottom: 2px;
  right: 4px;
  display: flex;
  gap: 2px;
  opacity: 0.6;
}
.lbl-cell:hover .lbl-cell-count {
  opacity: 1;
}
.lbl-cell-count-plus,
.lbl-cell-count-minus {
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border-radius: var(--radius-xs);
  background: rgba(0, 0, 0, 0.08);
  color: var(--bk);
  font-size: var(--fs-md);
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  user-select: none;
}
.lbl-cell-count-plus:hover,
.lbl-cell-count-minus:hover {
  background: rgba(0, 0, 0, 0.18);
}

/* Category badge + location chain inside the meta stack. */
.lbl-page-grid .lbl-cell-cat {
  font-size: 8px; /* label-print millimeter-precision */
  font-weight: 500;
  opacity: 0.7;
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.lbl-page-grid .lbl-cell-loc {
  font-size: 8px; /* label-print millimeter-precision */
  font-weight: 400;
  opacity: 0.6;
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* Skip-toggle button (top-right of each cell). */
.lbl-cell-skip {
  position: absolute;
  top: 2px;
  right: 4px;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: var(--radius-xs);
  background: rgba(0, 0, 0, 0.06);
  color: var(--bk);
  font-size: var(--fs-md);
  line-height: 1;
  cursor: pointer;
  user-select: none;
  opacity: 0.5;
  z-index: 1;
}
.lbl-cell:hover .lbl-cell-skip {
  opacity: 1;
}
.lbl-cell-skip:hover {
  background: rgba(200, 0, 0, 0.18);
  color: var(--red);
}
.lbl-cell.is-skipped .lbl-cell-skip {
  opacity: 1;
  background: rgba(255, 255, 255, 0.85);
  color: var(--bk);
}
.lbl-cell.is-skipped .lbl-cell-skip:hover {
  background: var(--y);
}

/* Queue-count badge — shows how many instances of this code are in
   the print queue. Editor-only; never drawn on the PDF. */
.lbl-cell-count-badge {
  position: absolute;
  top: 2px;
  left: 4px;
  display: inline-block;
  padding: 1px 5px;
  border-radius: 999px;
  background: var(--bk);
  color: #fff;
  font-size: var(--fs-xs);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0.02em;
  z-index: 1;
  pointer-events: none;
}

/* Trash button — sits next to +/− in the bottom-right control cluster.
   Deletes EVERY instance of this code from the queue. Slightly larger
   accent + hover color so it reads as "destructive". */
.lbl-cell-count-trash {
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border-radius: var(--radius-xs);
  background: rgba(0, 0, 0, 0.08);
  color: var(--bk);
  font-size: var(--fs-xs);
  line-height: 1;
  cursor: pointer;
  user-select: none;
}
.lbl-cell-count-trash:hover {
  background: rgba(200, 0, 0, 0.2);
  color: var(--red);
}

/* "−" disabled state — count is at 1; the operator must reach for the
   trash to remove the last instance. Visual gray, no cursor change. */
.lbl-cell-count-minus.is-disabled {
  opacity: 0.35;
  cursor: not-allowed;
  background: rgba(0, 0, 0, 0.04);
}
.lbl-cell-count-minus.is-disabled:hover {
  background: rgba(0, 0, 0, 0.04);
}

/* "Ajouter par code" bar sits above the multi-page editor. Compact
   inline input + button + a polite error slot. */
.lbl-batch-add-bar {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: var(--sp-2) 0;
}
.lbl-batch-add-input {
  flex: 0 0 220px;
  padding: 6px 10px;
  border: 1px solid var(--g2);
  border-radius: var(--radius-xs);
  font-family: inherit;
  font-size: var(--fs-sm);
  background: #fff;
  color: var(--bk);
}
.lbl-batch-add-input:focus {
  outline: 2px solid var(--y);
  outline-offset: 1px;
  border-color: transparent;
}
.lbl-batch-add-error {
  color: var(--fg-error, var(--red));
  font-size: var(--fs-xs);
}

/* ═══════════════════════════════════════════════════════════════════════
   §2 — matos-mobile (mobile shell + @media max-width: 639px)
   Formerly css/matos-mobile.css
   ═══════════════════════════════════════════════════════════════════════ */
/* ═══════════════════════════════════════════════════════════════════════
   matos-mobile.css — mobile shell + mobile-only patterns.

   Aligned to Camp v2 Style Guide §19 breakpoints:
     - phone:  max-width 639px  — bottom-bar visible, sidebar hidden
     - tablet: 640-959px        — handled by matos-desktop.css (sidebar on)

   Mobile-first base rules (e.g. `.m-topbar`, `.m-bottombar`) apply at all
   widths but are visually hidden ≥ 640px via overrides in
   matos-desktop.css. Truly mobile-only @media rules (`max-width: 639px`)
   live in this file.

   Tokens come from matos-shared.css; this sheet only contains layout,
   chrome, and mobile-shell-specific styles.
   ─────────────────────────────────────────────────────────────────────── */

/* ── Mobile topbar (light surface, 2px yellow hairline, DM Serif) ─────── */
/* .m-topbar / .m-logo / .m-topbar-info / .m-topbar-title / .m-topbar-sub /
 * .m-topbar-av / .m-icon-btn deleted 2026-06-20: identical to
 * shared/style/mobile/topbar.css. */

/* ── Mobile scroll region ─────────────────────────────────────────────── */
/* 2026-06-02 (user report: Android can't scroll): the previous rule
 * stacked `.m-scroll` (overflow-y: auto + overscroll-behavior: contain)
 * INSIDE `.main` (which already has overflow-y: auto on desktop, and
 * the mobile override didn't unset it). Two nested scroll containers
 * with contain on the inner one trapped touch scroll on Android.
 *
 * New mobile model: the BODY scrolls naturally. `.m-scroll` is a plain
 * block that grows with content; `.main` resets its overflow on mobile
 * (see the mobile @media block below). Bottom-bar is position: fixed
 * so it overlays the bottom of the natural scroll. Desktop keeps the
 * `.main`-scroll model via the unchanged shared rule. */
.m-scroll {
  padding: var(--sp-4) var(--sp-4) 96px;
}
.m-scroll.flush { padding: 0 0 96px; }

/* matos-app dense density mode tightens the mobile scroll padding. */
.matos-app.dense .m-scroll { padding: var(--sp-3) var(--sp-3) 96px; }

/* ── Bottom bar (mobile only; 4 verb-driven tabs + raised center FAB) ── */
/* .m-bottombar / .m-bb-item / .m-bb-item.is-active / .m-bb-spacer /
 * .m-scanfab / .m-scanfab:active / .m-scanfab-label deleted 2026-06-20:
 * identical to shared/style/mobile/bottombar.css. */

/* .matos-bottom-bar / .matos-bb-* deleted 2026-06-20: the Phase 2a
   two-shell migration replaced this with .m-bottombar (js/shell/
   mobile-bottombar.js). The emitter `js/components/bottom-bar.js` was
   already gone; this block of orphan CSS finally goes too.
   Closes smoke finding C-3. */

/* ── Mobile card list (Chercher: flex-column cards stack) ────────────── */
.m-cards { display: flex; flex-direction: column; gap: var(--sp-2h); }

/* ====== Page-wrap & header utilities (Wave 3.1, 2026-06-21) ===========
   Extracted from repeated inline-string patterns across creer/, item-*,
   profil, categories, sets, archives, etiquette, labels-batch, conflicts,
   prets, outils/, putaway-*, locations, sets, salle. Each class replaces
   a single inline style.cssText assignment.                              */

/* Standard centered-content wrap, 720px (sub-form default). */
.matos-subform-wrap {
  max-width: 720px;
  margin: 0 auto;
}

/* Lede / intro paragraph under page H1. */
.matos-subform-lede,
.section-intro {
  font-size: var(--fs-sm);
  color: var(--g4);
  margin: 0 0 var(--sp-4) 0;
}

/* Page header row: H1 (or section title) + right-aligned actions. */
.page-header {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-bottom: var(--sp-3);
  flex-wrap: wrap;
}
.page-header > :first-child {
  flex: 1;
  min-width: 0;
}

.modal-action-row {
  display: flex;
  gap: var(--sp-2);
  justify-content: flex-end;
  margin-top: var(--sp-4);
  flex-wrap: wrap;
}

/* Section heading with margin reset for top-of-card placement. */
.m-section-hd-flush {
  margin-top: 0;
}

/* ═══════════════════════════════════════════════════════════════════════
   Mobile-only viewport rules — fired below 640px (phone / phone-lg).
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-width: 639px) {
  /* App-shell: collapse to single column with topbar on top. */
  .app-shell {
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr;
  }
  .app-shell .sidebar {
    display: none;
  }
  .app-shell .main {
    grid-column: 1;
    grid-row: 2;
    padding: var(--sp-4);
    padding-bottom: 110px;
    /* 2026-06-02: reset the desktop-shared overflow-y: auto so the
     * mobile shell has a single scroll container (the body). The
     * shared rule at matos-shared.css#293 is desktop-default; mobile
     * lets the page scroll naturally. */
    overflow-y: visible;
  }

  body {
    padding-bottom: 88px;
  }

  .edit-danger {
    margin-bottom: calc(160px + env(safe-area-inset-bottom));
  }

  /* iPhone touch-target floor — Apple HIG: tappable ≥ 44×44pt. */
  .btn,
  .btn-y,
  .btn-g,
  .btn-b,
  .btn-r,
  .btn-gh,
  .btn-bk {
    min-height: 44px;
  }

  /* iOS Safari zoom-on-focus defence: bump .fm-field inputs to ≥16px so
     the layout doesn't yank when a user taps an input. */
  .fm-field input[type='text'],
  .fm-field input[type='email'],
  .fm-field input[type='tel'],
  .fm-field input[type='url'],
  .fm-field input[type='number'],
  .fm-field input[type='date'],
  .fm-field input[type='time'],
  .fm-field input[type='password'],
  .fm-field input[type='search'],
  .fm-field textarea,
  .fm-field select {
    /* iOS Safari zoom-on-focus defence — raw 16px on purpose (iphone-compat
       test pins the literal so a future --fs-lg rebase can't drop below 16). */
    font-size: 16px;
  }

  /* Item-edit parts row: tick + name + delete. CK-6 dropped the
     qty + expiry inputs, so no stacking is needed on mobile — the desktop
     layout already collapses cleanly. */
  .edit-parts-row {
    grid-template-columns: 32px 1fr 32px;
    gap: var(--sp-1) var(--sp-2);
  }

  /* Aperçu grid: collapse to 1 column under phone. */
  .apercu-grid {
    grid-template-columns: 1fr;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   §3 — matos-desktop (desktop chrome + @media min-width: 640/960)
   Formerly css/matos-desktop.css
   ═══════════════════════════════════════════════════════════════════════ */
/* ═══════════════════════════════════════════════════════════════════════
   matos-desktop.css — desktop chrome + density overrides.

   Aligned to Camp v2 Style Guide §19 breakpoints:
     - tablet:  640-959px — sidebar visible, no dense layout
     - desktop: ≥ 960px    — dense table, 2-col fiche, 4-col stats

   Two clusters of rules live in this file:
     1. Top-level `.d-*` classes (rendered by the desktop branch of the
        SPA — JS gates on matchMedia('(min-width: 960px)')). Rules are
        unconditional so the cascade attaches them whenever the JS path
        decides to emit those class names.
     2. `.sb-*` matos-specific sidebar polish — sidebar shows from
        640px up, so these polish styles are always-on with no media
        gate (they hurt nothing when the sidebar is hidden under 640px).
     3. `@media (min-width: 640px)` — nav-swap rules: hide mobile
        bottom-bar, position install-banner top-right.
     4. `@media (min-width: 960px)` — density overrides: 2-col fiche,
        4-col stats, sticky bulk bar, `.m-co-grid`, `.m-detail` grid.

   Tokens come from matos-shared.css; no :root block here.
   ─────────────────────────────────────────────────────────────────────── */

/* ── Desktop app shell (rendered by JS when matchMedia ≥ 960px) ──────── */
/* .d-sidebar / .d-brand / .d-launcher / .d-create / .d-nav / .d-nav-grp /
 * .d-nav-item / .d-side-foot deleted 2026-06-20: identical to
 * shared/style/desktop/sidebar.css.
 * .d-main / .d-topbar / .d-topbar-title / .d-topbar-sub / .d-search /
 * .d-icon-btn / .d-content deleted 2026-06-20: identical to
 * shared/style/desktop/topbar.css and desktop/app-shell.css.
 *
 * INTENTIONAL OVERRIDE kept:
 * .d-app — consumes shared --d-sidebar-w (248px) as of the 5-token
 *   consolidation (2026-06-21). The legacy local --sb-w (236px) is
 *   retained in the :root block as DEPRECATED for the Wave-5 cleanup. */
.d-app {
  position: fixed; inset: 0;
  display: grid;
  grid-template-columns: var(--d-sidebar-w, 248px) 1fr;
  background: var(--wh);
  color: var(--text);
  font-family: var(--sans);
  font-size: var(--fs-md);
  -webkit-font-smoothing: antialiased;
}
.d-app *, .d-app *::before, .d-app *::after { box-sizing: border-box; }
.d-app h1, .d-app h2, .d-app h3 { font-family: var(--serif); font-weight: 400; margin: 0; }
/* Plain-button reset for in-content buttons. EXCLUDES every chrome
   widget that has its own background/border styling: the canonical
   sidebar (`.sb-*` from @suite/lib/sidebar — fixed MT-1) and the topbar
   chips (`.d-search`, `.d-launcher`, `.d-create`, `.d-icon-btn` — fixed
   smoke P1 #7 2026-06-20). The reset still applies to every other
   in-content button. */
.d-app button:not([class*="sb-"]):not(.d-search):not(.d-launcher):not(.d-create):not(.d-icon-btn) { font-family: var(--sans); cursor: pointer; border: none; background: none; color: inherit; }
.d-app .mono { font-family: var(--mono); }
.d-pad { padding: 28px clamp(28px, 4vw, 64px); }
.d-wide { max-width: 1180px; margin: 0 auto; }
.d-narrow { max-width: 760px; margin: 0 auto; }

.d-page-hd { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 22px; }
.d-h1 { font-family: var(--serif); font-size: 1.65rem; line-height: 1.05; color: var(--text); } /* between --fs-2xl and --fs-3xl; no exact token */
.d-eyebrow { font-size: var(--fs-xs); letter-spacing: 0.12em; text-transform: uppercase; color: var(--g4); font-weight: 700; margin-bottom: 8px; }
.d-sec-title { font-family: var(--serif); font-size: var(--fs-xl); color: var(--text); margin-bottom: 12px; }
.d-row-actions { display: flex; gap: 8px; }

/* ── Desktop dashboard ─────────────────────────────────────────────────── */
.d-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 28px; }
.d-stat { background: var(--wh); border: 1px solid var(--g2); border-radius: var(--radius-md); padding: 18px 20px; box-shadow: var(--shadow-sm); }
.d-stat .n { font-family: var(--serif); font-weight: 700; font-size: 2.4rem; line-height: 1; color: var(--text); font-variant-numeric: tabular-nums; letter-spacing: -0.02em; } /* desktop stat numeral — beyond --fs-3xl; no exact token */
.d-stat .l { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: var(--g4); margin-top: 8px; }
.d-stat .bar { height: 5px; background: var(--g1); border-radius: 99px; overflow: hidden; margin-top: 10px; }
.d-stat .bar > i { display: block; height: 100%; background: var(--green); border-radius: 99px; }
.d-dash-grid { display: grid; grid-template-columns: 1.3fr 1fr; gap: 22px; align-items: start; }
.d-card { background: var(--wh); border: 1px solid var(--g2); border-radius: var(--radius-md); box-shadow: var(--shadow-sm); }
.d-card-hd { display: flex; align-items: center; justify-content: space-between; padding: 16px 20px; border-bottom: 1px solid var(--g1); }
.d-card-hd .t { font-family: var(--serif); font-size: var(--fs-md); color: var(--text); }
.d-card-body { padding: 6px 20px; }

.d-att { display: flex; align-items: center; gap: 14px; padding: 13px 20px; border-bottom: 1px solid var(--g1); width: 100%; text-align: left; }
.d-att:last-child { border-bottom: none; }
.d-att .ic { width: 38px; height: 38px; border-radius: var(--radius-sm); display: grid; place-items: center; font-size: var(--fs-xl); flex-shrink: 0; }
.d-att .ic.err { background: var(--bg-error); } .d-att .ic.warn { background: var(--bg-warn); } .d-att .ic.info { background: var(--bg-info); }
.d-att .n { font-family: var(--serif); font-size: var(--fs-xl); color: var(--text); }
.d-att .l { font-size: var(--fs-md); color: var(--g4); }
.d-att .chev { margin-left: auto; color: var(--g3); }
.d-feed { padding: 4px 0; }
.d-feed-row { display: flex; gap: 12px; padding: 11px 0; border-bottom: 1px solid var(--g1); }
.d-feed-row:last-child { border-bottom: none; }
.d-feed-row .ic { font-size: var(--fs-lg); width: 22px; text-align: center; }
.d-feed-row .tx { font-size: var(--fs-md); color: var(--text); }
.d-feed-row .tm { font-size: var(--fs-xs); color: var(--g3); margin-top: 2px; }

/* ── Master–detail browse + dense table ────────────────────────────────── */
/* .d-browse / .d-browse.split / .d-toolbar / .d-filter deleted 2026-06-20:
 * identical to shared/style/desktop/browse.css.
 * .d-thead / .d-trow / .d-check / .d-check.on / .d-bulk deleted 2026-06-20:
 * identical to shared/style/desktop/browse.css.
 * .d-panel-empty / .d-panel-scroll deleted 2026-06-20: identical.
 *
 * INTENTIONAL OVERRIDES kept below:
 * .d-select / .d-select:focus — matos uses background: var(--wh) (flipping);
 *   shared uses var(--surface-card). Intentional: --wh gives off-white (#fafaf8)
 *   vs. shared's pure-white (--white/#fff) in light mode, matching the page bg.
 * .d-searchbox — same rationale as .d-select.
 * .d-table — same rationale (flipping page-surface bg).
 * .d-panel — matos uses var(--wh) instead of shared's var(--surface-card)
 *   so the panel sits at page-surface level, not as a distinct card. */
/* .d-select:focus deleted 2026-06-20: identical to shared/style/desktop/browse.css;
 * the dark-mode override (.d-select:focus in @media prefers-color-scheme dark)
 * still handles the --g4 border-color re-route. */
.d-select { font-family: var(--sans); font-size: var(--fs-md); color: var(--bk); background: var(--wh); border: 1px solid var(--g2); border-radius: var(--radius-sm); padding: 7px 10px; outline: none; }
.d-searchbox { flex: 1; min-width: 180px; display: flex; align-items: center; gap: 8px; background: var(--wh); border: 1px solid var(--g2); border-radius: var(--radius-sm); padding: 7px 12px; }
.d-searchbox input { border: none; outline: none; background: none; flex: 1; font-family: var(--sans); font-size: var(--fs-md); color: var(--bk); }

.d-table { width: 100%; background: var(--wh); border: 1px solid var(--g2); border-radius: var(--radius-md); overflow: hidden; }

/* Detail side panel */
.d-panel { background: var(--wh); border: 1px solid var(--g2); border-radius: var(--radius-md); box-shadow: var(--shadow-sm); overflow: hidden; position: sticky; top: 0; max-height: calc(100vh - 160px); display: flex; flex-direction: column; }

/* Two-column fiche */
.d-fiche { display: grid; grid-template-columns: 360px minmax(0,1fr); gap: 28px; align-items: start; }
.d-block { background: var(--wh); border: 1px solid var(--g2); border-radius: var(--radius-md); box-shadow: var(--shadow-sm); padding: 18px 20px; margin-bottom: 18px; }
.d-block h3 { font-family: var(--sans); font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.1em; color: var(--g4); margin-bottom: 12px; }

/* ⌘K palette (desktop variant kept here for parity; legacy duplicate
   exists in shared/style/cmdk.css — these styles are matos-local). */
.d-cmdk-back { position: fixed; inset: 0; background: rgba(20,20,20,0.4); z-index: 200; display: flex; align-items: flex-start; justify-content: center; padding-top: 12vh; }
.d-cmdk { width: 560px; max-width: 92vw; background: var(--wh); border: 1px solid var(--g2); border-radius: var(--radius-md); box-shadow: var(--shadow-lg); overflow: hidden; }
.d-cmdk-input { display: flex; align-items: center; gap: 10px; padding: 16px 18px; border-bottom: 1px solid var(--g2); }
.d-cmdk-input input { border: none; outline: none; background: none; flex: 1; font-family: var(--sans); font-size: var(--fs-lg); color: var(--bk); }
.d-cmdk-input .kbd { font-size: var(--fs-xs); background: var(--g1); border: 1px solid var(--g2); color: var(--g4); padding: 2px 7px; border-radius: 4px; }
.d-cmdk-list { max-height: 380px; overflow-y: auto; padding: 6px; }
.d-cmdk-grp { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.1em; color: var(--g4); padding: 10px 12px 4px; }
.d-cmdk-item { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: var(--radius-sm); width: 100%; text-align: left; font-size: var(--fs-md); color: var(--text); }
.d-cmdk-item .ic { font-size: var(--fs-xl); width: 22px; text-align: center; }
.d-cmdk-item .code { margin-left: auto; font-family: var(--mono); font-size: var(--fs-xs); color: var(--g4); }
.d-cmdk-item.on, .d-cmdk-item:hover { background: var(--g1); }
.d-cmdk-item.on { box-shadow: inset 2px 0 0 var(--y); }

.d-empty-hint { padding: 60px 20px; text-align: center; color: var(--g4); font-size: var(--fs-md); }

mobile bottom-bar hidden.
   Tablet (640-959px) gets the sidebar but not the dense layout.
   ═══════════════════════════════════════════════════════════════════════ */
@media (min-width: 640px) {
  /* Hide the mobile bottombar above the phone breakpoint. */
  .m-bottombar { display: none; }

  /* PWA install-banner desktop positioning: top-right corner, no
     centring (so it doesn't fight with the topbar wordmark). */
  .matos-install-banner {
    top: calc(env(safe-area-inset-top, 0px) + var(--sp-3));
    right: var(--sp-3);
    left: auto;
    margin: 0;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   Density layer @ 960px — dense table, 2-col fiche, 4-col stats, etc.
   This is the cutoff where `.d-*` JS paths and `.m-*`-rearrange overrides
   kick in. Below this (tablet 640-959px), pages still use the mobile-
   card layout but with the sidebar fixed to the left.
   ═══════════════════════════════════════════════════════════════════════ */
@media (min-width: 960px) {
  /* ── Page-level: widen + breathe ── */
  .main.m-scroll,
  .apercu-host.m-scroll,
  .chercher-host.m-scroll {
    max-width: 1180px;
    margin: 0 auto;
    padding: 28px clamp(28px, 4vw, 48px);
  }

  /* ── Aperçu desktop layout ─────────────────────────────────────────
     The mobile renderer stacks: Hero · Search · Stats · Attention ·
     À venir · Activité récente. Desktop folds Attention + À venir into
     a 2-col grid; stats go to 4-col; Activité stays full-width below. */
  .apercu-host {
    display: block;
  }
  .m-accueil-hero {
    margin-bottom: 8px;
  }
  /* Stats band → 4 columns desktop */
  .apercu-host .m-stats {
    grid-template-columns: repeat(4, 1fr);
    gap: 18px;
    margin-bottom: 22px;
  }
  .apercu-host .m-stat {
    padding: 18px 22px;
  }
  .apercu-host .m-stat-num {
    font-size: 2.4rem; /* desktop stat numeral — beyond --fs-3xl; no exact token */
  }
  /* 2-col row for first two <section>s (Attention + À venir). */
  .apercu-host > section:nth-of-type(1),
  .apercu-host > section:nth-of-type(2) {
    display: inline-block;
    width: calc(50% - 11px);
    vertical-align: top;
  }
  .apercu-host > section:nth-of-type(1) {
    margin-right: 18px;
  }
  /* Activité récente / 3rd section is full-width below. */
  .apercu-host > section:nth-of-type(3) {
    display: block;
    width: 100%;
    margin-top: 22px;
  }

  /* ── Chercher (parcourir.js) desktop spacing ──────────────────────── */
  .chercher-host h2.m-h2 {
    font-size: 1.65rem; /* between --fs-2xl and --fs-3xl; no exact token */
    margin-bottom: 16px;
  }
  .chercher-host .m-search.field {
    max-width: 480px;
  }
  .chercher-host .m-filter-row {
    margin-top: 12px;
  }
  .chercher-host .d-bulk {
    margin-top: 14px;
  }

  /* ── Fiche / item-detail 2-col grid ──────────────────────────────── */
  .m-detail {
    max-width: 1180px;
    margin: 0 auto;
    padding: 28px clamp(28px, 4vw, 48px);
  }
  .m-detail .m-detail-actionbar-top {
    margin-bottom: 14px;
  }
  .m-detail .m-detail-hd {
    margin-bottom: 22px;
  }
  .m-detail .m-detail-name {
    font-size: 2.4rem; /* desktop item-name display — beyond --fs-3xl; no exact token */
  }
  .m-detail {
    display: grid;
    grid-template-columns: minmax(0, 360px) minmax(0, 1fr);
    grid-template-areas:
      'top   top'
      'head  head'
      'photo right'
      'loc   right'
      'hist  right'
      'extras extras'
      'foot  foot';
    gap: 0 28px;
    align-items: start;
  }
  .m-detail > .m-detail-actionbar-top {
    grid-area: top;
  }
  .m-detail > .m-detail-hd {
    grid-area: head;
  }
  .m-detail > .m-photo-grid {
    grid-area: photo;
  }
  /* Role-specific anchors (2026-06-02). The previous selectors used
   * `.m-card-block:nth-of-type(1..3)` over the .m-detail children, which
   * silently matched nothing because nth-of-type counts ALL div siblings
   * — and the first div under .m-detail is the top action bar, not a
   * card. The result was every .m-card-block landing in grid auto-flow's
   * first open cell and stacking on top of each other (Quantité card,
   * Historique card and Photos sheet all rendered at the same y on the
   * fiche page). buildLocationCard / buildCounterCard / buildPartsCard /
   * buildHistoryCard now stamp m-card-loc / m-card-status / m-card-hist
   * so each card lands in its named area regardless of sibling order. */
  .m-detail > .m-card-loc {
    grid-area: loc;
  }
  .m-detail > .m-card-status {
    grid-area: right;
    align-self: start;
  }
  .m-detail > .m-card-hist {
    grid-area: hist;
  }
  /* Single extras cell — js/pages/item-detail.js wraps the container
   * contents card, photos card and item-history details in one
   * .m-detail-extras div so they don't all resolve to `grid-area: extras`
   * and stack at the same row position (visible bug: photos card image
   * bleeding through the container contents on desktop). Children inside
   * the wrapper stack vertically via flex.
   */
  .m-detail > .m-detail-extras {
    grid-area: extras;
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    min-width: 0;
  }
  /* Note banner kept as a direct child (rare; conditional on item state)
   * — also routes to extras but as a single occupant, no stacking risk. */
  .m-detail > .sg-banner {
    grid-area: extras;
  }
  .m-detail > .m-actionbar {
    grid-area: foot;
    margin-top: 14px;
  }

  /* ── Sorties (checkout-lifecycle) 2-col grid ─────────────────────── */
  .m-scroll:has(> .m-co-card) {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 18px;
    align-items: start;
  }
  .m-scroll:has(> .m-co-card) > .m-section-hd,
  .m-scroll:has(> .m-co-card) > .m-chips {
    grid-column: 1 / -1;
  }
  .m-co-card {
    margin: 0;
  }

  /* ── Sets / kits desktop grid ─────────────────────────────────────── */
  body .m-scroll > .m-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 16px;
  }

  /* ── Revue annuelle desktop comfort ─────────────────────────────── */
  .m-review {
    max-width: 760px;
    margin: 0 auto;
    padding: 32px clamp(28px, 4vw, 64px);
    position: relative;
    inset: auto;
  }
  .m-review-body {
    margin-top: 16px;
  }

  /* ── Outils hub tabs (desktop sizing) ─────────────────────────────── */
  .outils-tabs.creer-tabs {
    border-bottom: 1px solid var(--g2);
    padding-bottom: 0;
    margin-bottom: 22px;
  }
  .outils-tabs .tag-chip {
    padding: 10px 16px;
    font-size: var(--fs-md);
  }

  /* Audit log rows reuse .d-thead / .d-trow chrome but only have 3 cells
     (glyph, description, timestamp). Override the items-browse 7-col grid
     so the description column gets the leftover space instead of being
     squeezed into the 30 px icon slot. */
  .d-thead.audit,
  .d-trow.audit {
    grid-template-columns: 34px minmax(0, 1fr) 160px;
  }
}
