/* Rohy — design tokens (cf. design_handoff_expense_tracker/README.md) */
:root,
[data-theme="dark"] {
  /* Sans ça, les éléments natifs du navigateur (sélecteur de date,
     liste déroulante ouverte, barre de défilement) gardent un rendu clair
     par défaut même quand le thème sombre de l'app est actif — décalage
     visible notamment sur le picker de date natif. */
  color-scheme: dark;
  --surface-canvas: #111318;
  --surface-raised: #1B1E27;
  --surface-overlay: #262A35;
  --surface-sunken: #0A0B0E;
  --text-primary: #F4F3F0;
  --text-secondary: #9A9AA4;
  --text-tertiary: #6E7080;
  --border-subtle: #262A35;
  --border-default: #363B49;
  --brand-primary: #0F8F6B;
  --brand-primary-hover: #12AF83;
  --brand-secondary: #0F8F6B;
  --status-positive: #4ADE80;
  --status-positive-bg: rgba(74, 222, 128, .12);
  --status-warning: #F4D35E;
  --status-warning-bg: rgba(244, 211, 94, .12);
  --status-danger: #F97362;
  --status-danger-bg: rgba(249, 115, 98, .12);
  --status-neutral: #7D8194;
  --status-neutral-bg: rgba(125, 129, 148, .12);
}

[data-theme="light"] {
  color-scheme: light;
  --surface-canvas: #FAF9F6;
  --surface-raised: #FFFFFF;
  --surface-overlay: #F4F3F0;
  --surface-sunken: #F0EEE8;
  --text-primary: #14161B;
  --text-secondary: #55575F;
  --text-tertiary: #83858C;
  --border-subtle: #E7E4DC;
  --border-default: #D8D4C9;
  --brand-primary: #0F8F6B;
  --brand-primary-hover: #0A5C45;
  --brand-secondary: #0F8F6B;
  /* Versions assombries de ces couleurs par rapport à leur teinte "brand"
     d'origine (#29B876/#C99A1E/#E1533F) : sur fond clair, ces teintes plus
     vives tombaient sous 3:1 de contraste (illisibles). Les fonds `-bg`
     (halos très clairs) gardent la teinte d'origine, seule la couleur de
     texte/icône pleine est assombrie. */
  --status-positive: #1E8656;
  --status-positive-bg: rgba(41, 184, 118, .12);
  --status-warning: #947116;
  --status-warning-bg: rgba(201, 154, 30, .12);
  --status-danger: #DC3922;
  --status-danger-bg: rgba(225, 83, 63, .1);
  --status-neutral: #6B6E78;
  --status-neutral-bg: rgba(107, 110, 120, .1);
}

@keyframes slideUp { from { transform: translateY(28px); opacity: 0 } to { transform: translateY(0); opacity: 1 } }
@keyframes fadeIn { from { opacity: 0 } to { opacity: 1 } }
@keyframes screenIn { from { opacity: 0; transform: translateY(6px) } to { opacity: 1; transform: translateY(0) } }
@keyframes popIn { from { opacity: 0; transform: translateY(-6px) scale(.98) } to { opacity: 1; transform: translateY(0) scale(1) } }

* { box-sizing: border-box; transition: background-color .15s ease, border-color .15s ease; }
/* Un re-rendu (innerHTML) reconstruit tout le sous-arbre : sans ça, la
   transition ci-dessus rejoue sur les nœuds fraîchement créés à chaque
   frappe dans un champ non "silencieux", provoquant un flash visuel.
   Basculée par scripts/app.js autour de chaque appel à render(). */
.no-transition, .no-transition * { transition: none !important; }
/* overflow-x + overscroll-behavior-x : empêche tout défilement horizontal
   (accidentel, ou l'effet de rebond élastique de certains navigateurs
   mobiles quand on swipe au-delà du bord gauche/droit), qui décalait
   momentanément l'app hors de son centrage. Ne touche pas au défilement
   vertical (scroll normal, pull-to-refresh). */
html, body { margin: 0; height: 100%; overflow-x: hidden; overscroll-behavior-x: none; }
body {
  background: var(--surface-sunken);
  font-family: 'Manrope', sans-serif;
  color: var(--text-primary);
}
h1, h2, h3 { font-family: 'Sora', sans-serif; }
input::placeholder { color: var(--text-tertiary); }
::-webkit-scrollbar { width: 0; height: 0; }
button { font-family: inherit; }

/* Par défaut (jusqu'à DESKTOP_BREAKPOINT ci-dessous, cf. media query) :
   l'app occupe tout l'écran, sans "carte" ni marge — c'est ce qui donne
   l'impression d'une vraie app plutôt qu'une maquette de téléphone flottant
   au milieu de la page. 100vh : repli pour les navigateurs qui ne
   connaissent aucune des unités dynamiques ci-dessous. 100dvh (hauteur de
   viewport "dynamique") tente de suivre l'affichage/masquage du chrome du
   navigateur, mais s'est avérée peu fiable en pratique sur certains
   navigateurs/contextes mobiles (barre d'outils ancrée en bas, barre de
   navigation gestuelle Android, navigateurs intégrés) — y compris une
   première tentative de correctif via window.visualViewport, qui ne
   reflétait pas non plus toujours correctement cette barre, laissant le
   menu du bas (position: fixed; bottom: 0) caché derrière. 100svh (hauteur
   de viewport "small", qui suppose TOUJOURS le chrome du navigateur affiché
   au maximum) est le dernier repli : par définition jamais trop grande,
   donc jamais susceptible de cacher le menu du bas derrière une barre du
   navigateur — au prix, dans de rares cas, de ne pas profiter du plein
   espace disponible quand ce chrome vient à disparaître (compromis
   largement préférable à un menu inaccessible). */
.app-frame-wrap {
  min-height: 100vh;
  min-height: 100dvh;
  min-height: 100svh;
}
.app-frame {
  width: 100%;
  height: 100vh;
  height: 100dvh;
  height: 100svh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  position: relative;
  background: var(--surface-canvas);
  /* `data-theme` (clair/sombre) est porté par cet élément (et par <html>,
     cf. app.js) — sans ce color explicite, tout texte sans couleur propre
     hérite du color de <body>, résolu HORS de ce scope de thème (donc
     toujours celui du thème sombre, quel que soit le thème réellement actif). */
  color: var(--text-primary);
}

/* À partir de ce seuil (desktop), l'app garde le plein écran (pas de
   "carte" flottante avec ombre — ça, c'est justement ce qui donnait
   l'impression d'une appli mobile agrandie plutôt que d'un site pensé pour
   le desktop) mais réorganise la navigation en menu latéral fixe façon
   application web classique (Gmail, Notion...), avec une colonne de
   contenu de largeur confortable à lire plutôt qu'étirée sur toute la
   largeur de l'écran. */
@media (min-width: 900px) {
  .app-frame {
    display: grid;
    grid-template-columns: 240px 1fr;
    grid-template-rows: auto 1fr;
    grid-template-areas: "nav topbar" "nav content";
  }
  .top-bar { grid-area: topbar; max-width: 720px; margin: 0 auto; width: 100%; }
  .content { grid-area: content; padding-bottom: 24px; max-width: 720px; margin: 0 auto; width: 100%; }

  /* .login-screen et .loading-screen n'ont pas de grid-area (pas de menu ni
     de barre du haut tant qu'on n'est pas connecté) : sans cette règle, la
     grille les casait par défaut dans la première cellule libre (la colonne
     de 240px prévue pour le menu), collant tout le formulaire de connexion
     contre le bord. On les fait plutôt occuper toute la grille et on centre
     le formulaire dans une carte, comme une page de connexion classique
     (Notion, Linear...) plutôt qu'un formulaire étiré sur un écran large. */
  .app-frame > .login-screen {
    grid-column: 1 / -1;
    grid-row: 1 / -1;
    align-self: center;
    justify-self: center;
    flex: none;
    width: 100%;
    max-width: 400px;
    padding: 40px 36px;
    background: var(--surface-raised);
    border-radius: 24px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, .16);
  }
  .app-frame > .loading-screen {
    grid-column: 1 / -1;
    grid-row: 1 / -1;
  }
  .app-frame > .splash-screen {
    grid-column: 1 / -1;
    grid-row: 1 / -1;
  }
}

.pressable { cursor: pointer; }
.pressable:active { transform: scale(0.96); }

/* --- Login --- */
.login-screen { flex: 1; display: flex; flex-direction: column; padding: 32px 24px; overflow-y: auto; }
.loading-screen { flex: 1; display: flex; align-items: center; justify-content: center; color: var(--text-secondary); font-size: 14px; }
/* --- Écran de lancement --- */
.splash-screen { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; background: var(--surface-canvas); }
/* Chaque bande s'assemble à sa place définitive (échelle, avec un léger
   dépassement avant de se stabiliser) plutôt que de parcourir une longue
   distance : plus net et plus confiant qu'un glissement, et honnête sur ce
   qu'une simple transformation 2D peut représenter (un vrai tissage
   par-dessus/en-dessous demanderait de faire alterner l'ordre d'empilement
   des bandes, pas juste leur position). Bandes verticales puis horizontales
   groupées (écart de .09s au sein d'un même groupe, contre .4s entre les
   deux groupes) : chaque étape intermédiaire montre un ensemble de couleurs
   cohérent (le trio doré/violet, puis le motif complet), jamais une bande
   isolée qui jure avec le reste. Contour et remplissage de chaque bande
   horizontale partagent la même classe et le même délai (`.splash-h`) pour
   apparaître ensemble — l'ancienne version animait seulement le
   remplissage, laissant le contour vide visible dès le début.
   Volontairement PAS de fondu d'opacité ici (contrairement à un premier
   essai) : une bande semi-transparente en cours de fondu laisse voir par
   transparence la bordure de la bande qu'elle est censée recouvrir —
   visible le temps de la transition. Une échelle seule reste toujours
   pleinement opaque, donc masque proprement dès qu'elle atteint un point,
   sans jamais laisser rien transparaître.
   Le point d'origine de chaque bande (`transform-origin`) est fixé en
   coordonnées explicites, en style inline sur chaque élément (cf. JS) —
   plutôt que `transform-box: fill-box` + `transform-origin: center`, dont
   le support est inégal selon les navigateurs pour les éléments <path>
   (notamment sur WebKit/iOS, où le point de départ de l'échelle peut être
   mal calculé, décalant la bordure par rapport au remplissage pendant la
   transition et recréant un bug d'apparence similaire à celui de la
   transparence). Des coordonnées explicites contournent entièrement ce
   calcul de boîte englobante et sont fiables sur tous les navigateurs. */
.splash-v, .splash-h {
  animation: splashSettle .55s cubic-bezier(.2, .7, .3, 1) both;
}
@keyframes splashSettle {
  0%   { transform: scale(0); }
  65%  { transform: scale(1.05); }
  100% { transform: scale(1); }
}
/* Wordmark + baseline : apparaissent une fois le motif assemblé (dernière
   bande installée à 1.13s), puis restent affichés le temps que l'utilisateur
   les lise avant que l'écran de lancement ne disparaisse (cf. le délai dans
   DOMContentLoaded, ajusté en conséquence). Léger décalage entre les deux
   (wordmark puis baseline) plutôt qu'une apparition simultanée — un fondu
   enchaîné progressif plutôt qu'un bloc de texte qui surgit d'un coup. */
.splash-wordmark {
  font-family: 'Sora', sans-serif; font-weight: 800; font-size: 30px; color: var(--brand-primary);
  margin-top: 18px; opacity: 0; animation: splashFadeUp .5s ease both; animation-delay: 1.3s;
}
.splash-tagline {
  font-size: 14px; color: var(--text-secondary); opacity: 0; animation: splashFadeUp .5s ease both; animation-delay: 1.48s;
}
@keyframes splashFadeUp { 0% { opacity: 0; transform: translateY(10px); } 100% { opacity: 1; transform: translateY(0); } }
.login-brand { display: flex; align-items: center; gap: 14px; margin-bottom: 24px; }
.login-icon { width: 52px; height: 52px; border-radius: 16px; background: rgba(15, 143, 107, .12); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.login-wordmark { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 22px; color: var(--brand-primary); }
.login-title { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 24px; color: var(--text-primary); margin-bottom: 6px; }
.login-subtitle { font-size: 13px; color: var(--text-secondary); margin-bottom: 26px; }
.field-label { font-size: 11px; font-weight: 800; color: var(--text-tertiary); text-transform: uppercase; letter-spacing: .06em; margin-bottom: 8px; }
.text-input {
  width: 100%; padding: 13px 15px; border-radius: 14px; border: 1px solid var(--border-default);
  background: var(--surface-canvas); color: var(--text-primary);
  /* 16px minimum : en dessous, Safari iOS zoome automatiquement toute la
     page dès qu'on touche le champ (comportement natif non désactivable
     autrement que par la taille de police elle-même). */
  font-size: 16px; margin-bottom: 14px;
  font-family: 'Manrope', sans-serif;
}
/* Un <select> avec juste la classe .text-input garde la flèche native du
   navigateur/OS, qui jure avec le reste du design (pas la même forme, pas
   toujours bien centrée dans le padding). .select-field masque cette
   flèche (`appearance: none`) et la remplace par un chevron Phosphor,
   cohérent avec les autres icônes de l'app (ex. le chevron déjà utilisé sur
   la ligne "Bonjour" de l'accueil). */
.select-field { position: relative; margin-bottom: 14px; }
.select-field .select-native { margin-bottom: 0; appearance: none; -webkit-appearance: none; padding-right: 38px; }
.select-field .select-chevron {
  position: absolute; right: 15px; top: 50%; transform: translateY(-50%);
  font-size: 13px; color: var(--text-tertiary); pointer-events: none;
}
.link-right { text-align: right; color: var(--brand-primary-hover); font-size: 13px; font-weight: 700; margin-bottom: 20px; cursor: pointer; }
.btn-primary {
  text-align: center; padding: 14px; background: var(--brand-primary); color: #fff; border-radius: 14px;
  font-weight: 700; font-size: 15px; cursor: pointer; border: none; width: 100%;
  box-shadow: 0 0 0 1px rgba(15, 143, 107, .4), 0 8px 24px rgba(15, 143, 107, .25);
}
/* (hover: hover) : limite ces styles aux appareils à pointeur réel
   (souris/trackpad). Sans ce garde-fou, un survol reste "collé" après un
   tap sur tout appareil tactile (téléphone, ou tablette assez large pour
   passer les seuils desktop ci-dessous) jusqu'au tap suivant ailleurs. */
@media (hover: hover) { .btn-primary:hover { background: var(--brand-primary-hover); } }
.form-error { text-align: center; color: var(--status-danger); font-size: 12.5px; margin-top: 10px; }
.divider-or { display: flex; align-items: center; gap: 10px; margin: 20px 0; color: var(--text-tertiary); font-size: 12px; }
.divider-or::before, .divider-or::after { content: ''; flex: 1; height: 1px; background: var(--border-subtle); }
.link-center { text-align: center; color: var(--text-secondary); font-size: 13.5px; font-weight: 600; cursor: pointer; }
/* Discret et ancré en bas de l'écran de connexion (margin-top: auto sur ce
   conteneur flex en colonne) plutôt qu'un lien mis en avant — la page de
   connexion doit rester concentrée sur l'action de se connecter/s'inscrire. */
.login-footer-link { text-align: center; color: var(--text-tertiary); font-size: 12px; font-weight: 600; cursor: pointer; margin-top: auto; padding-top: 24px; }
.magic-confirm { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; }
.magic-icon { width: 64px; height: 64px; border-radius: 50%; background: var(--status-positive-bg); display: flex; align-items: center; justify-content: center; color: var(--status-positive); font-size: 28px; margin-bottom: 20px; }

/* --- Top bar --- */
.top-bar { padding: 18px 20px 14px; display: flex; align-items: center; gap: 10px; border-bottom: 1px solid var(--border-subtle); flex-shrink: 0; }
.icon-btn { width: 34px; height: 34px; border-radius: 14px; background: var(--surface-raised); display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-primary); font-size: 16px; flex-shrink: 0; border: none; }
.icon-btn.small { width: 36px; height: 36px; }
.icon-btn.brand { background: var(--brand-primary); color: #fff; box-shadow: 0 0 0 1px rgba(15, 143, 107, .4), 0 8px 20px rgba(15, 143, 107, .22); }
@media (hover: hover) { .icon-btn.brand:hover { background: var(--brand-primary-hover); } }
.top-title { font-family: 'Sora', sans-serif; font-weight: 700; font-size: 19px; color: var(--text-primary); letter-spacing: -0.2px; }
/* Sur l'écran d'accueil, le titre texte ("Mes dépenses") cède la place au
   logo + wordmark (cf. .top-bar-wordmark) — mais seulement sur mobile. Sur
   desktop, le menu latéral affiche déjà la marque en permanence : garder
   aussi le wordmark dans cette barre ferait apparaître le logo deux fois
   sur le même écran (cf. media query plus bas, qui inverse ces deux règles). */
.top-title.home-title { display: none; }
.top-subtitle { font-size: 12.5px; color: var(--text-tertiary); margin-top: 1px; }
/* Logo dans la barre du haut : uniquement sur les écrans de premier niveau
   (pas de bouton retour) — remplace ce bouton dans le même emplacement pour
   que le titre ne saute pas d'un écran à l'autre. */
.top-bar-logo { width: 34px; height: 34px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
/* Logo multicolore + wordmark, réservé à l'écran d'accueil sur mobile
   uniquement (cf. .top-title.home-title ci-dessus). */
.top-bar-wordmark { display: flex; align-items: center; gap: 8px; flex-shrink: 0; font-family: 'Sora', sans-serif; font-weight: 800; font-size: 17px; color: var(--text-primary); }

/* --- Content --- */
.content { flex: 1; overflow-y: auto; padding: 18px 20px 90px; }
.section-label { color: var(--text-tertiary); font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; margin-bottom: 10px; }
.select-all-link { text-transform: none; letter-spacing: normal; font-size: 12px; font-weight: 700; color: var(--brand-secondary); cursor: pointer; }

/* --- Home --- */
.current-user-row { display: flex; align-items: center; gap: 8px; cursor: pointer; margin-bottom: 16px; width: fit-content; border: none; background: none; padding: 0; }
.current-user-row:active { opacity: .7; }
.avatar { border-radius: 50%; display: flex; align-items: center; justify-content: center; font-family: 'Sora', sans-serif; font-weight: 700; color: #0B1210; flex-shrink: 0; }
.avatar-26 { width: 26px; height: 26px; font-size: 10px; }
.avatar-30 { width: 30px; height: 30px; font-size: 12px; }
.avatar-38 { width: 38px; height: 38px; font-size: 14px; }
.avatar-64 { width: 64px; height: 64px; font-size: 22px; margin: 0 auto 12px; }

.balance-card { background: var(--surface-raised); border-radius: 20px; padding: 22px; margin-bottom: 16px; animation: screenIn .25s ease; }
.balance-label { font-size: 13px; color: var(--text-secondary); font-weight: 500; }
.balance-amount { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 28px; margin-top: 6px; }
.balance-detail-row { display: flex; gap: 18px; margin-top: 14px; }
.balance-detail-row .owed { font-size: 13px; color: var(--status-positive); font-weight: 500; }
.balance-detail-row .owe { font-size: 13px; color: var(--status-danger); font-weight: 500; }

.warning-banner { background: var(--status-warning-bg); border: 1px solid var(--status-warning); border-radius: 16px; padding: 14px 16px; margin-bottom: 16px; }
.warning-banner-title { display: flex; align-items: center; gap: 8px; color: var(--status-warning); font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; }
.warning-banner-body { color: var(--text-primary); font-size: 14px; margin-top: 6px; font-weight: 500; }

.person-row { display: flex; align-items: center; gap: 12px; background: var(--surface-raised); border-radius: 16px; padding: 12px 14px; margin-bottom: 8px; cursor: pointer; border: none; width: 100%; text-align: left; }
.person-row:active { transform: scale(0.98); }
.person-name { font-size: 15px; font-weight: 600; color: var(--text-primary); }
.badge-child { font-size: 10px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--status-warning); background: var(--status-warning-bg); padding: 2px 8px; border-radius: 999px; display: inline-block; margin-top: 3px; }
.badge-child.inline { font-size: 9.5px; padding: 2px 6px; margin-left: 5px; margin-top: 0; }
.covered-note { font-size: 11.5px; color: var(--text-tertiary); margin-top: 2px; }
.person-amount { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 15px; }
.remind-link { font-size: 11.5px; color: var(--brand-primary); font-weight: 700; margin-top: 3px; background: none; border: none; padding: 0; cursor: pointer; }

/* --- Groups --- */
.group-card { background: var(--surface-raised); border-radius: 20px; padding: 16px; margin-bottom: 12px; cursor: pointer; display: flex; align-items: center; gap: 12px; border: none; width: 100%; text-align: left; }
.group-card:active { transform: scale(0.98); }
.group-icon { width: 44px; height: 44px; border-radius: 14px; background: var(--surface-overlay); display: flex; align-items: center; justify-content: center; color: var(--brand-primary); font-size: 19px; flex-shrink: 0; }
.group-name { font-size: 16px; font-weight: 700; color: var(--text-primary); }
.group-members { font-size: 12px; color: var(--text-tertiary); margin-top: 1px; }
.group-summary { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 14px; }
.dashed-btn { text-align: center; padding: 14px; border: 1.5px dashed var(--border-default); border-radius: 16px; color: var(--text-tertiary); font-weight: 700; font-size: 14px; cursor: pointer; margin-top: 6px; background: none; width: 100%; }
@media (hover: hover) { .dashed-btn:hover { border-color: var(--brand-primary); color: var(--brand-primary-hover); } }

/* --- Pièce jointe (formulaire dépense) --- */
/* Zone cliquable habillée façon "dashed-btn" plutôt que le <input type="file">
   natif du navigateur (rendu très brut, incohérent avec le reste des champs).
   L'input reste un vrai <input type="file"> superposé en transparence sur
   toute la zone (accessible au clavier, ouvre le bon sélecteur — photo/PDF —
   sur mobile), seul son style par défaut est masqué. */
.attachment-dropzone {
  position: relative; display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 18px 14px; border: 1.5px dashed var(--border-default); border-radius: 16px;
  color: var(--text-tertiary); font-weight: 700; font-size: 13.5px; cursor: pointer; margin-bottom: 14px;
}
@media (hover: hover) { .attachment-dropzone:hover { border-color: var(--brand-primary); color: var(--brand-primary-hover); } }
.attachment-dropzone input[type="file"] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.attachment-picked { display: flex; align-items: center; gap: 10px; background: var(--surface-raised); border-radius: 14px; padding: 11px 12px; margin-bottom: 14px; }
.attachment-picked i { color: var(--status-positive); font-size: 17px; flex-shrink: 0; }
.attachment-picked-name { flex: 1; font-size: 13px; color: var(--text-primary); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.attachment-picked-clear { width: 26px; height: 26px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; border-radius: 8px; background: none; border: none; color: var(--text-tertiary); cursor: pointer; }
@media (hover: hover) { .attachment-picked-clear:hover { background: var(--surface-overlay); color: var(--text-primary); } }

/* --- Scan de ticket (formulaire dépense) --- */
/* Même logique que .attachment-dropzone (input[type=file] natif superposé en
   transparence), avec un traitement plus affirmé (couleur de marque) pour se
   distinguer de la zone "pièce jointe" plus bas : celle-ci est LE point
   d'entrée principal mis en avant, pas une simple pièce jointe optionnelle. */
.scan-dropzone {
  position: relative; display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 16px 14px; border: 1.5px dashed var(--brand-primary); border-radius: 16px;
  color: var(--brand-primary); font-weight: 700; font-size: 14px; cursor: pointer; margin-bottom: 18px;
  background: rgba(15, 143, 107, .06);
}
@media (hover: hover) { .scan-dropzone:hover { background: rgba(15, 143, 107, .1); } }
.scan-dropzone input[type="file"] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.scan-dropzone.scanning { pointer-events: none; }
.scan-spinner { width: 16px; height: 16px; border: 2px solid rgba(15, 143, 107, .3); border-top-color: var(--brand-primary); border-radius: 50%; animation: scanSpin .7s linear infinite; flex-shrink: 0; }
@keyframes scanSpin { to { transform: rotate(360deg); } }

/* --- Group detail --- */
.member-table { background: var(--surface-raised); border-radius: 20px; padding: 16px; margin-bottom: 16px; }
.member-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-top: 1px solid var(--border-subtle); }
.member-row:first-child { border-top: none; }
.col-name { flex: 1; font-size: 14px; font-weight: 600; color: var(--text-primary); }
.col-num { width: 64px; text-align: right; font-size: 12.5px; color: var(--text-tertiary); }
.col-bal { width: 80px; text-align: right; font-family: 'Sora', sans-serif; font-weight: 700; font-size: 13px; }
.admin-actions { display: flex; gap: 10px; margin-bottom: 16px; }
.btn-outline { flex: 1; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 11px; border: 1px solid var(--border-default); border-radius: 14px; color: var(--text-primary); font-weight: 700; font-size: 13.5px; cursor: pointer; background: var(--surface-raised); }
.btn-outline:active { transform: scale(0.98); }
.btn-icon-danger { width: 44px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; border: 1px solid var(--border-default); border-radius: 14px; color: var(--status-danger); cursor: pointer; background: none; }
.suggestion-row { display: flex; align-items: center; justify-content: space-between; background: var(--surface-raised); border-radius: 14px; padding: 10px 14px; margin-bottom: 8px; font-size: 13.5px; color: var(--text-primary); }
.suggestion-amount { font-family: 'Sora', sans-serif; font-weight: 800; color: var(--brand-primary-hover); }
.btn-icon-settle { width: 32px; height: 32px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; border: 1px solid var(--border-default); border-radius: 12px; color: var(--status-positive); cursor: pointer; background: none; font-size: 15px; }

.expense-row { display: flex; align-items: center; gap: 10px; padding: 10px 0; border-top: 1px solid var(--border-subtle); cursor: pointer; }
.expense-row:first-child { border-top: none; }
.expense-row:active { opacity: .7; }
.expense-icon { width: 34px; height: 34px; border-radius: 12px; background: var(--surface-overlay); display: flex; align-items: center; justify-content: center; color: var(--text-secondary); font-size: 15px; flex-shrink: 0; }
.expense-label { font-size: 14px; font-weight: 600; color: var(--text-primary); }
.expense-subtitle { font-size: 11.5px; color: var(--text-tertiary); }
.expense-amount { font-family: 'Sora', sans-serif; font-weight: 700; font-size: 14px; color: var(--text-primary); }

/* --- Person detail --- */
.person-header { text-align: center; padding: 20px 0 6px; }
.person-header-name { font-family: 'Sora', sans-serif; font-weight: 700; font-size: 20px; color: var(--text-primary); }
.person-header-amount { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 26px; margin-top: 14px; }
.person-actions { display: flex; gap: 10px; margin: 16px 0 20px; }
.btn-danger-fill { flex: 1; text-align: center; padding: 12px; background: var(--status-danger); color: #fff; border-radius: 14px; font-weight: 700; font-size: 14px; cursor: pointer; border: none; }
.btn-danger-fill:active { transform: scale(0.97); }
.btn-outline-flex { flex: 1; text-align: center; padding: 12px; background: var(--surface-raised); color: var(--text-primary); border-radius: 14px; font-weight: 700; font-size: 14px; cursor: pointer; border: 1px solid var(--border-default); }
.btn-outline-flex:active { transform: scale(0.97); }
.reminder-preview { background: var(--status-danger-bg); border: 1px solid var(--status-danger); border-radius: 14px; padding: 12px 14px; font-size: 13px; color: var(--text-primary); margin-bottom: 16px; }
.person-expense-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-top: 1px solid var(--border-subtle); }
.person-expense-row:first-child { border-top: none; }

/* --- All expenses --- */
.summary-cards { display: flex; gap: 10px; margin-bottom: 16px; }
.summary-card { flex: 1; background: var(--surface-raised); border-radius: 16px; padding: 12px 10px; text-align: center; }
.summary-card-label { font-size: 10px; color: var(--text-tertiary); font-weight: 800; text-transform: uppercase; letter-spacing: .05em; }
.summary-card-value { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 15px; margin-top: 3px; }
.status-badge { font-size: 9.5px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase; padding: 2px 8px; border-radius: 999px; white-space: nowrap; flex-shrink: 0; }
.expense-meta-row { display: flex; align-items: center; gap: 6px; margin-top: 4px; flex-wrap: wrap; }
.due-external { font-size: 11.5px; color: var(--status-warning); margin-top: 5px; }
.mark-paid-link { font-size: 11.5px; font-weight: 700; color: var(--brand-primary-hover); margin-top: 3px; cursor: pointer; background: none; border: none; padding: 0; }

/* --- History --- */
.history-row { display: flex; align-items: center; gap: 12px; padding: 11px 0; border-top: 1px solid var(--border-subtle); }
.history-row:first-child { border-top: none; }
.history-icon { width: 32px; height: 32px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 14px; flex-shrink: 0; }
.history-text { font-size: 13.5px; color: var(--text-primary); font-weight: 600; }
.history-date { font-size: 11.5px; color: var(--text-tertiary); }
.history-amount { font-family: 'Sora', sans-serif; font-weight: 700; font-size: 13.5px; }

/* --- À propos --- */
.about-screen { padding: 32px 24px 40px; max-width: 560px; margin: 0 auto; }
.about-hero { display: flex; flex-direction: column; align-items: center; text-align: center; margin-bottom: 28px; }
.about-logo { margin-bottom: 16px; }
.about-name { font-family: 'Sora', sans-serif; font-weight: 800; font-size: 22px; color: var(--text-primary); }
.about-tagline { font-size: 13.5px; font-style: italic; color: var(--text-secondary); margin-top: 4px; }
.about-body p { font-size: 14px; line-height: 1.65; color: var(--text-secondary); margin: 0 0 12px; }
.about-body p:last-child { margin-bottom: 0; }
.about-lead { font-size: 15px !important; color: var(--text-primary) !important; }
.about-emphasis { font-weight: 600; color: var(--text-primary) !important; }
.about-heading { font-family: 'Sora', sans-serif; font-weight: 700; font-size: 16px; color: var(--brand-primary); margin: 0 0 10px; }
.about-list { margin: 0 0 4px; padding-left: 20px; }
.about-list li { font-size: 14px; line-height: 1.7; color: var(--text-secondary); margin-bottom: 4px; }
.about-divider { width: 40px; height: 1px; background: var(--border-default); margin: 24px auto; }
.about-closing {
  text-align: center; font-family: 'Sora', sans-serif; font-weight: 700; font-size: 15px;
  color: var(--brand-primary); line-height: 1.5; margin-bottom: 10px;
}
.about-meta { text-align: center; font-size: 12px; color: var(--text-tertiary); }

/* --- Bottom nav (menu latéral sur desktop, cf. media query) --- */
/* `fixed` (et non `absolute`) : ancré directement au viewport visuel plutôt
   qu'au bloc englobant .app-frame (dont la hauteur, en 100dvh, se recalcule
   en layout à chaque apparition/disparition de la barre d'adresse mobile).
   Avec `absolute`, ce recalcul de layout accuse un temps de retard sur
   l'animation (gérée par le compositeur) de la barre du navigateur, ce qui
   donnait l'impression que le menu "suivait" le scroll en laissant un
   espace vide entre lui et le bas réel de l'écran. En `fixed`, le menu
   colle instantanément au bas du viewport, comme sur une app native. */
.bottom-nav {
  position: fixed; bottom: 0; left: 0; right: 0; background: var(--surface-raised);
  /* Safari (macOS et iOS, donc aussi Chrome iOS qui partage le même moteur)
     n'a supporté la propriété non préfixée qu'à partir de la version 18 —
     sans le préfixe, le flou disparaît silencieusement sur les versions
     antérieures, majoritaires au moment du lancement. */
  -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
  border-top: 1px solid var(--border-subtle); display: flex; padding: 10px 8px calc(env(safe-area-inset-bottom, 0px) + 10px);
}
.nav-item { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; cursor: pointer; background: none; border: none; }
.nav-item-label { font-size: 10.5px; font-weight: 700; }
/* Logo en tête du menu latéral desktop (cf. media query) — invisible sur
   mobile, où .bottom-nav est une barre d'onglets horizontale sans place
   pour un en-tête de marque. */
.sidebar-brand { display: none; }
/* Entrée de compte ancrée en bas du menu latéral desktop (cf. media query)
   — invisible sur mobile, où l'icône de compte de la barre du haut
   (.account-icon-btn) remplit déjà ce rôle. */
.sidebar-account { display: none; }
/* Menu déroulant ancré à .sidebar-account, desktop uniquement (cf.
   media query) — sur mobile, cet élément n'existe que dans le flux du
   menu latéral desktop et doit rester invisible par défaut. */
.account-dropdown-overlay,
.account-dropdown { display: none; }

@media (min-width: 900px) {
  .bottom-nav {
    grid-area: nav;
    position: static;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 4px;
    padding: 24px 14px;
    border-top: none;
    border-right: 1px solid var(--border-subtle);
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  .sidebar-brand {
    display: flex; align-items: center; gap: 10px; padding: 0 14px 20px; margin-bottom: 8px;
    border-bottom: 1px solid var(--border-subtle);
    font-family: 'Sora', sans-serif; font-weight: 800; font-size: 16px; color: var(--text-primary);
  }
  /* Le logo de la barre du haut fait doublon avec celui du menu latéral
     (toujours visible à cette largeur) — masqué ici pour ne pas répéter la
     marque deux fois sur le même écran. */
  .top-bar-logo { display: none; }
  /* Idem pour le wordmark de l'accueil : le menu latéral porte déjà la
     marque en permanence, donc ici on revient au même traitement que les
     autres écrans (titre texte simple, pas de logo dans cette barre). */
  .top-bar-wordmark { display: none; }
  .top-title.home-title { display: block; }
  /* Idem : l'icône de compte de la barre du haut fait doublon avec l'entrée
     de compte ancrée en bas du menu latéral (cf. .sidebar-account) sur
     cette largeur. */
  .account-icon-btn { display: none; }
  /* Ancrée en bas du menu latéral (marge automatique sur le dernier
     nav-item avant elle la pousse vers le bas), façon Slack/Notion/Discord
     — toujours visible, séparée des liens de navigation principaux.
     position: relative sur le conteneur (et non le bouton lui-même) : sert
     de repère d'ancrage au menu déroulant (.account-dropdown), qui doit
     rester à la largeur du menu latéral quel que soit son contenu. */
  .sidebar-account-wrap { position: relative; margin-top: auto; }
  .sidebar-account {
    display: flex; align-items: center; gap: 10px; width: 100%; padding: 12px 14px;
    border: none; border-top: 1px solid var(--border-subtle); border-radius: 0;
    background: none; cursor: pointer;
  }
  @media (hover: hover) { .sidebar-account:hover { background: var(--surface-overlay); } }
  .sidebar-account-name { font-size: 13.5px; font-weight: 600; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* Avatar du menu latéral + de l'en-tête du menu déroulant : un léger
     contour et une ombre portée lui donnent un peu de relief sur ces deux
     fonds plats (menu latéral, en-tête du menu déroulant), plutôt qu'un
     aplat de couleur qui se fond dedans. */
  .avatar-account { box-shadow: 0 0 0 1px var(--border-subtle), 0 2px 5px rgba(0, 0, 0, .18); }
  .account-dropdown-overlay { display: block; position: fixed; inset: 0; z-index: 10; }
  .account-dropdown {
    display: flex; flex-direction: column; position: absolute; left: 0; right: 0; bottom: 100%;
    margin-bottom: 8px; background: var(--surface-raised); border: 1px solid var(--border-subtle);
    border-radius: 14px; box-shadow: 0 12px 32px rgba(0, 0, 0, .24); padding: 8px; z-index: 11;
    animation: popIn .15s ease;
  }
  .account-dropdown-header { display: flex; align-items: center; gap: 10px; padding: 8px 10px 10px; }
  .account-dropdown-name { font-size: 13.5px; font-weight: 600; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .account-dropdown-divider { height: 1px; background: var(--border-subtle); margin: 4px 0; }
  .account-dropdown-item {
    display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; padding: 9px 10px;
    border-radius: 10px; border: none; background: none; cursor: pointer; font-size: 13.5px;
    font-weight: 600; color: var(--text-primary); font-family: 'Manrope', sans-serif;
  }
  @media (hover: hover) { .account-dropdown-item:hover { background: var(--surface-overlay); } }
  .account-dropdown-item i { font-size: 16px; color: var(--text-tertiary); }
  /* Remplacée sur cette largeur par le menu déroulant ci-dessus (cf.
     renderAccountDropdown()), plus idiomatique qu'une feuille glissée
     depuis le bas façon mobile sur un écran large. Sélecteur à deux
     classes (et non juste .account-modal-mobile) : .modal-overlay fixe
     aussi son propre display:flex plus loin dans la feuille de style,
     à spécificité égale — sans ce cran de spécificité en plus, l'ordre
     du fichier ferait gagner .modal-overlay et la feuille resterait
     visible en plus du nouveau menu déroulant. */
  .modal-overlay.account-modal-mobile { display: none; }
  .nav-item {
    flex: none;
    flex-direction: row;
    justify-content: flex-start;
    gap: 12px;
    padding: 11px 14px;
    border-radius: 12px;
  }
  @media (hover: hover) { .nav-item:hover { background: var(--surface-overlay); } }
  .nav-item-label { font-size: 13.5px; }
}

/* --- Modals --- */
.modal-overlay { position: absolute; inset: 0; background: rgba(10, 11, 14, .6); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); display: flex; animation: fadeIn .15s ease; z-index: 10; }
.modal-overlay.bottom { align-items: flex-end; justify-content: center; }
.modal-overlay.center { align-items: center; justify-content: center; }
/* max-width : sur un .app-frame plein écran (desktop large notamment), les
   modales gardent une largeur de formulaire lisible plutôt que de s'étirer
   sur toute la largeur disponible. */
.modal-sheet { background: var(--surface-raised); border-radius: 28px 28px 0 0; width: 100%; max-width: 480px; max-height: 88%; overflow-y: auto; padding: 20px 20px 26px; animation: slideUp .28s cubic-bezier(.3, .7, .4, 1); box-shadow: 0 20px 60px rgba(0, 0, 0, .5); }
.modal-card { background: var(--surface-raised); border-radius: 20px; width: 85%; max-width: 420px; padding: 22px; animation: slideUp .28s cubic-bezier(.3, .7, .4, 1); box-shadow: 0 20px 60px rgba(0, 0, 0, .5); }
.modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
.modal-title { font-family: 'Sora', sans-serif; font-weight: 700; font-size: 18px; color: var(--text-primary); }
.modal-close { color: var(--text-tertiary); cursor: pointer; font-size: 20px; background: none; border: none; }
.pill-row { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 16px; }
.pill { padding: 8px 14px; border-radius: 999px; font-size: 13px; font-weight: 700; cursor: pointer; border: 1px solid var(--border-default); background: var(--surface-overlay); color: var(--text-primary); }
.pill.active { background: var(--brand-primary); color: #fff; border-color: var(--brand-primary); }
.pill:active { transform: scale(0.96); }
.checkbox { width: 22px; height: 22px; border-radius: 7px; border: 2px solid var(--border-default); background: transparent; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 13px; flex-shrink: 0; cursor: pointer; }
.checkbox.checked { border-color: var(--brand-primary); background: var(--brand-primary); }
.checkbox-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-top: 1px solid var(--border-subtle); cursor: pointer; }
.checkbox-row:first-child { border-top: none; }
/* font-size 16px sur les deux (au lieu de 12/12.5px) : même raison que
   .text-input, ce sont aussi des champs natifs qu'on touche directement
   (Safari iOS zoome la page en dessous de ce seuil). Largeur de
   .child-percent-input élargie en conséquence pour garder 2-3 chiffres
   lisibles sans les tronquer. */
.participant-select { font-size: 16px; border-radius: 10px; border: 1px solid var(--border-default); background: var(--surface-canvas); padding: 6px 8px; font-family: 'Manrope', sans-serif; color: var(--text-primary); }
.child-percent-input { width: 56px; text-align: center; padding: 6px 4px; border-radius: 8px; border: 1px solid var(--border-default); background: var(--surface-canvas); color: var(--text-primary); font-size: 16px; font-family: 'Manrope', sans-serif; }
.switch-user-row { display: flex; align-items: center; gap: 12px; padding: 11px 8px; border-radius: 14px; cursor: pointer; background: transparent; border: none; width: 100%; text-align: left; }
.switch-user-row:active { background: var(--surface-overlay); }
.modal-footer-buttons { display: flex; gap: 10px; }
.btn-cancel { flex: 1; text-align: center; padding: 12px; background: transparent; border: 1px solid var(--border-default); color: var(--text-primary); border-radius: 14px; font-weight: 700; font-size: 14px; cursor: pointer; }
.btn-confirm { flex: 1; text-align: center; padding: 12px; background: var(--brand-primary); color: #fff; border-radius: 14px; font-weight: 700; font-size: 14px; cursor: pointer; border: none; }
@media (hover: hover) { .btn-confirm:hover { background: var(--brand-primary-hover); } }
.delete-link { text-align: center; color: var(--status-danger); font-size: 13.5px; font-weight: 700; margin-top: 14px; cursor: pointer; background: none; border: none; width: 100%; padding: 0; }

/* --- Toast --- */
.toast { position: absolute; bottom: 78px; left: 20px; right: 20px; background: var(--surface-overlay); color: var(--text-primary); padding: 13px 16px; border-radius: 14px; font-size: 13.5px; font-weight: 600; text-align: center; animation: popIn .22s cubic-bezier(.3, .7, .4, 1); box-shadow: 0 20px 60px rgba(0, 0, 0, .5); z-index: 20; }

/* utility */
.hidden { display: none !important; }

/* Réglage d'accessibilité au niveau de l'OS (iOS/Android/macOS/Windows) —
   raccourcit toute animation/transition CSS à une durée quasi nulle plutôt
   que de la désactiver élément par élément (l'écran de lancement, les
   fondus/glissements de modales, l'effet d'appui des boutons...). Les
   confettis (JS, cf. celebrateSettlement) suivent déjà ce réglage de leur
   côté via l'option disableForReducedMotion de la librairie. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
