/*
 * Piloxa Design System — components.css
 * Composants, patterns marketing et coque applicative.
 *
 * Source : .claude/skills/Piloxa new design system/Piloxa DS Static.html (sections 3 à 18).
 * Plan : docs/refactor/design-system-piloxa.md (Phase 0).
 *
 * Dépend de tokens.css (vars --pi-*, --ff-*, --r-*, --sh-*, --sp-*).
 * Hex de statut (#0F8550, #B00020, #8A6E00) remplacés par var(--pi-success/error/warn).
 */

/* 0 · ATTRIBUT hidden — prime sur tout `display` de ce fichier.
 * Sans cette règle, `.btn { display:inline-flex }`, `.overflow-menu button`
 * ou `.preview-panel` battaient l'attribut HTML `hidden` (feuille auteur >
 * feuille navigateur) : un bouton réservé à un rôle restait visible, un
 * panneau « fermé » restait à l'écran. Constaté sur templates.html (lot 5,
 * 2026-09-05), présent aussi sur booking-config, login, forgot / reset /
 * setup-password. Décision user : règle globale ici plutôt que page par page.
 * Audit préalable : 50 éléments `hidden` dans 21 pages, tous réaffichés en
 * touchant `hidden`, aucun par classe ou style seul. */
[hidden] { display: none !important; }

/* 2b · FOCUS VISIBLE (a11y 2.4.7 AA) — anneau global au clavier.
   Les composants qui déclarent leur propre outline restent prioritaires. */
:focus-visible{outline:2px solid var(--pi-accent-fg);outline-offset:2px;}

/* 3 · LAYOUT */
.wrap{max-width:1280px;margin:0 auto;padding:0 48px;}
.section{padding:96px 0;border-top:1px solid var(--pi-divider);position:relative;}
.section:first-of-type{border-top:0;}
.eyebrow{font-family:var(--ff-body);font-size:12px;letter-spacing:0.18em;text-transform:uppercase;color:var(--pi-muted);font-weight:600;}
.lede{color:var(--pi-muted);max-width:640px;font-size:16px;line-height:1.6;}
.mono{font-family:var(--ff-mono);font-size:12px;color:var(--pi-muted);}
.stack{display:flex;flex-direction:column;gap:16px;}
.row{display:flex;gap:16px;align-items:center;flex-wrap:wrap;}
.grid{display:grid;gap:22px;}
.g-2{grid-template-columns:repeat(2,1fr);}
.g-3{grid-template-columns:repeat(3,1fr);}
.g-4{grid-template-columns:repeat(4,1fr);}
.g-5{grid-template-columns:repeat(5,1fr);}
.g-6{grid-template-columns:repeat(6,1fr);}

/* 4 · TOP NAV */
.top{position:sticky;top:0;z-index:50;background:rgba(244,239,228,0.85);backdrop-filter:saturate(140%) blur(10px);-webkit-backdrop-filter:saturate(140%) blur(10px);border-bottom:1px solid var(--pi-divider);}
.top-inner{display:flex;align-items:center;justify-content:space-between;padding:18px 48px;}
.topnav{display:flex;gap:24px;font-size:13px;color:var(--pi-muted);font-weight:500;}
.topnav a:hover{color:var(--pi-ink);}
.top-cta{display:flex;gap:12px;align-items:center;}
.anchors{display:flex;gap:14px;padding:18px 48px;border-top:1px solid var(--pi-divider);flex-wrap:wrap;font-size:12px;}
.anchors a{display:inline-flex;align-items:center;gap:8px;padding:7px 14px;border-radius:var(--r-pill);background:var(--pi-card);border:1px solid var(--pi-divider);color:var(--pi-ink);font-weight:500;}
.anchors a .num{font-family:var(--ff-mono);color:var(--pi-muted);font-size:10.5px;}
.anchors a:hover{background:var(--pi-violet);border-color:var(--pi-violet);}

/* 5 · LOGO */
.logo{font-family:var(--ff-display);font-weight:var(--fw-display);font-size:28px;letter-spacing:-0.03em;line-height:1;color:var(--pi-ink);text-decoration:none;display:inline-flex;align-items:baseline;}
.logo .dot{color:var(--pi-lime);}
.logo-mark{font-family:var(--ff-display);font-weight:var(--fw-display);letter-spacing:-0.03em;line-height:1;color:var(--pi-ink);text-decoration:none;display:inline-flex;align-items:baseline;}
.logo-mark .dot{color:var(--pi-lime);}
.logo-mark--xl{font-size:96px;}
.logo-mark--lg{font-size:56px;}
.logo-mark--md{font-size:36px;}
.logo-mark--sm{font-size:22px;}
.logo-mark--xs{font-size:14px;}
.logo-mark--dot-lime .dot{color:var(--pi-lime);}
.logo-mark--dot-purple .dot{color:var(--pi-purple);}
.logo-mark--dot-coral .dot{color:var(--pi-coral);}
.logo-mark--dot-sun .dot{color:var(--pi-sun);}
.logo-mark--dot-ink .dot{color:var(--pi-ink);}
.logo-mark--inverse{color:#fff;}
.logo-mark--mono .dot{color:inherit;}

/* 6 · BUTTONS */
/* `color` explicite : sans elle, un <button> retombe sur la couleur système
   `buttontext` — valeur DÉPENDANTE DU MOTEUR, hors charte (noir pur #000 sur
   Chrome/macOS, potentiellement blanc ailleurs). Les variants qui posent leur
   propre couleur (--primary, --ink, --ghost, --lime) restent inchangés.

   Le variant --text ne déclare volontairement PAS de couleur : il hérite donc
   l'encre. Le gris `--pi-muted` de la maquette a été écarté après mesure — il
   fait tomber tous les boutons texte de AAA à un AA limite (4,57:1 sur
   `--pi-cream-2`, soit 0,07 au-dessus du seuil), pour un contrôle CLIQUABLE.
   La hiérarchie du tertiaire se joue sur la taille et l'absence de fond.

   Mouvement (#219, revue emil-design-eng) :
   - propriétés listées, jamais `all` : `all` animait aussi l'anneau de focus
     (couleur et décalage), et une action au clavier ne s'anime pas ;
   - l'appui se rétracte (`scale(.97)`, ease-out marqué) : le bouton montre
     qu'il a entendu ;
   - les survols ne valent que pour un pointeur fin : au doigt, le toucher
     laisse un faux survol collé (« Choisir Essentiel » restait inversé). */
.btn{display:inline-flex;align-items:center;gap:8px;font-family:var(--ff-body);font-weight:500;font-size:14px;line-height:1;padding:12px 22px;border:1px solid transparent;border-radius:var(--r-pill);cursor:pointer;transition:background-color .15s ease,color .15s ease,border-color .15s ease,opacity .15s ease,transform .16s cubic-bezier(.23,1,.32,1);white-space:nowrap;color:var(--pi-ink);}
.btn:active{transform:scale(.97);}
.btn:focus-visible{outline:2px solid var(--pi-accent-fg);outline-offset:2px;}
.btn--primary{background:var(--pi-accent);color:var(--pi-on-accent);}
.btn--ink{background:var(--pi-ink);color:#fff;}
.btn--ghost{background:transparent;color:var(--pi-ink);border-color:var(--pi-ink);}
.btn--lime{background:var(--pi-lime);color:var(--pi-ink);}
@media (hover:hover) and (pointer:fine){
.btn--primary:hover{background:var(--pi-accent-press);}
.btn--ink:hover{background:#000;}
.btn--ghost:hover{background:var(--pi-ink);color:#fff;}
.btn--lime:hover{background:var(--pi-lime-soft);}
}
.btn--text{background:transparent;padding:8px 4px;border-radius:0;}
/* Page en chargement (#175, js/shared/page-ready.js) : la zone de travail est
   `inert` jusqu'à pageReady() ; ses boutons le montrent. */
[data-page-pending] .btn{opacity:.5;}
.btn--lg{padding:15px 26px;font-size:15px;}
.btn--sm{padding:9px 16px;font-size:13px;}

/* 7 · CARDS */
.card{background:var(--pi-card);border-radius:var(--r-lg);border:1px solid var(--pi-divider);box-shadow:var(--sh-1);overflow:hidden;}
.card .chip{height:140px;}
.card .meta{padding:18px 20px 20px;}
.card .name{font-family:var(--ff-display);font-weight:var(--fw-display);font-size:18px;letter-spacing:-0.02em;}
.card .hex{font-family:var(--ff-mono);font-size:12px;color:var(--pi-muted);margin-top:6px;}
.card .role{font-size:12.5px;color:var(--pi-muted);margin-top:10px;line-height:1.5;}
.card .tokens{display:flex;gap:6px;margin-top:12px;flex-wrap:wrap;}
.card .tok{font-family:var(--ff-mono);font-size:10.5px;padding:4px 8px;border-radius:var(--r-pill);background:var(--pi-cream-2);color:var(--pi-ink-soft);}

/* 8 · BADGES + PILLS */
.badge{display:inline-flex;align-items:center;gap:6px;font-size:10px;font-weight:700;letter-spacing:0.06em;text-transform:uppercase;padding:5px 11px;border-radius:var(--r-pill);line-height:1;}
.badge--sun{background:var(--pi-sun);color:var(--pi-ink);}
.badge--soon{background:transparent;color:var(--pi-muted);border:1px dashed var(--pi-muted);}
.badge--coral{background:var(--pi-coral);color:#fff;}
.badge--lime{background:var(--pi-lime);color:var(--pi-ink);}
.badge--ink{background:var(--pi-ink);color:#fff;}
.badge--violet{background:var(--pi-violet);color:var(--pi-ink);}
.badge--dot::before{content:"";width:6px;height:6px;border-radius:999px;background:currentColor;}

/* ── Status badges (états facture / devis) — handoff-statuts ──
   Composant DS unique : .piloxa-status + un modificateur par état (13 états).
   Icône + libellé portés par le markup ; couleur depuis les tokens. */
.piloxa-status{display:inline-flex;align-items:center;gap:6px;font-family:var(--ff-body);font-size:11px;font-weight:700;letter-spacing:0.05em;text-transform:uppercase;line-height:1;padding:6px 11px 6px 9px;border-radius:var(--r-pill);border:1.5px solid transparent;white-space:nowrap;}
.piloxa-status svg{width:13px;height:13px;flex:none;}
.piloxa-status--draft{background:transparent;color:var(--pi-muted);border-color:var(--pi-muted);border-style:dashed;}
.piloxa-status--sent{background:var(--pi-violet-3);color:var(--pi-purple);}
.piloxa-status--valid{background:var(--pi-ink-soft-bg);color:var(--pi-ink);}
.piloxa-status--paid{background:var(--pi-success-soft);color:var(--pi-success-strong);}
.piloxa-status--overdue{background:var(--pi-orange-soft);color:var(--pi-orange);}
.piloxa-status--avoir{background:var(--pi-amber-soft);color:var(--pi-warn);}
.piloxa-status--accepted{background:transparent;color:var(--pi-success);border-color:var(--pi-success);}
.piloxa-status--converted{background:var(--pi-violet);color:var(--pi-purple-press);}
.piloxa-status--refused{background:transparent;color:var(--pi-error);border-color:var(--pi-coral);}
.piloxa-status--expired{background:var(--pi-cream-2);color:var(--pi-muted);border-color:var(--pi-divider);}
.piloxa-status--cancel{background:var(--pi-cream-2);color:var(--pi-muted);}
.piloxa-status--echec{background:var(--pi-coral-soft);color:var(--pi-error);}
.piloxa-status--error{background:var(--pi-coral);color:#fff;}
.piloxa-status--dot{padding:6px;width:26px;height:26px;justify-content:center;}
.piloxa-status--dot svg{width:14px;height:14px;}

.pill{display:inline-flex;align-items:center;gap:8px;background:var(--pi-violet);color:var(--pi-ink);padding:8px 16px;border-radius:var(--r-pill);font-size:13px;font-weight:500;}
.pill::before{content:"";width:6px;height:6px;border-radius:999px;background:var(--pi-ink);}

/* 9 · COLOR SCALE */
.scale{display:grid;grid-template-columns:repeat(6,1fr);gap:0;border-radius:var(--r-md);overflow:hidden;border:1px solid var(--pi-divider);}
.scale .step{height:96px;display:flex;align-items:flex-end;padding:10px;font-family:var(--ff-mono);font-size:11px;color:rgba(20,18,31,0.7);}
.scale .step.dark{color:rgba(255,255,255,0.85);}

/* 10 · TYPE ROWS */
.type-row{display:grid;grid-template-columns:180px 1fr 220px;gap:32px;align-items:baseline;padding:22px 0;border-bottom:1px dashed var(--pi-divider);}
.type-row:last-child{border-bottom:0;}
.type-row .label{font-family:var(--ff-mono);font-size:12px;color:var(--pi-muted);}
.type-row .specs{font-family:var(--ff-mono);font-size:12px;color:var(--pi-muted);text-align:right;}
.type-d1{font-family:var(--ff-display);font-weight:var(--fw-display);font-size:84px;line-height:0.96;letter-spacing:-0.03em;}
.type-d2{font-family:var(--ff-display);font-weight:var(--fw-display);font-size:56px;line-height:1.02;letter-spacing:-0.025em;}
.type-h2{font-family:var(--ff-display);font-weight:var(--fw-display);font-size:44px;line-height:1.05;letter-spacing:-0.02em;}
.type-h3{font-family:var(--ff-display);font-weight:var(--fw-display);font-size:28px;line-height:1.15;letter-spacing:-0.02em;}
.type-h4{font-family:var(--ff-body);font-size:20px;line-height:1.3;font-weight:600;}
.type-body{font-family:var(--ff-body);font-size:15px;line-height:1.6;font-weight:400;color:var(--pi-ink-soft);}
.type-body-sm{font-family:var(--ff-body);font-size:13px;line-height:1.55;color:var(--pi-ink-soft);}
.type-eyebrow-sample{font-family:var(--ff-body);font-size:13px;letter-spacing:0.18em;text-transform:uppercase;font-weight:600;}
.type-mono{font-family:var(--ff-mono);font-size:12px;color:var(--pi-ink-soft);}

/* 11 · SPACING + RADIUS */
.sp-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:14px;}
.sp-cell{background:var(--pi-card);border-radius:var(--r-md);padding:18px;border:1px solid var(--pi-divider);display:flex;flex-direction:column;gap:14px;align-items:flex-start;}
.sp-cell .bar{background:var(--pi-violet);height:14px;border-radius:999px;}
.sp-cell .label{font-family:var(--ff-mono);font-size:11px;color:var(--pi-muted);}
.sp-cell .name{font-family:var(--ff-display);font-weight:var(--fw-display);font-size:22px;letter-spacing:-0.02em;}
.r-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:14px;}
.r-cell{background:var(--pi-card);border:1px solid var(--pi-divider);padding:24px;display:flex;flex-direction:column;gap:14px;align-items:center;border-radius:var(--r-lg);}
.r-cell .demo{width:90px;height:90px;background:var(--pi-violet);}
.r-cell .label{font-family:var(--ff-mono);font-size:11px;color:var(--pi-muted);}
.r-cell .name{font-family:var(--ff-display);font-weight:var(--fw-display);font-size:18px;letter-spacing:-0.02em;}

/* 12 · ELEVATION */
.ele-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;}
.ele{background:var(--pi-card);border-radius:var(--r-lg);padding:32px;min-height:180px;display:flex;flex-direction:column;justify-content:flex-end;}
.ele .name{font-family:var(--ff-display);font-weight:var(--fw-display);font-size:22px;letter-spacing:-0.02em;}
.ele .role{font-size:12.5px;color:var(--pi-muted);margin-top:6px;}
.ele--1{box-shadow:var(--sh-1);}
.ele--2{box-shadow:var(--sh-2);}
.ele--3{box-shadow:var(--sh-3);}

/* 13 · ICONS */
.icon-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:12px;}
.icon-card{background:var(--pi-card);border-radius:var(--r-lg);border:1px solid var(--pi-divider);padding:18px 14px 14px;display:flex;flex-direction:column;align-items:center;gap:10px;}
.icon-card .frame{width:64px;height:64px;border-radius:var(--r-md);background:var(--pi-cream-2);display:flex;align-items:center;justify-content:center;}
.icon-card .frame img{width:36px;height:36px;}
.icon-card .name{font-family:var(--ff-display);font-weight:var(--fw-display);font-size:15px;letter-spacing:-0.02em;text-align:center;line-height:1.1;}
.icon-card .key{font-family:var(--ff-mono);font-size:10px;color:var(--pi-muted);}
.icon-section-h{font-family:var(--ff-body);font-size:11px;font-weight:600;letter-spacing:0.14em;text-transform:uppercase;color:var(--pi-muted);margin:32px 0 14px;}
.icon-section-h:first-of-type{margin-top:24px;}
.icon-tile{width:42px;height:42px;border-radius:var(--r-md);background:var(--pi-ink);display:inline-flex;align-items:center;justify-content:center;}
.icon-tile img{width:22px;height:22px;}
.icon-tile--lime{background:var(--pi-lime);}
.icon-tile--violet{background:var(--pi-violet);}
.icon-tile--cream{background:var(--pi-cream-2);}

/* 14 · DO/DON'T */
.do-dont{display:grid;grid-template-columns:1fr 1fr;gap:22px;}
.dd{background:var(--pi-card);border-radius:var(--r-lg);padding:28px;border:1px solid var(--pi-divider);}
.dd .tag{display:inline-flex;align-items:center;gap:8px;font-family:var(--ff-mono);font-size:11px;padding:5px 12px;border-radius:var(--r-pill);margin-bottom:14px;}
.dd.do .tag{background:rgba(201,240,59,0.25);color:var(--pi-ink);}
.dd.dont .tag{background:rgba(255,99,99,0.18);color:var(--pi-error);}
.dd p{font-size:14px;color:var(--pi-ink-soft);line-height:1.55;}

/* 15 · PATTERNS */
.pattern-constat{background:var(--pi-violet);border-radius:var(--r-xl);padding:48px 56px;display:grid;grid-template-columns:1fr 1fr;gap:32px;align-items:center;min-height:320px;}
.pattern-constat .right{text-align:center;}
.pattern-constat h3{font-size:40px;line-height:1.15;letter-spacing:-0.015em;}
.hl-pill{display:inline-block;background:#fff;border-radius:var(--r-pill);padding:2px 18px;line-height:1.15;}
.pattern-cta{background:var(--pi-violet);border-radius:var(--r-xl);padding:40px 56px;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:20px;}
.pattern-cta h3{font-size:40px;line-height:1.05;}
.price{background:var(--pi-card);border-radius:var(--r-lg);padding:30px 26px;display:flex;flex-direction:column;gap:16px;border:1px solid var(--pi-divider);position:relative;}
.price.dark{background:var(--pi-ink);color:#fff;border-color:var(--pi-ink);}
.price .pname{font-family:var(--ff-display);font-weight:var(--fw-display);font-size:22px;letter-spacing:-0.01em;}
.price .amount{font-family:var(--ff-display);font-weight:var(--fw-display);font-size:52px;line-height:0.95;letter-spacing:-0.02em;display:flex;align-items:flex-end;gap:6px;}
.price .unit{font-family:var(--ff-body);font-size:12px;font-weight:500;color:var(--pi-muted);padding-bottom:8px;}
.price.dark .unit{color:rgba(255,255,255,0.65);}
.price .sub{font-size:13px;color:var(--pi-muted);}
.price.dark .sub{color:rgba(255,255,255,0.7);}
.price .recom{position:absolute;top:-12px;left:50%;transform:translateX(-50%);background:var(--pi-coral);color:#fff;font-size:10px;font-weight:700;padding:6px 12px;border-radius:var(--r-pill);letter-spacing:0.1em;text-transform:uppercase;}
.mod{background:var(--pi-card);border-radius:var(--r-lg);padding:22px;display:flex;flex-direction:column;gap:18px;min-height:200px;box-shadow:var(--sh-1);border:1px solid var(--pi-divider);}
.mod-head{display:flex;align-items:flex-start;justify-content:space-between;}
.mod h4{font-family:var(--ff-display);font-weight:var(--fw-display);font-size:22px;letter-spacing:-0.01em;line-height:1.1;}
.mod p{font-size:12.5px;color:var(--pi-muted);margin-top:4px;line-height:1.5;}

/* Footer pattern */
.pattern-footer{background:var(--pi-ink);color:#fff;border-radius:var(--r-xl);padding:56px 56px 28px;}
.pattern-footer .foot-grid{display:grid;grid-template-columns:1.5fr 1fr 1fr 1fr 1fr;gap:36px;}
.pattern-footer .foot-brand .logo{color:#fff;font-size:32px;}
.pattern-footer p{color:rgba(255,255,255,0.55);font-size:13px;max-width:280px;margin-top:16px;line-height:1.55;}
.pattern-footer .foot-meta{margin-top:20px;display:flex;flex-direction:column;gap:12px;font-size:13px;}
.pattern-footer .foot-loc{display:flex;align-items:center;gap:8px;color:rgba(255,255,255,0.7);}
.pattern-footer .foot-loc svg{flex:none;color:var(--pi-lime);}
.pattern-footer .foot-pills{display:flex;flex-direction:column;gap:8px;margin-top:4px;}
.foot-pill{display:inline-flex;align-items:center;gap:8px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.10);color:rgba(255,255,255,0.85);padding:7px 14px 7px 8px;border-radius:var(--r-pill);font-size:12.5px;font-weight:500;width:fit-content;}
.foot-pill .swatch{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:var(--r-pill);background:rgba(255,255,255,0.05);flex:none;overflow:hidden;}
.foot-flag{width:18px;height:14px;border-radius:3px;overflow:hidden;display:inline-flex;}
.foot-flag i{display:block;width:6px;height:100%;}
.foot-flag i:nth-child(1){background:#0055A4;}
.foot-flag i:nth-child(2){background:#fff;}
.foot-flag i:nth-child(3){background:#EF4135;}
.pattern-footer h4{color:#fff;font-family:var(--ff-body);font-size:13px;font-weight:600;letter-spacing:0.04em;text-transform:uppercase;margin:0 0 16px;}
.pattern-footer ul{font-size:13px;color:rgba(255,255,255,0.6);display:flex;flex-direction:column;gap:10px;}
.pattern-footer ul a:hover{color:var(--pi-lime);}
.foot-bottom{margin-top:40px;padding-top:22px;border-top:1px solid rgba(255,255,255,0.1);display:flex;justify-content:space-between;font-size:12px;color:rgba(255,255,255,0.45);}
.foot-bottom .links{display:flex;gap:18px;}

/* 16 · VOICE */
.voice{display:grid;grid-template-columns:1fr 1fr;gap:22px;}
.voice-cell{background:var(--pi-card);border-radius:var(--r-lg);padding:32px;border:1px solid var(--pi-divider);}
.voice-cell h4{font-family:var(--ff-display);font-weight:var(--fw-display);font-size:24px;letter-spacing:-0.02em;}
.voice-cell ul{margin-top:14px;display:flex;flex-direction:column;gap:12px;font-size:14px;color:var(--pi-ink-soft);}
.voice-cell li::before{content:"— ";color:var(--pi-accent-fg);font-weight:600;}

/* ============================================================
   17 · APPLICATION UI
   ============================================================ */

/* App shell */
.app-shell {
  display: grid; grid-template-columns: 260px 1fr;
  background: var(--pi-cream); border-radius: var(--r-xl);
  border: 1px solid var(--pi-divider); overflow: hidden;
  min-height: 640px;
}

/* Variante --full : pleine page (dashboard + pages app). Sidebar et topbar
   sticky, le body scrolle naturellement dans la fenetre. Pattern aligne
   sur la maquette `Piloxa Dashboard Redesign.html`. */
.app-shell.app-shell--full {
  border-radius: 0; border: 0;
  min-height: 100vh; min-height: 100dvh;
  background: var(--pi-cream);
  overflow: visible;
}
.app-shell.app-shell--full .app-side {
  position: sticky; top: 0; align-self: start;
  max-height: 100vh; max-height: 100dvh;
  overflow-y: auto;
}
.app-shell.app-shell--full .app-main { min-width: 0; }

/* Grille de la coquille par produit (#66) : `data-layout` posé par
   design-system/shell-loader.js d'après `layout` de products/<clé>/shell.js.
   `sidebar` = la grille ci-dessus (barre latérale de 260px, coquille par
   défaut). `topbar` : la coquille rend une barre haute pleine largeur, le
   contenu dessous. `focus` : aucune navigation, le contenu seul. Spécificité
   (0,2,0) : bat les `.app-shell--full` recopiés en ligne par les pages. */
.app-shell[data-layout="topbar"],
.app-shell[data-layout="focus"] { grid-template-columns: 1fr; }
/* `minmax(0, 1fr)` : une rangée d'onglets plus large que l'écran défile dans
   la barre au lieu d'élargir la colonne (et la page) sur mobile. Spécificité
   (0,3,0) : bat aussi le `1fr` mobile de `.app-shell.app-shell--full` (§ 18).
   `html[data-shell-layout]` (#164) : la même grille, posée dès le <head> par
   shell-preload.js — avant le premier rendu, sans attendre le loader. */
.app-shell[data-layout="topbar"],
.app-shell.app-shell--full[data-layout="topbar"],
html[data-shell-layout="topbar"] .app-shell.app-shell--full { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr; }
/* Sous la barre à onglets, qui porte déjà le compte, la topbar de la page ne
   garde que son fil d'Ariane et ses actions. */
.app-shell[data-layout="topbar"] .app-top .user-menu-wrap,
html[data-shell-layout="topbar"] .app-top .user-menu-wrap { display: none; }
/* Barre réservée (#164) : tant que shell.js n'a pas remplacé le point de
   montage, il occupe la place exacte de la barre, sur son fond. Changer
   d'onglet ne fait plus disparaître puis revenir la barre. La hauteur est
   celle de `.app-tabbar` : padding de la rangée + 6px + padding de l'onglet
   + sa ligne de 20px (bureau 10+6+21+20, mobile 8+6+19+20). */
html[data-shell-layout="topbar"] [data-shell] {
  height: 57px; background: var(--pi-bar, var(--pi-ink));
}
/* Changement d'onglet (#164) : chaque onglet reste une page HTML (ADR-0032),
   le navigateur fond l'ancienne page dans la nouvelle au lieu de la couper.
   Chrome et Safari récents ; ailleurs, la navigation reste celle d'avant.
   Jamais sous « mouvement réduit ». */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}
/* Pas de `view-transition-name` sur la barre : mesuré (#164), le point de
   montage nommé est remplacé par la barre réelle pendant le fondu, et le
   navigateur abandonne alors la transition (coupure nette à mi-course). Le
   fondu de la page entière suffit : la barre réservée est déjà au même
   endroit, sur le même fond, des deux côtés. */

/* Barre à onglets de travail (grille `topbar`, products/collections/shell.js,
   #75) : fond sombre du thème (`--pi-bar`), onglets écrits en blanc, l'onglet
   actif ouvert sur la page (fond carte, comme `.app-top` dessous). */
.app-tabbar {
  background: var(--pi-bar, var(--pi-ink)); color: #fff;
  position: sticky; top: 0; z-index: 30;
}
.app-tabbar__row { display: flex; align-items: center; gap: 20px; padding: 10px 24px 0; }
.app-tabbar__brand { color: #fff; font-size: 22px; padding-bottom: 8px; flex: none; --pi-muted: rgb(255 255 255 / .62); }
.app-tabbar__tabs {
  display: flex; align-items: flex-end; gap: 2px; flex: 1; min-width: 0;
  overflow-x: auto; scrollbar-width: none; padding-top: 6px;
}
.app-tabbar__tabs::-webkit-scrollbar { display: none; }
.app-tab {
  display: inline-flex; align-items: center; gap: 8px; flex: none; max-width: 240px;
  padding: 10px 14px 11px; border-radius: 12px 12px 0 0;
  font-size: 13px; line-height: 20px; font-weight: 500; white-space: nowrap;
  color: rgb(255 255 255 / .7); background: rgb(255 255 255 / .06);
}
.app-tab > a { color: inherit; overflow: hidden; text-overflow: ellipsis; }
.app-tab:hover { color: #fff; background: rgb(255 255 255 / .12); }
.app-tab.active, .app-tab.active:hover { color: var(--pi-ink); background: var(--pi-card); }
.app-tab--pinned { font-weight: 600; }
.app-tab__close {
  width: 18px; height: 18px; border: 0; border-radius: 6px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: inherit; font-size: 14px; line-height: 1;
  opacity: .55; cursor: pointer;
}
.app-tab__close:hover, .app-tab__close:focus-visible { opacity: 1; background: rgb(14 20 40 / .12); }
.app-tabbar__right { display: flex; align-items: center; gap: 12px; padding-bottom: 8px; flex: none; }
.app-tabbar__icon {
  width: 36px; height: 36px; border-radius: 10px; border: 1px solid rgb(255 255 255 / .18);
  display: inline-flex; align-items: center; justify-content: center; color: #fff;
}
.app-tabbar__account { position: relative; }
.app-tabbar__who {
  display: inline-flex; align-items: center; gap: 10px; padding: 0; border: 0;
  background: transparent; color: #fff; cursor: pointer; font: inherit;
}
.app-tabbar__who .avatar { width: 34px; height: 34px; font-size: 13px; }
.app-tabbar__org { font-size: 12px; line-height: 1.25; text-align: right; }
.app-tabbar__org b { display: block; font-weight: 600; }
.app-tabbar__org span { opacity: .62; }
.app-tabbar__menu { color: var(--pi-ink); width: 300px; }
.app-tabbar__menu .item { width: 100%; border: 0; background: transparent; font: inherit; font-size: 13px; text-align: left; }
.app-tabbar__menu .item.is-locked { flex-wrap: wrap; color: var(--pi-muted); }
.app-tabbar__menu div.item.is-locked { cursor: default; }
.app-tabbar__menu .lock-note { flex-basis: 100%; font-size: 11.5px; line-height: 1.4; }
/* Menu « + » : hors de la rangée d'onglets, qui défile sur mobile et couperait le menu. */
.app-tabbar__new { position: relative; flex: none; padding-bottom: 8px; }
.app-tabbar__plus {
  width: 34px; height: 34px; border-radius: 10px; border: 1px solid rgb(255 255 255 / .18);
  background: transparent; color: #fff; font-size: 20px; line-height: 1; cursor: pointer;
}
.app-tabbar__plus:hover, .app-tabbar__plus[aria-expanded="true"] { background: rgb(255 255 255 / .1); }
.app-tabbar__menu--new { left: 0; right: auto; width: 260px; }
@media (max-width: 768px) {
  .app-tabbar__row { gap: 8px; padding: 8px 12px 0; }
  .app-tabbar__brand, .app-tabbar__org { display: none; }
  .app-tab { padding: 9px 11px 10px; }
  html[data-shell-layout="topbar"] [data-shell] { height: 53px; }
}

/* Sidebar */
.app-side {
  background: var(--pi-card);
  border-right: 1px solid var(--pi-divider);
  padding: 22px 16px;
  display: flex; flex-direction: column; gap: 6px;
}
.app-side .brand { padding: 6px 12px 18px; display: flex; align-items: center; justify-content: space-between; }
.app-side .brand .logo { font-size: 22px; }
/* Organisation active (#124) : repère quand la personne a plusieurs espaces. */
.app-side .brand .brand-org { font-size: 11.5px; font-weight: 600; color: var(--pi-muted);
  max-width: 50%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.app-side .section-h {
  font-family: var(--ff-body); font-size: 11px; font-weight: 600;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--pi-muted);
  padding: 14px 12px 8px;
}
.side-item {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 12px; border-radius: 10px;
  font-size: 13.5px; font-weight: 500; color: var(--pi-ink-soft);
  cursor: pointer;
  text-decoration: none;
}
.side-item:hover { background: var(--pi-cream-2); color: var(--pi-ink); }
.side-item img { width: 20px; height: 20px; flex: none; }
.side-item .count {
  margin-left: auto; font-family: var(--ff-mono); font-size: 11px;
  background: var(--pi-cream-2); padding: 2px 7px; border-radius: 999px; color: var(--pi-muted);
}
.side-item.active {
  background: var(--pi-violet); color: var(--pi-ink);
  --piloxa-icon-accent: var(--pi-lime);
}
.side-item.active .count { background: rgba(14,20,40,0.10); color: var(--pi-ink); }
.side-foot {
  margin-top: auto; padding-top: 18px; border-top: 1px dashed var(--pi-divider);
  display: flex; flex-direction: column; gap: 2px;
}

/* Topbar */
.app-main { display: flex; flex-direction: column; }
.app-top {
  background: var(--pi-card);
  border-bottom: 1px solid var(--pi-divider);
  padding: 14px 28px;
  display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 24px;
}
.app-top .crumbs { display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--pi-muted); }
.app-top .crumbs .cur { color: var(--pi-ink); font-weight: 600; }
.app-top .crumbs .sep { color: var(--pi-divider); }
.app-top .actions { display: flex; align-items: center; gap: 10px; }
.search {
  display: flex; align-items: center; gap: 8px;
  background: var(--pi-cream); padding: 8px 14px; border-radius: var(--r-pill);
  border: 1px solid var(--pi-divider);
  color: var(--pi-muted); font-size: 13px; min-width: 240px;
}
.search input {
  border: 0; background: transparent; color: var(--pi-ink); font-family: inherit;
  width: 100%; font-size: 13px;
}
.search .kbd {
  font-family: var(--ff-mono); font-size: 10.5px; padding: 2px 6px; border-radius: 5px;
  background: var(--pi-card); color: var(--pi-muted); border: 1px solid var(--pi-divider);
}
.icon-btn {
  width: 36px; height: 36px; border-radius: 10px;
  background: var(--pi-cream); border: 1px solid var(--pi-divider);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; position: relative; color: var(--pi-ink-soft);
}
.icon-btn:hover { background: var(--pi-cream-2); }
.icon-btn img { width: 18px; height: 18px; }
.icon-btn .dot {
  position: absolute; top: 6px; right: 6px; width: 8px; height: 8px;
  border-radius: 999px; background: var(--pi-coral); border: 2px solid var(--pi-card);
}
.avatar {
  width: 36px; height: 36px; border-radius: var(--r-pill);
  background: var(--pi-accent); color: var(--pi-on-accent);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--ff-display); font-weight: var(--fw-display); font-size: 15px;
}

/* App body */
.app-body {
  padding: 28px; background: var(--pi-cream); flex: 1;
  display: flex; flex-direction: column; gap: 24px;
}

/* KPIs */
.kpi-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.kpi {
  background: var(--pi-card); border-radius: var(--r-lg);
  padding: 22px; border: 1px solid var(--pi-divider);
  display: flex; flex-direction: column; gap: 14px;
}
.kpi-head { display: flex; align-items: center; justify-content: space-between; }
.kpi-head .label {
  font-size: 11.5px; font-weight: 600; color: var(--pi-muted);
  letter-spacing: 0.06em; text-transform: uppercase;
}
.kpi .icon-tile { width: 32px; height: 32px; }
.kpi .icon-tile img { width: 18px; height: 18px; }
.kpi .value {
  font-family: var(--ff-display); font-weight: var(--fw-display);
  font-size: 38px; line-height: 1; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.kpi .trend {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 600;
}
.kpi .trend.up { color: var(--pi-success); }
.kpi .trend.down { color: var(--pi-error); }
.kpi .trend.flat { color: var(--pi-muted); }
.kpi .trend svg { width: 14px; height: 14px; }
.kpi .sub { font-size: 12px; color: var(--pi-muted); }

/* Table */
.table-wrap {
  background: var(--pi-card); border-radius: var(--r-lg);
  border: 1px solid var(--pi-divider); overflow-x: auto; overflow-y: hidden;
}
.table-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 20px 22px; border-bottom: 1px solid var(--pi-divider);
}
.table-head h4 { font-family: var(--ff-display); font-weight: var(--fw-display); font-size: 20px; letter-spacing: -0.01em; }
.table-head .row { gap: 8px; }
.filter-pill {
  font-size: 12px; padding: 6px 12px; border-radius: var(--r-pill);
  background: var(--pi-cream-2); color: var(--pi-ink-soft); font-weight: 500;
  cursor: pointer; border: 1px solid transparent;
}
.filter-pill:hover { background: var(--pi-violet-3); }
.filter-pill.active { background: var(--pi-ink); color: #fff; }
.table {
  width: 100%; border-collapse: collapse;
  font-size: 13px;
}
.table th, .table td { padding: 14px 22px; text-align: left; border-bottom: 1px solid var(--pi-divider); }
.table th {
  font-family: var(--ff-body); font-size: 11px; font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--pi-muted);
  background: var(--pi-cream); cursor: pointer; user-select: none;
}
.table th .sort { opacity: 0.4; margin-left: 6px; font-size: 9px; }
.table th:hover .sort { opacity: 1; }
.table tbody tr:hover { background: var(--pi-cream); }
.table tbody tr:last-child td { border-bottom: 0; }
.table .client { display: flex; align-items: center; gap: 10px; }
.table .client .avatar { width: 28px; height: 28px; font-size: 12px; }
.table .amount { font-variant-numeric: tabular-nums; font-weight: 600; }
.table .ref { font-family: var(--ff-mono); font-size: 11.5px; color: var(--pi-muted); }
.row-actions {
  display: inline-flex; gap: 6px;
}
.row-actions .icon-btn { width: 28px; height: 28px; border-radius: 8px; }

/* Status pills (états visuels) */
.state {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11.5px; font-weight: 600;
  padding: 4px 10px 4px 8px; border-radius: var(--r-pill);
  line-height: 1.4;
}
.state::before { content: ""; width: 6px; height: 6px; border-radius: 999px; background: currentColor; }
.state--paid     { background: rgba(15,133,80,0.10);  color: var(--pi-success); }
.state--pending  { background: rgba(248,221,44,0.20); color: var(--pi-warn); }
.state--overdue  { background: rgba(255,99,99,0.16);  color: var(--pi-error); }
.state--draft    { background: var(--pi-cream-2);     color: var(--pi-muted); }
.state--sent     { background: rgba(122,91,232,0.14); color: var(--pi-purple); }

/* Forms */
.form-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 22px; }
.field { display: flex; flex-direction: column; gap: 8px; }
.field-label {
  font-size: 12.5px; font-weight: 600; color: var(--pi-ink);
  display: flex; align-items: center; gap: 6px;
}
.field-label .req { color: var(--pi-coral); }
.field-help { font-size: 11.5px; color: var(--pi-muted); }
.input, .select, .textarea {
  background: var(--pi-card); border: 1px solid var(--pi-divider);
  border-radius: 10px; padding: 11px 14px; font-family: inherit; font-size: 13.5px;
  color: var(--pi-ink); transition: all .15s ease;
}
.input:focus, .select:focus, .textarea:focus { border-color: var(--pi-accent-fg); box-shadow: 0 0 0 3px rgb(var(--pi-accent-rgb) / 0.15); }
.input::placeholder, .textarea::placeholder { color: var(--pi-muted); }
.field-error { color: var(--pi-error); font-size: 11.5px; display: flex; align-items: center; gap: 6px; }
.input.is-invalid, .select.is-invalid, .textarea.is-invalid { border-color: var(--pi-coral); box-shadow: 0 0 0 3px rgba(255,99,99,0.12); }

.input-group { position: relative; display: flex; align-items: center; }
.input-group .input { padding-left: 38px; width: 100%; }
.input-group .lead {
  position: absolute; left: 12px; width: 18px; height: 18px;
  color: var(--pi-muted); pointer-events: none;
}
.input-group .suffix {
  position: absolute; right: 14px;
  font-size: 12px; color: var(--pi-muted); font-family: var(--ff-mono);
}
.textarea { min-height: 92px; resize: vertical; }

.check {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: 13.5px; color: var(--pi-ink); cursor: pointer;
}
.check input { position: absolute; opacity: 0; }
.check .box {
  width: 18px; height: 18px; border-radius: 5px;
  background: var(--pi-card); border: 1.5px solid var(--pi-divider);
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  transition: all .15s ease;
}
.check .box::after {
  content: ""; width: 6px; height: 9px;
  border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg) translate(-1px, -1px);
  opacity: 0;
}
.check input:checked + .box { background: var(--pi-accent); border-color: var(--pi-accent-fg); }
.check input:checked + .box::after { opacity: 1; }
.check.is-radio .box { border-radius: 999px; }
.check.is-radio .box::after { width: 8px; height: 8px; border: 0; background: #fff; border-radius: 999px; transform: none; }

.switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; font-size: 13.5px; }
.switch input { position: absolute; opacity: 0; }
.switch .track {
  width: 40px; height: 22px; border-radius: 999px;
  background: var(--pi-divider); position: relative; transition: background .2s ease; flex: none;
}
.switch .track::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 18px; height: 18px; border-radius: 999px; background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,0.15); transition: transform .2s ease;
}
.switch input:checked + .track { background: var(--pi-accent); }
.switch input:checked + .track::after { transform: translateX(18px); }

/* Modal */
.modal-frame {
  position: relative;
  background: var(--pi-cream); border-radius: var(--r-xl);
  padding: 48px; border: 1px solid var(--pi-divider);
  min-height: 420px;
  overflow: hidden;
}
.modal-frame::before {
  content: ""; position: absolute; inset: 0;
  background: rgba(14,20,40,0.35); backdrop-filter: blur(2px);
}
.modal {
  position: relative;
  background: var(--pi-card); border-radius: var(--r-lg);
  box-shadow: var(--sh-3);
  width: 480px; max-width: 100%; margin: 32px auto;
  overflow: hidden;
}
.modal-head {
  padding: 22px 26px 16px;
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
}
.modal-head h4 { font-family: var(--ff-display); font-weight: var(--fw-display); font-size: 22px; letter-spacing: -0.02em; line-height: 1.1; }
.modal-head .close {
  width: 28px; height: 28px; border-radius: 8px; background: transparent;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--pi-muted); cursor: pointer; border: 0; flex: none; font-size: 18px; line-height: 1;
}
.modal-head .close:hover { background: var(--pi-cream-2); color: var(--pi-ink); }
.modal-body { padding: 0 26px 22px; color: var(--pi-ink-soft); font-size: 14px; line-height: 1.55; }
.modal-foot {
  padding: 16px 26px 22px;
  background: var(--pi-cream);
  display: flex; align-items: center; justify-content: flex-end; gap: 10px;
}

/* States: success/warn/error/info banners */
.banner {
  display: flex; align-items: flex-start; gap: 14px;
  background: var(--pi-card); border: 1px solid var(--pi-divider);
  border-radius: var(--r-md); padding: 14px 16px;
}
.banner .icon {
  width: 32px; height: 32px; border-radius: 10px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  color: #fff;
}
.banner .body { font-size: 13.5px; color: var(--pi-ink-soft); line-height: 1.5; }
.banner .body strong { color: var(--pi-ink); font-weight: 600; }
.banner.banner--success { background: rgba(15,133,80,0.06);  border-color: rgba(15,133,80,0.18); }
.banner.banner--success .icon { background: var(--pi-success); }
.banner.banner--warn    { background: rgba(248,221,44,0.10); border-color: rgba(180,144,0,0.30); }
.banner.banner--warn    .icon { background: var(--pi-warn); }
.banner.banner--error   { background: rgba(255,99,99,0.08);  border-color: rgba(255,99,99,0.30); }
.banner.banner--error   .icon { background: var(--pi-coral); }
.banner.banner--info    { background: rgb(var(--pi-accent-rgb) / 0.08); border-color: rgb(var(--pi-accent-rgb) / 0.28); }
.banner.banner--info    .icon { background: var(--pi-accent); }

/* Ligne de tableau SIGNALÉE (ex. NIF en double, #37) : fond ambre doux sur
   chaque cellule (prime sur le survol de ligne) et filet ambre à gauche — la
   couleur n'est jamais seule, la ligne porte aussi un `.row-flag` texte.
   Contraste : encre #0E1428 sur ambre doux ≈ 17:1 ; texte atténué ≈ 5:1.
   Mode jour uniquement (theme.js) : pas de variante sombre à maintenir. */
tr.row--flagged > td { background: var(--pi-amber-soft); }
tr.row--flagged > td:first-child { box-shadow: inset 4px 0 0 var(--pi-warn); }
.row-flag {
  display: inline-flex; align-items: center; margin-top: 4px;
  padding: 2px 8px; border-radius: var(--r-pill);
  background: var(--pi-card); border: 1px solid var(--pi-warn);
  color: var(--pi-warn); font-size: 11px; font-weight: 600; white-space: nowrap;
}

/* Empty state */
.empty {
  background: var(--pi-card); border: 1px dashed var(--pi-divider);
  border-radius: var(--r-lg); padding: 56px 32px;
  display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center;
}
.empty .glyph {
  width: 64px; height: 64px; border-radius: var(--r-md); background: var(--pi-cream-2);
  display: inline-flex; align-items: center; justify-content: center;
}
.empty .glyph img { width: 32px; height: 32px; }
.empty h4 { font-family: var(--ff-display); font-weight: var(--fw-display); font-size: 20px; letter-spacing: -0.02em; }
.empty p { color: var(--pi-muted); font-size: 13.5px; max-width: 380px; line-height: 1.55; }

/* Loading state */
.skeleton {
  background: linear-gradient(90deg, var(--pi-cream-2) 0%, rgba(245,239,228,0.6) 50%, var(--pi-cream-2) 100%);
  background-size: 200% 100%;
  animation: skeleton 1.4s ease-in-out infinite;
  border-radius: 6px;
}
@keyframes skeleton {
  0% { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}
.spinner {
  width: 22px; height: 22px; border: 2.5px solid var(--pi-divider);
  border-top-color: var(--pi-accent-fg); border-radius: 999px;
  animation: spin .8s linear infinite;
  display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }


/* ============================================================
   18 · APP — manquants (user menu, pagination, sheet, toasts)
   ============================================================ */

/* Menu ouvert par son bouton (js/shared/disclosure-menu.js, #75, #219) : fermé,
   il sort du rendu, comme le faisait `hidden`. Rendu mais invisible par
   défaut, un menu fermé de la coquille (300 px, en position absolue) faisait
   déborder l'écran de 124 px à 390 px. Une page qui anime la fermeture de son
   menu le garde rendu dans sa propre feuille (`visibility`, cf. offres.css). */
[data-menu]:not([data-open]) { display: none; }

/* User menu (dropdown sur l'avatar du topbar) */
.user-menu-wrap {
  position: relative;
  display: inline-block;
}
.user-menu-trigger {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 4px 12px 4px 4px; border-radius: var(--r-pill);
  border: 1px solid var(--pi-divider); background: var(--pi-card);
  cursor: pointer; transition: background .15s ease;
}
.user-menu-trigger:hover { background: var(--pi-cream-2); }
.user-menu-trigger .who { line-height: 1.1; }
.user-menu-trigger .who .name { font-size: 13px; font-weight: 600; color: var(--pi-ink); }
.user-menu-trigger .who .role { font-size: 11px; color: var(--pi-muted); }
.user-menu-trigger .chev { color: var(--pi-muted); margin-left: 4px; }
.user-menu {
  position: absolute; top: calc(100% + 8px); right: 0;
  background: var(--pi-card); border-radius: var(--r-md);
  box-shadow: var(--sh-3); border: 1px solid var(--pi-divider);
  width: 260px; padding: 8px; z-index: 5;
}
.user-menu .who-card {
  padding: 14px 12px; display: flex; gap: 12px; align-items: center;
  border-bottom: 1px solid var(--pi-divider); margin-bottom: 6px;
}
.user-menu .who-card .avatar { width: 40px; height: 40px; font-size: 14px; }
.user-menu .who-card .name { font-size: 14px; font-weight: 600; }
.user-menu .who-card .mail { font-size: 12px; color: var(--pi-muted); }
.user-menu .item {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; font-size: 13px; color: var(--pi-ink-soft);
  cursor: pointer; border-radius: 8px;
}
.user-menu .item:hover { background: var(--pi-cream-2); color: var(--pi-ink); }
.user-menu .item img { width: 16px; height: 16px; }
.user-menu .item .kbd {
  margin-left: auto; font-family: var(--ff-mono); font-size: 10.5px;
  padding: 1px 6px; border-radius: 4px; background: var(--pi-cream-2); color: var(--pi-muted);
}
.user-menu .sep { height: 1px; background: var(--pi-divider); margin: 6px 4px; }
.user-menu .item.danger { color: var(--pi-error); }
.user-menu .item.danger:hover { background: rgba(255,99,99,0.10); }

/* Pagination */
.pagination {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 22px; border-top: 1px solid var(--pi-divider);
  font-size: 12.5px; color: var(--pi-muted);
}
.pagination .count strong { color: var(--pi-ink); font-weight: 600; }
.pagination .pages { display: inline-flex; align-items: center; gap: 4px; }
.page-btn {
  min-width: 32px; height: 32px; padding: 0 10px;
  border-radius: 8px; background: transparent; border: 1px solid transparent;
  font-family: var(--ff-mono); font-size: 12px; color: var(--pi-ink-soft);
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
}
.page-btn:hover { background: var(--pi-cream-2); }
.page-btn.active {
  background: var(--pi-ink); color: #fff; border-color: var(--pi-ink);
}
.page-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.page-btn.ellipsis { cursor: default; color: var(--pi-muted); }
.page-size {
  display: inline-flex; align-items: center; gap: 8px;
}
.page-size .select {
  padding: 6px 10px; font-size: 12px; border-radius: 8px;
  height: 32px;
}

/* Sheet (drawer latéral droit) */
.sheet-frame {
  position: relative;
  background: var(--pi-cream); border-radius: var(--r-xl);
  height: 540px; border: 1px solid var(--pi-divider);
  overflow: hidden;
}
.sheet-frame::before {
  content: ""; position: absolute; inset: 0;
  background: rgba(14,20,40,0.30); backdrop-filter: blur(2px);
}
.sheet {
  position: absolute; right: 0; top: 0; bottom: 0;
  width: 480px; max-width: 90%;
  background: var(--pi-card);
  box-shadow: -20px 0 60px rgba(14,20,40,0.18);
  display: flex; flex-direction: column;
}
.sheet-head {
  padding: 22px 26px 16px;
  border-bottom: 1px solid var(--pi-divider);
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
}
.sheet-head h4 { font-family: var(--ff-display); font-weight: var(--fw-display); font-size: 22px; letter-spacing: -0.02em; line-height: 1.1; }
.sheet-head .meta { font-size: 12px; color: var(--pi-muted); margin-top: 4px; }
.sheet-head .close {
  width: 28px; height: 28px; border-radius: 8px; background: transparent;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--pi-muted); cursor: pointer; border: 0; font-size: 18px; line-height: 1;
}
.sheet-head .close:hover { background: var(--pi-cream-2); color: var(--pi-ink); }
.sheet-body { padding: 22px 26px; flex: 1; overflow-y: auto; font-size: 14px; color: var(--pi-ink-soft); line-height: 1.55; }
.sheet-body .row-kv {
  display: grid; grid-template-columns: 130px 1fr; gap: 12px;
  padding: 10px 0; border-bottom: 1px dashed var(--pi-divider);
  font-size: 13px;
}
.sheet-body .row-kv:last-of-type { border-bottom: 0; }
.sheet-body .row-kv .k { color: var(--pi-muted); }
.sheet-body .row-kv .v { color: var(--pi-ink); font-weight: 500; }
.sheet-foot {
  padding: 16px 26px 22px; background: var(--pi-cream);
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  border-top: 1px solid var(--pi-divider);
}

/* Toasts (notifications flottantes) */
.toast-frame {
  position: relative; background: var(--pi-cream); border-radius: var(--r-xl);
  border: 1px solid var(--pi-divider); min-height: 320px;
  padding: 22px;
}
.toast-stack {
  position: absolute; right: 22px; bottom: 22px;
  display: flex; flex-direction: column; gap: 10px;
  width: 360px;
}
.toast {
  display: flex; align-items: flex-start; gap: 12px;
  background: var(--pi-card); border: 1px solid var(--pi-divider);
  border-radius: var(--r-md); padding: 12px 14px;
  box-shadow: var(--sh-2);
  animation: toast-in .25s var(--pi-ease, ease-out);
}
@keyframes toast-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
.toast .icon {
  width: 28px; height: 28px; border-radius: 8px; flex: none; color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
}
.toast .body { flex: 1; }
.toast .body .title { font-size: 13px; font-weight: 600; color: var(--pi-ink); line-height: 1.3; }
.toast .body .sub { font-size: 12px; color: var(--pi-muted); margin-top: 2px; line-height: 1.4; }
.toast .body .actions { margin-top: 8px; display: inline-flex; gap: 14px; font-size: 12px; }
.toast .body .actions a { color: var(--pi-accent-fg); font-weight: 600; }
.toast .close {
  width: 22px; height: 22px; border-radius: 6px; border: 0; background: transparent;
  color: var(--pi-muted); cursor: pointer; font-size: 14px; line-height: 1;
}
.toast .close:hover { background: var(--pi-cream-2); color: var(--pi-ink); }
.toast--success .icon { background: var(--pi-success); }
.toast--warn    .icon { background: var(--pi-warn); }
.toast--error   .icon { background: var(--pi-coral); }
.toast--info    .icon { background: var(--pi-accent); }
.toast--ink {
  background: var(--pi-ink); border-color: var(--pi-ink);
}
.toast--ink .body .title, .toast--ink .body .sub, .toast--ink .close { color: rgba(255,255,255,0.85); }
.toast--ink .close:hover { background: rgba(255,255,255,0.10); color: #fff; }
.toast--ink .body .actions a { color: var(--pi-lime); }

/* Verrou (#66, « Catalogue des produits v1 », règle 2) : une fonction dont le
   module manque à la formule reste visible, floutée et inerte, sous un
   cadenas et la phrase du serveur. Rendu par js/shared/locked-section.js. */
.locked-section { position: relative; border-radius: var(--r-lg); overflow: hidden; }
.locked-section__preview { filter: blur(4px); opacity: .55; pointer-events: none; user-select: none; }
.locked-section__veil {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; padding: 24px; text-align: center;
  background: rgba(244,239,228,.55);
}
.locked-section__veil p { max-width: 420px; margin: 0; font-size: 13.5px; color: var(--pi-ink); }
.locked-section__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 999px;
  background: var(--pi-card); color: var(--pi-ink); box-shadow: var(--sh-1);
}
/* Action seule verrouillée (#188) : le bouton reste visible et inerte, la
   phrase du serveur le suit en petit — un voile ne tient pas sur un bouton. */
.locked-action { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; max-width: 320px; }
.locked-action__btn { gap: 6px; color: var(--pi-muted); cursor: not-allowed; }
.locked-action__btn svg { width: 14px; height: 14px; flex: none; }
.locked-action__note { margin: 0; font-size: 11.5px; line-height: 1.4; color: var(--pi-muted); text-align: right; }
.locked-action__note a { color: var(--pi-ink); text-decoration: underline; }

/* ============================================================
   18 · RESPONSIVE MOBILE (≤ 768px puis ≤ 360px)
   ------------------------------------------------------------
   - Sidebar off-canvas + hamburger gérés par la coquille par défaut
     (products/default/shell.js, grille data-layout="sidebar")
     (création .app-side-hamburger + .app-side-backdrop dans .app-top).
   - Spécificité .app-shell.app-shell--full (0,2,0) pour battre les
     définitions inline des pages migrées (spec 0,1,0).
   ============================================================ */

/* Default desktop : éléments mobiles cachés (créés par products/default/shell.js) */
.app-side-hamburger { display: none; }
.app-side-backdrop  { display: none; }

@media (max-width: 768px) {
  /* App shell single-column full-bleed */
  .app-shell.app-shell--full {
    grid-template-columns: 1fr;
    min-height: 100vh; min-height: 100dvh;
    border-radius: 0; border: 0;
  }

  /* Sidebar off-canvas (override sticky desktop des pages) */
  .app-shell.app-shell--full .app-side {
    position: fixed;
    left: 0; top: 0; bottom: 0;
    width: 280px; height: 100vh; height: 100dvh;
    max-height: none;
    transform: translateX(-110%);
    transition: transform .28s cubic-bezier(.4,0,.2,1);
    z-index: 150;
    border-right: 1px solid var(--pi-divider);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
  }
  .app-shell.app-shell--full .app-side.open {
    transform: translateX(0);
    box-shadow: 8px 0 32px rgba(14,20,40,.30);
  }

  /* Body scroll-lock iOS-safe (products/default/shell.js ajoute la classe .app-side-open) */
  body.app-side-open {
    position: fixed;
    width: 100%;
    height: 100vh; height: 100dvh;
    overflow: hidden;
  }

  /* Hamburger 3-stripes (inséré dans .app-top par products/default/shell.js) */
  .app-side-hamburger {
    display: inline-flex;
    flex-direction: column; justify-content: center; align-items: center;
    gap: 5px;
    width: 36px; height: 36px;
    background: transparent; border: 0;
    padding: 0; margin-right: 6px; cursor: pointer;
    border-radius: var(--r-sm);
  }
  .app-side-hamburger:hover { background: var(--pi-cream-2); }
  .app-side-hamburger:focus-visible { outline: 2px solid var(--pi-accent-fg); outline-offset: 2px; }
  .app-side-hamburger span {
    display: block; width: 22px; height: 2px;
    background: var(--pi-ink); border-radius: 2px;
    transition: transform .25s, opacity .25s;
  }
  .app-side-hamburger[aria-expanded="true"] span:nth-child(1) {
    transform: translateY(7px) rotate(45deg);
  }
  .app-side-hamburger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
  .app-side-hamburger[aria-expanded="true"] span:nth-child(3) {
    transform: translateY(-7px) rotate(-45deg);
  }

  /* Backdrop sidebar */
  .app-side-backdrop {
    display: block;
    position: fixed; inset: 0;
    background: rgba(14,20,40,.55);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    z-index: 149;
    opacity: 0;
    pointer-events: none;
    touch-action: none;
    transition: opacity .25s;
  }
  .app-side-backdrop.open { opacity: 1; pointer-events: auto; }

  /* Topbar mobile compact */
  .app-top {
    padding: 12px 16px;
    gap: 12px;
    position: relative;
    grid-template-columns: 1fr;
  }
  .app-top .crumbs { font-size: 12.5px; }
  .app-top .actions { flex-wrap: wrap; gap: 8px; }

  /* App body padding compact */
  .app-body { padding: 16px; }

  /* KPI grid 4 → 2 */
  .kpi-grid { grid-template-columns: repeat(2, 1fr); }

  /* Tables scrollables horizontalement.
     !important nécessaire : les pages app (invoices, clients, quotes, contracts,
     expenses, hr, team) redéclarent inline .table-wrap{overflow:hidden} et
     table{width:100%} APRÈS le <link> du DS. À spécificité égale (0,1,1) l'ordre
     source les fait gagner et tue le scroll horizontal mobile — d'où le !important
     pour rétablir le scroll. Même pattern que l'override font-size 16px ci-dessous. */
  .table-wrap {
    overflow-x: auto !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  .table-wrap table { width: max-content !important; min-width: 100%; }

  /* iOS Safari : 16px min pour éviter le zoom auto sur focus.
     !important nécessaire pour battre les .input-sm inline-page
     (spec 0,2,0) qui imposent .85rem. */
  input:not([type="radio"]):not([type="checkbox"]):not([type="range"]):not([type="submit"]):not([type="button"]),
  select, textarea {
    font-size: 16px !important;
  }

  /* Touch targets (WCAG 2.5.5 — minimum 44×44 pour cibles critiques) */
  .btn { min-height: 40px; }
  .side-item { min-height: 44px; }
}

@media (max-width: 360px) {
  .kpi-grid { grid-template-columns: 1fr; }
  .app-shell.app-shell--full .app-side { width: 240px; }
}

/* ═══════════════════════════════════════════════════════════════════
 * 19 · MARKETING CHROME — pages publiques (landing + légal + auth)
 *
 * Ces composants remplacent les classes legacy `.nav-wrap`/`.container`/
 * `.nav`/`.logo-brand-name`/etc. de `frontend/piloxa/styles.css` pour
 * permettre aux pages marketing/auth de s'affranchir de styles.css.
 *
 * Namespace `.mk-*` pour eviter les collisions avec d'eventuelles
 * regles legacy chargees en parallele (transition Phase 2 → Phase 3).
 * ═══════════════════════════════════════════════════════════════════ */
.mk-container { width: min(1100px, 100% - 2rem); margin-inline: auto; }

.mk-nav {
  position: sticky; top: 0; z-index: 50;
  backdrop-filter: blur(12px) saturate(140%);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  background: rgba(244,239,228,0.78);
  border-bottom: 0.5px solid var(--pi-divider);
}
.mk-nav-inner {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1rem 0; gap: 2rem;
}
.mk-logo {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--ff-display); font-weight: var(--fw-display);
  font-size: 1.15rem; letter-spacing: -0.02em;
  color: var(--pi-ink); text-decoration: none;
}
.mk-logo .mk-logo-mark { width: 28px; height: 28px; border-radius: 8px; flex-shrink: 0; }
.mk-logo .ox { color: var(--pi-accent-fg); }

.mk-nav-links {
  display: flex; gap: 1.5rem; align-items: center;
  flex: 1; justify-content: center;
}
.mk-nav-links a {
  color: var(--pi-ink-soft);
  text-decoration: none;
  font-size: 0.875rem; font-weight: 500;
  transition: color .2s;
}
.mk-nav-links a:hover { color: var(--pi-accent-fg); }

.mk-nav-toggle {
  display: none;
  flex-direction: column; justify-content: center; gap: 5px;
  background: transparent; border: none;
  cursor: pointer; padding: 4px; margin-left: auto;
}
.mk-nav-toggle span {
  display: block; width: 22px; height: 2px;
  background: var(--pi-ink); border-radius: 2px;
  transition: transform .25s, opacity .25s;
}
.mk-nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.mk-nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.mk-nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 680px) {
  .mk-nav-toggle { display: flex; }
  .mk-nav-links {
    display: none;
    flex-direction: column; align-items: flex-start; gap: 0;
    position: absolute;
    top: 100%; left: 0; right: 0;
    background: rgba(244,239,228,0.95);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-bottom: 0.5px solid var(--pi-divider);
    padding: 0.5rem 1rem;
  }
  .mk-nav-links.open { display: flex; }
  .mk-nav-links a {
    width: 100%; padding: 0.75rem 0;
    border-bottom: 0.5px solid var(--pi-divider);
    font-size: 1rem;
  }
  .mk-nav-links a:last-child { border-bottom: none; }
}

/* Footer marketing simple (centre, copyright minimal) */
.mk-foot {
  padding: 32px 0 24px;
  border-top: 0.5px solid var(--pi-divider);
  margin-top: 56px;
  color: var(--pi-muted);
  font-size: 0.85rem;
  text-align: center;
}
.mk-foot a { color: var(--pi-ink-soft); text-decoration: none; }
.mk-foot a:hover { color: var(--pi-accent-fg); }

/* Footer marketing grid (multi-col : Ressources / Societe).
   Utilise sur les pages publiques : contact, support, documentation,
   mentions-legales, politique-de-confidentialite, cgu-cgv. */
.mk-footer {
  border-top: 0.5px solid var(--pi-divider);
  padding: 36px 36px 28px;
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1fr;
  gap: 36px;
  color: var(--pi-ink-soft);
  font-size: 0.85rem;
  background: var(--pi-cream-2);
}
.mk-footer .col h4 {
  margin: 0 0 12px;
  font-size: 0.72rem;
  color: var(--pi-ink);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-weight: 700;
}
.mk-footer .col a {
  display: block;
  padding: 4px 0;
  color: inherit;
  text-decoration: none;
}
.mk-footer .col a:hover { color: var(--pi-accent-fg); }

@media (max-width: 900px) {
  .mk-footer { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 680px) {
  .mk-footer { grid-template-columns: 1fr; padding: 28px 18px; gap: 24px; }
}

/* ── Description de ligne mise en forme, en lecture (vues détail) ──
   Enveloppe le HTML de js/shared/rich-text.js : le reset de tokens.css retire
   puces et retrait de toutes les listes. */
.rich-text ul { margin: 2px 0 0; padding-left: 18px; list-style: disc; }

/* ── Description de ligne mise en forme (devis, facture) ──
   Quill bridé au gras, à l'italique et aux puces : js/shared/rich-text-editor.js.
   Habille le thème « snow » aux couleurs du DS ; le champ grandit avec le
   texte et se redimensionne à la main. */
.rich-desc .ql-toolbar.ql-snow {
  border: 1px solid var(--pi-divider); border-bottom: none;
  border-radius: var(--r-sm) var(--r-sm) 0 0;
  padding: 4px 6px; background: var(--pi-cream);
}
.rich-desc .ql-container.ql-snow {
  border: 1px solid var(--pi-divider); border-radius: 0 0 var(--r-sm) var(--r-sm);
  font-family: var(--ff-body); font-size: .85rem; color: var(--pi-ink);
  background: var(--pi-card);
}
.rich-desc .ql-editor {
  min-height: 110px; resize: vertical; overflow-y: auto;
  line-height: 1.45; padding: 8px 10px;
}
.rich-desc .ql-editor.ql-blank::before { font-style: normal; color: var(--pi-muted); left: 10px; right: 10px; }
.rich-desc .ql-snow .ql-stroke { stroke: var(--pi-ink-soft); }
.rich-desc .ql-snow .ql-fill { fill: var(--pi-ink-soft); }
.rich-desc .ql-snow.ql-toolbar button:hover .ql-stroke,
.rich-desc .ql-snow.ql-toolbar button.ql-active .ql-stroke { stroke: var(--pi-accent); }
.rich-desc .ql-snow.ql-toolbar button:hover .ql-fill,
.rich-desc .ql-snow.ql-toolbar button.ql-active .ql-fill { fill: var(--pi-accent); }
.rich-desc:focus-within .ql-toolbar.ql-snow,
.rich-desc:focus-within .ql-container.ql-snow { border-color: var(--pi-accent-fg); }
.rich-desc:focus-within .ql-container.ql-snow { box-shadow: 0 3px 0 0 rgb(var(--pi-accent-rgb) / .15); }

/* 2c · SKIP LINK (a11y 2.4.1) — visible uniquement au focus clavier */
.skip-link{position:absolute;left:-9999px;top:0;background:var(--pi-ink);color:#fff;padding:8px 16px;border-radius:8px;z-index:9999;font-size:.9rem;}
.skip-link:focus{left:8px;top:8px;}

/* ── prefers-reduced-motion (WCAG 2.3.3) — coupe animations et transitions ── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
