/* ==========================================================================
   App Shell — maquettes Tressol-Chabrier
   Sidebar repliable + topbar + bascule de thème.
   S'appuie sur design-system.css (tokens, composants).
   ========================================================================== */

body.app { display: flex; min-height: 100vh; --sb: 264px; }
body.app.nav-collapsed { --sb: 78px; }

/* ------------------------------------------------------------------ */
/* Sidebar                                                             */
/* ------------------------------------------------------------------ */
.app-sidebar {
  position: fixed; inset: 0 auto 0 0; width: var(--sb); z-index: var(--z-nav);
  background: linear-gradient(180deg, var(--c-sidebar-from) 0%, var(--c-sidebar-to) 100%);
  color: var(--c-on-navy); display: flex; flex-direction: column;
  padding: var(--space-5) 14px; overflow: hidden;
  transition: width var(--t-base);
}
.app-sidebar__head { display: flex; align-items: center; gap: var(--space-3); height: 38px; margin: 0 var(--space-2) var(--space-6); }
.app-sidebar__mark { width: 36px; height: 36px; border-radius: 10px; background: rgba(255,255,255,0.10); display: grid; place-items: center; flex-shrink: 0; }
.app-sidebar__mark img { height: 18px; }
.app-sidebar__logo { height: 19px; white-space: nowrap; transition: opacity var(--t-fast); }
body.nav-collapsed .app-sidebar__logo { opacity: 0; pointer-events: none; }

/* Zone de navigation scrollable : le pied (.app-sidebar__foot) reste ancré en
   bas même quand la liste de liens dépasse la hauteur de l'écran. */
.app-nav { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; }
.app-sidebar__head, .app-sidebar__foot { flex-shrink: 0; }
/* Les liens de nav peuvent être des <button> (cas SPA) : reset pour matcher <a>.
   On ne réinitialise QUE la famille de police — la taille/graisse viennent de
   .nav-link (un `font: inherit` écraserait fs-sm/600 par l'héritage du body). */
button.nav-link { width: 100%; background: none; border: none; font-family: inherit; text-align: left; cursor: pointer; }

.nav-section { font-size: 0.66rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--c-on-navy-soft); padding: var(--space-4) var(--space-3) var(--space-2); white-space: nowrap; }
body.nav-collapsed .nav-section { opacity: 0; height: var(--space-4); padding-top: var(--space-3); padding-bottom: 0; overflow: hidden; }

.nav-link {
  display: flex; align-items: center; gap: var(--space-3);
  padding: 11px var(--space-3); border-radius: var(--radius-md); margin-bottom: 2px;
  color: var(--c-on-navy); text-decoration: none; font-size: var(--fs-sm); font-weight: 600;
  white-space: nowrap; transition: background var(--t-fast), color var(--t-fast); position: relative;
}
.nav-link svg { width: 19px; height: 19px; stroke: currentColor; stroke-width: 1.8; fill: none; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }
.nav-link span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; transition: opacity var(--t-fast); }
body.nav-collapsed .nav-link span { opacity: 0; }
.nav-link:hover { background: rgba(255,255,255,0.07); color: #fff; text-decoration: none; }
/* Item actif : encre chaude sur l'orange de marque (7,2:1). Le blanc sur cet
   orange ne plafonnait qu'à 2,33:1, sous le seuil WCAG AA. */
.nav-link.is-active { background: var(--c-accent); color: var(--c-accent-on); box-shadow: var(--shadow-accent); }
.nav-link .lock { margin-left: auto; width: 14px; height: 14px; opacity: 0.8; }
.nav-link.is-locked { opacity: 0.45; cursor: not-allowed; }
body.nav-collapsed .nav-link .lock { display: none; }

/* Bouton de repli, accroché au bord de la sidebar */
.nav-collapse-btn {
  position: fixed; top: 22px; left: calc(var(--sb) - 13px); z-index: calc(var(--z-nav) + 1);
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--c-card); border: 1px solid var(--c-border); color: var(--c-heading);
  cursor: pointer; display: grid; place-items: center; box-shadow: var(--shadow-sm);
  transition: left var(--t-base);
}
.nav-collapse-btn svg { width: 15px; height: 15px; stroke: currentColor; stroke-width: 2; fill: none; transition: transform var(--t-base); }
body.nav-collapsed .nav-collapse-btn svg { transform: rotate(180deg); }

.app-sidebar__foot { margin-top: auto; }
.app-user { display: flex; align-items: center; gap: var(--space-3); padding: 8px; border-radius: var(--radius-md); }
/* L'avatar reprend la primitive .avatar du design-system (dégradé accent) :
   même pastille orange que le Back-Office, aucune surcharge locale. */
.app-user .avatar { text-transform: uppercase; }
.app-user .meta { display: flex; flex-direction: column; flex: 1 1 auto; transition: opacity var(--t-fast); white-space: nowrap; min-width: 0; }
/* Replié, le bloc identité perd son libellé mais GARDE sa déconnexion.
   Auparavant le bouton passait à opacity:0 + pointer-events:none : invisible,
   inopérant à la souris, mais toujours atteignable au clavier — un focus
   posé sur rien, et aucun moyen visible de fermer sa session. Les deux
   éléments s'empilent, les 78 px du rail ne permettant pas de les poser côte
   à côte (même solution qu'au Back-Office). Le libellé sort du flux mais
   reste lu par les lecteurs d'écran. */
body.nav-collapsed .app-user .meta { opacity: 0; pointer-events: none; position: absolute; }
body.nav-collapsed .app-user { flex-direction: column; gap: var(--space-2); }
body.nav-collapsed .app-user__logout { margin-left: 0; background: rgba(255,255,255,0.08); }
.app-user .nm { font-size: var(--fs-sm); font-weight: 600; color: #fff; line-height: 1.15; overflow: hidden; text-overflow: ellipsis; }
.app-user .rl { font-size: var(--fs-xs); color: var(--c-on-navy-soft); overflow: hidden; text-overflow: ellipsis; }
.app-user__logout { margin-left: auto; background: none; border: none; color: var(--c-on-navy-soft); cursor: pointer; padding: 6px; border-radius: 8px; flex-shrink: 0; }
.app-user__logout:hover { color: #fff; background: rgba(255,255,255,0.08); }
.app-user__logout svg { width: 18px; height: 18px; stroke: currentColor; stroke-width: 1.8; fill: none; stroke-linecap: round; stroke-linejoin: round; }

/* ------------------------------------------------------------------ */
/* Squelette de la barre latérale                                      */
/* ------------------------------------------------------------------ */
/* Posé avant l'arrivée des données (univers, favoris, identité). Il reprend
   la structure définitive et remplace les liens par des formes, pour que la
   barre ne saute pas d'un pixel au remplacement.
   Le miroitement de `.skeleton` (design-system) est calé sur le fond de page
   CLAIR : sur le dégradé navy de la barre il serait invisible. On reprend donc
   la même animation, avec des blancs translucides. */
.nav-skel {
  display: block; border-radius: var(--radius-md);
  background: linear-gradient(90deg,
    rgba(255,255,255,0.07) 0%,
    rgba(255,255,255,0.15) 50%,
    rgba(255,255,255,0.07) 100%);
  background-size: 200% 100%;
  animation: ds-skeleton 1.4s linear infinite;
}
/* Même hauteur qu'un .nav-link (11 px de marge intérieure + une ligne). */
.nav-skel--link { height: 41px; margin-bottom: 2px; }
.nav-skel--sec { height: 9px; width: 44%; margin: var(--space-4) var(--space-3) var(--space-3); border-radius: var(--radius-sm); }
/* Repliée, le vrai intertitre se réduit à une bande vide (cf. .nav-section) :
   le squelette prend la même forme, sinon un bloc large apparaîtrait là où il
   n'y a bientôt plus rien. */
body.nav-collapsed .nav-skel--sec { height: 1px; width: auto; margin: var(--space-3) var(--space-2) var(--space-2); }
.nav-skel--av { width: 38px; height: 38px; border-radius: 50%; flex-shrink: 0; }
.nav-skel--nm { height: 11px; flex: 1; border-radius: var(--radius-sm); }
/* Repliée, le bloc identité n'a plus la place d'un nom : le trait serait une
   barre en travers du rail. */
body.nav-collapsed .nav-skel--nm { display: none; }
.app-user--skel { pointer-events: none; }
@media (prefers-reduced-motion: reduce) { .nav-skel { animation: none; } }
[data-motion="reduce"] .nav-skel { animation: none; }

/* ------------------------------------------------------------------ */
/* Infobulle des liens de navigation (TCNavTip)                        */
/* ------------------------------------------------------------------ */
/* `position: fixed` sur le <body> : la barre latérale est en
   `overflow: hidden`, une infobulle enfant y serait rognée. */
.nav-tip {
  position: fixed; z-index: var(--z-tooltip);
  max-width: 264px; padding: 9px 12px;
  background: var(--c-navy); color: #fff;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  font-size: var(--fs-sm); line-height: var(--lh-snug);
  pointer-events: none;                 /* ne doit jamais voler le survol */
  opacity: 0; transform: translateX(-4px);
  transition: opacity var(--t-fast), transform var(--t-fast);
}
.nav-tip.is-open { opacity: 1; transform: none; }
.nav-tip[hidden] { display: none; }
.nav-tip__nm { display: block; font-weight: 600; }
.nav-tip__ds { display: block; margin-top: 3px; font-size: var(--fs-xs); color: var(--c-on-navy-soft); }
/* Flèche calée sur le centre du LIEN (--tip-caret), pas sur celui de
   l'infobulle : près du bord de l'écran l'infobulle est recadrée alors que le
   lien, lui, ne bouge pas. */
.nav-tip::before {
  content: ''; position: absolute; left: -4px; top: var(--tip-caret, 16px);
  width: 9px; height: 9px; margin-top: -4px;
  background: var(--c-navy); border-radius: 2px; transform: rotate(45deg);
}
/* En sombre, le navy se rapproche du fond de page : on le détache par une
   bordure fine plutôt qu'en changeant sa couleur, pour rester cohérent avec
   la barre latérale. */
[data-theme="dark"] .nav-tip { border: 1px solid var(--c-border-strong); }
[data-motion="reduce"] .nav-tip { transition: none; }

/* ------------------------------------------------------------------ */
/* Zone principale + topbar                                            */
/* ------------------------------------------------------------------ */
.app-main { flex: 1; margin-left: var(--sb); display: flex; flex-direction: column; min-width: 0; transition: margin-left var(--t-base); }
.app-topbar {
  display: flex; align-items: center; gap: var(--space-5); height: 66px; padding: 0 var(--space-8);
  background: color-mix(in srgb, var(--c-bg) 78%, transparent); backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--c-border); position: sticky; top: 0; z-index: 20;
}
.app-topbar__title { font-size: var(--fs-lg); }
/* ── Fil d'Ariane ────────────────────────────────────────────────────────
   Il ne se lisait pas comme un chemin : les niveaux étaient séparés par un
   point médian et aucun n'était cliquable. Chevrons, liens et niveau courant
   marqué `aria-current` en font désormais un vrai fil. */
.app-crumb { font-size: var(--fs-sm); color: var(--c-muted); min-width: 0; }
.app-crumb ol {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2);
  list-style: none; margin: 0; padding: 0;
}
.app-crumb li { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.app-crumb li + li::before {
  content: ''; flex: none; width: 6px; height: 6px; transform: rotate(45deg);
  border-right: 1.5px solid var(--c-border-strong);
  border-top: 1.5px solid var(--c-border-strong);
}
.app-crumb a, .app-crumb button.app-crumb__link {
  color: var(--c-muted); text-decoration: none; background: none; border: none;
  padding: 0; font: inherit; cursor: pointer; border-radius: var(--radius-sm);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.app-crumb a:hover, .app-crumb button.app-crumb__link:hover {
  color: var(--c-heading); text-decoration: underline;
}
.app-crumb a:focus-visible, .app-crumb button.app-crumb__link:focus-visible {
  outline: 2px solid var(--c-focus); outline-offset: 2px;
}
.app-crumb [aria-current="page"] {
  color: var(--c-heading); font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Ancien rendu (niveau courant en <b>), conservé le temps que toutes les
   pages passent à la liste ordonnée. */
.app-crumb b { color: var(--c-heading); font-weight: 600; }
.app-topbar__right { margin-left: auto; display: flex; align-items: center; gap: var(--space-3); }
.app-body { padding: var(--space-8); width: 100%; }

/* .icon-btn et sa variante .icon-btn--guide (bouton « Guide ») : primitives
   centralisées dans design-system.css, comme au Back-Office. */

/* ── Menu d'administration (roue crantée + menu déroulant) ──────────── */
.admin-menu { position: relative; display: inline-flex; }
.admin-menu__panel {
  position: absolute; top: calc(100% + 8px); right: 0;
  min-width: 230px;
  background: var(--c-card); border: 1px solid var(--c-border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
  padding: var(--space-2); z-index: var(--z-nav);
  display: flex; flex-direction: column; gap: 2px;
  animation: am-pop var(--t-fast) var(--ease);
}
.admin-menu__panel[hidden] { display: none; }
.admin-menu__title {
  font-family: var(--font-display); font-size: var(--fs-xs); font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.08em; color: var(--c-muted);
  padding: var(--space-2) var(--space-3) var(--space-1);
}
.admin-menu__item {
  display: flex; align-items: center; gap: var(--space-3);
  padding: 0.55rem var(--space-3); border-radius: var(--radius-sm);
  color: var(--c-text-soft); text-decoration: none;
  font-size: var(--fs-sm); font-weight: 600;
  transition: background var(--t-fast), color var(--t-fast);
}
.admin-menu__item:hover { background: var(--c-chip); color: var(--c-heading); text-decoration: none; }
.admin-menu__item.is-active { background: var(--c-accent-soft); color: var(--c-accent-ink); }
.admin-menu__ico {
  width: 26px; height: 26px; border-radius: var(--radius-sm); flex-shrink: 0;
  display: grid; place-items: center; background: var(--c-chip); color: var(--c-muted);
}
.admin-menu__ico svg { width: 15px; height: 15px; stroke: currentColor; stroke-width: 1.8; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.admin-menu__item.is-active .admin-menu__ico { background: var(--c-accent); color: var(--c-accent-on); }

@keyframes am-pop { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: translateY(0); } }
@media (prefers-reduced-motion: reduce) { .admin-menu__panel { animation: none; } }

/* Bascule de thème (icône soleil/lune) : règles centralisées dans design-system.css */

/* ------------------------------------------------------------------ */
/* Composants réutilisables (icônes modules, cartes, KPI, avatar)      */
/* ------------------------------------------------------------------ */
/* .avatar / .mod-ico : déplacés dans design-system.css (composants partagés) */

.module-card { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-6); background: var(--c-card); border: 1px solid var(--c-border); border-radius: var(--radius-lg); box-shadow: var(--shadow-xs); text-decoration: none; color: inherit; position: relative; overflow: hidden; transition: transform var(--t-base), box-shadow var(--t-base), border-color var(--t-base); }
.module-card::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--c-accent); transform: scaleY(0); transform-origin: top; transition: transform var(--t-base); }
.module-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); border-color: var(--c-border-strong); text-decoration: none; }
.module-card:hover::before { transform: scaleY(1); }
.module-card__name { font-family: var(--font-display); font-weight: 600; font-size: var(--fs-md); color: var(--c-heading); }
.module-card__desc { font-size: var(--fs-sm); color: var(--c-muted); line-height: var(--lh-snug); }
/* Action de la carte : même bouton plein orange que sur les cartes de rapport.
   C'est un repère visuel, pas un contrôle à part — toute la carte est un lien. */
.module-card__go {
  margin-top: auto; align-self: flex-start;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 15px; border-radius: var(--radius-md);
  background: var(--c-accent); color: var(--c-accent-on);
  font-size: var(--fs-sm); font-weight: 600; box-shadow: var(--shadow-xs);
  transition: background var(--t-fast), box-shadow var(--t-fast);
}
.module-card__go svg { width: 15px; height: 15px; stroke: currentColor; stroke-width: 2.2; fill: none; stroke-linecap: round; stroke-linejoin: round; transition: transform var(--t-fast); }
.module-card:hover .module-card__go { background: var(--c-accent-hover); box-shadow: var(--shadow-accent); }
.module-card:hover .module-card__go svg { transform: translateX(3px); }
.module-card--locked { background: color-mix(in srgb, var(--c-card) 88%, var(--c-muted)); cursor: not-allowed; box-shadow: none; }
.module-card--locked:hover { transform: none; box-shadow: none; border-color: var(--c-border); }
.module-card--locked:hover::before { transform: scaleY(0); }
.module-card .mod-ico, .module-card .mod-ico--blue, .module-card .mod-ico--navy {
  width: 46px; height: 46px; border-radius: var(--radius-md);
  display: grid; place-items: center; margin-bottom: var(--space-1);
  background: var(--c-accent-soft); color: var(--c-accent-ink);
}
.module-card .mod-ico svg { width: 23px; height: 23px; stroke-linecap: round; stroke-linejoin: round; }
.module-card__name { font-family: var(--font-display); font-size: var(--fs-md); font-weight: 600; color: var(--c-heading); }
.module-card__desc { color: var(--c-muted); font-size: var(--fs-sm); line-height: var(--lh-snug); flex: 1; }
.module-card--locked .mod-ico { background: var(--c-chip); color: var(--c-muted); }

.kpi { background: var(--c-card); border: 1px solid var(--c-border); border-radius: var(--radius-lg); padding: var(--space-5); box-shadow: var(--shadow-sm); }
.kpi__label { font-size: var(--fs-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--c-muted); }
.kpi__value { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-2xl); color: var(--c-heading); margin-top: var(--space-2); font-variant-numeric: tabular-nums; }
.kpi__trend { font-size: var(--fs-xs); font-weight: 600; margin-top: var(--space-1); display: inline-flex; align-items: center; gap: 4px; }
.kpi__trend--up { color: var(--c-success); }
.kpi__trend--down { color: var(--c-danger); }
[data-theme="dark"] .kpi__trend--up { color: #4ADE80; }
[data-theme="dark"] .kpi__trend--down { color: #F87171; }

/* ------------------------------------------------------------------ */
/* Hamburger (mobile)                                                  */
/* ------------------------------------------------------------------ */
.nav-mobile-toggle {
  display: none; width: 40px; height: 40px; border-radius: var(--radius-md);
  border: 1px solid var(--c-border); background: var(--c-card); color: var(--c-text-soft);
  cursor: pointer; align-items: center; justify-content: center; transition: all var(--t-fast); margin-right: var(--space-2);
}
.nav-mobile-toggle:hover { color: var(--c-heading); border-color: var(--c-border-strong); }
.nav-mobile-toggle svg { width: 20px; height: 20px; stroke: currentColor; stroke-width: 2; fill: none; stroke-linecap: round; stroke-linejoin: round; }

/* Scrim affiché derrière la sidebar mobile ouverte */
.nav-scrim {
  display: none; position: fixed; inset: 0; background: rgba(15,18,32,0.55);
  backdrop-filter: blur(2px); z-index: calc(var(--z-nav) - 1);
  opacity: 0; transition: opacity var(--t-base);
}
body.nav-mobile-open .nav-scrim { display: block; opacity: 1; }

/* ------------------------------------------------------------------ */
/* Responsive                                                          */
/* ------------------------------------------------------------------ */

/* Tablette et portables 13" : le repli est le DÉFAUT, pas un verrou.
   theme.js pose la classe `nav-collapsed` quand aucune préférence n'est
   enregistrée ; le bouton de repli reste donc visible et l'utilisateur peut
   déplier. La version précédente forçait l'état replié en CSS ET masquait le
   bouton : libellés et déconnexion devenaient inaccessibles sur ces largeurs
   (alignement sur Back-Office-TC). */
@media (max-width: 1080px) and (min-width: 721px) {
  .app-body { padding: var(--space-6); }
  .app-topbar { padding: 0 var(--space-6); }
}

/* Mobile : sidebar en off-canvas, hamburger dans la topbar */
@media (max-width: 720px) {
  /* `.nav-collapsed` compris : sa règle (78 px) est plus spécifique et
     l'emporterait sinon sur le 0 du tiroir. */
  body.app, body.app.nav-collapsed { --sb: 0px; }
  .app-sidebar {
    width: 280px;
    transform: translateX(-100%);
    transition: transform var(--t-base) var(--ease, ease);
    box-shadow: var(--shadow-xl);
  }
  body.nav-mobile-open .app-sidebar { transform: translateX(0); }
  /* Le tiroir est large (280 px) : on annule TOUT l'habillage « replié »,
     que la classe `nav-collapsed` soit présente ou non (préférence
     enregistrée, ou défaut posé sous 1080 px avant un redimensionnement). */
  .app-sidebar__logo, .nav-link span, .nav-section, .app-user .meta { opacity: 1 !important; }
  body.nav-collapsed .nav-section { height: auto; padding: var(--space-4) var(--space-3) var(--space-2); overflow: visible; }
  body.nav-collapsed .nav-link .lock { display: block; }
  body.nav-collapsed .nav-skel--sec { height: 9px; width: 44%; margin: var(--space-4) var(--space-3) var(--space-3); }
  body.nav-collapsed .nav-skel--nm { display: block; }
  body.nav-collapsed .app-user { flex-direction: row; gap: var(--space-3); }
  body.nav-collapsed .app-user .meta { position: static; pointer-events: auto; }
  body.nav-collapsed .app-user__logout { margin-left: auto; background: none; }
  .nav-collapse-btn { display: none; }
  .app-main { margin-left: 0; }
  .nav-mobile-toggle { display: inline-flex; }
  .app-topbar { padding: 0 var(--space-4); gap: var(--space-3); height: 60px; }
  .app-body { padding: var(--space-5) var(--space-4); }
  .app-crumb { font-size: var(--fs-xs); }

}

/* Très petits écrans : on resserre encore */
@media (max-width: 420px) {
  .app-topbar { padding: 0 var(--space-3); }
  .app-body { padding: var(--space-4) var(--space-3); }
  .app-sidebar { width: 86vw; }
}
