/* ──────────────────────────────────────────────────────────────────────────
   Kredy — feuille de style principale
   Les valeurs viennent du design validé (aiDocs/design_handoff_kredy_mvp).
   ────────────────────────────────────────────────────────────────────────── */

/* ─── Polices ─────────────────────────────────────────────────────────────
   Auto-hébergées : un lien vers Google Fonts casserait l'affichage hors
   connexion, précisément le scénario que le produit doit couvrir.
   Sous-ensemble latin uniquement — le français et le wolof n'ont pas besoin
   de latin-ext, ce qui économise 90 ko sur une connexion 3G.              */
@font-face {
    font-family: 'Bricolage Grotesque';
    src: url("../fonts/bricolage-grotesque-latin-k0HXNf5.woff2") format('woff2');
    font-weight: 400 800;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
        U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Source Sans 3';
    src: url("../fonts/source-sans-3-latin-8PKsh_E.woff2") format('woff2');
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
        U+FEFF, U+FFFD;
}

/* ─── Jetons de couleur ───────────────────────────────────────────────────
   Les hex sont le rendu sRGB des valeurs oklch du design, pour les WebView
   Android anciennes ; les navigateurs récents reçoivent l'oklch exact.    */
:root {
    --ink: #140B05;
    --cream: #FCF4EB;
    --surface: #FFFBF7;
    --amber: #A63C00;
    --amber-brand: #D55C13;
    --olive: #5C6C14;
    --olive-text: #354000;
    --olive-light: #C4E4A5;
    --error: #BE222A;
    --border: #E3DDD8;
    --field: #DDD6D1;
    --field-line: #D3CCC7;
    --skeleton: #EAE3DE;
    --text-2: #5E534A;
    --text-3: #6C6158;
    --tab-off: #84786F;
    --chip-on-ink: #30271F;
    --nav-active-bg: #302017;
    --nav-active-text: #FFA659;
    --on-ink-2: #B8ABA2;
    --on-ink-3: #A89C92;
    --on-ink-strong: #F0EAE4;
    --on-ink-4: #AEA298;
    --on-ink-chip: #D5CBC3;
    --nav-inactive: #C1B5AB;
    --field-strong: #C9C3BE;
    --placeholder: #84786F;
    --amber-wash: rgb(166 60 0 / 12%);
    --olive-bright: #7E903E;
    --on-ink-label: #998D83;
    --nav-outline: #443428;
    --ink-raised: #241B13;
    --rail: #EDE7DF;
    --chip: #F0EAE4;
    --chip-text: #362C24;
    --handle: #D6D0CB;
    --swipe-edit: #564B42;
    --rowact-ink: #4B4038;
    --rowact-danger-bg: #FCEAE8;
    --rowact-danger-line: #E2AFAA;
    --veil: rgb(20 11 5 / 45%);
    --olive-soft: rgb(92 108 20 / 14%);
    --olive-line: rgb(92 108 20 / 28%);
    --olive-wash: rgb(92 108 20 / 10%);
    --amber-soft: #F6E7D8;
    --amber-line: #E7D2C2;
    --install-bg: #F8ECE1;
    --install-line: #E9CFBB;
    --on-ink-late: #E9C6A6;
    --on-ink-action: #FFBB65;
    --limit-rail: #362C24;
    --limit-ok: #89B559;
    --limit-near: #DEA132;
    --limit-near-text: #FCD180;
    --limit-over-text: #FFB589;
    --limit-text: #842B02;
    --limit-wash: rgb(213 92 19 / 10%);
    --limit-line: rgb(213 92 19 / 30%);

    --font-display: 'Bricolage Grotesque', 'Trebuchet MS', sans-serif;
    --font-body: 'Source Sans 3', 'Segoe UI', system-ui, sans-serif;
}

@supports (color: oklch(0.5 0.1 60)) {
    :root {
        --ink: oklch(0.16 0.02 60);
        --cream: oklch(0.97 0.015 70);
        --surface: oklch(0.99 0.008 70);
        --amber: oklch(0.50 0.17 42);
        --amber-brand: oklch(0.62 0.17 45);
        --olive: oklch(0.50 0.11 120);
        --olive-text: oklch(0.35 0.10 120);
        --olive-light: oklch(0.88 0.09 130);
        --error: oklch(0.52 0.19 25);
        --border: oklch(0.90 0.01 60);
        --field: oklch(0.88 0.01 60);
        --field-line: oklch(0.85 0.01 60);
        --skeleton: oklch(0.92 0.01 60);
        --text-2: oklch(0.45 0.02 60);
        --text-3: oklch(0.50 0.02 60);
        --tab-off: oklch(0.58 0.02 60);
        --chip-on-ink: oklch(0.28 0.02 60);
        --nav-active-bg: oklch(0.26 0.03 50);
        --nav-active-text: oklch(0.80 0.14 60);
        --on-ink-2: oklch(0.75 0.02 60);
        --on-ink-3: oklch(0.70 0.02 60);
        --on-ink-strong: oklch(0.94 0.01 70);
        --on-ink-4: oklch(0.72 0.02 60);
        --on-ink-chip: oklch(0.85 0.01 60);
        --nav-inactive: oklch(0.78 0.02 60);
        --field-strong: oklch(0.82 0.01 60);
        --placeholder: oklch(0.58 0.02 60);
        --amber-wash: oklch(0.50 0.17 42 / 12%);
        --olive-bright: oklch(0.62 0.11 120);
        --on-ink-label: oklch(0.65 0.02 60);
        --nav-outline: oklch(0.34 0.03 60);
        --ink-raised: oklch(0.23 0.02 60);
        --rail: oklch(0.93 0.012 70);
        --chip: oklch(0.94 0.01 70);
        --chip-text: oklch(0.30 0.02 60);
        --handle: oklch(0.86 0.01 60);
        --swipe-edit: oklch(0.42 0.02 60);
        --rowact-ink: oklch(0.38 0.02 60);
        --rowact-danger-bg: oklch(0.95 0.02 25);
        --rowact-danger-line: oklch(0.80 0.06 25);
        --veil: oklch(0.16 0.02 60 / 45%);
        --olive-soft: oklch(0.50 0.11 120 / 14%);
        --olive-line: oklch(0.50 0.11 120 / 28%);
        --olive-wash: oklch(0.50 0.11 120 / 10%);
        --amber-soft: oklch(0.94 0.02 65);
        --amber-line: oklch(0.88 0.03 55);
        --install-bg: oklch(0.95 0.02 68);
        --install-line: oklch(0.87 0.04 60);
        --limit-rail: oklch(0.30 0.02 60);
        --limit-ok: oklch(0.72 0.13 130);
        --limit-near: oklch(0.75 0.14 78);
        --limit-near-text: oklch(0.88 0.11 82);
        --limit-over-text: oklch(0.84 0.11 50);
        --limit-text: oklch(0.42 0.13 40);
        --limit-wash: oklch(0.62 0.17 45 / 10%);
        --limit-line: oklch(0.62 0.17 45 / 30%);
        --on-ink-late: oklch(0.86 0.06 60);
        --on-ink-action: oklch(0.84 0.13 70);
    }
}

/* ─── Base ────────────────────────────────────────────────────────────────*/
*,
*::before,
*::after {
    box-sizing: border-box;
}

html,
body {
    height: 100%;
}

/* Passer d'un onglet à l'autre est un vrai chargement de page. Sans fond sur
   `html`, le navigateur peint sa toile blanche entre l'ancien document et le
   premier rendu du suivant : sur mobile, cela se voit comme un clignotement à
   chaque changement d'écran. `color-scheme` dit au navigateur de ne pas non
   plus assombrir cette toile quand le téléphone est en thème sombre — Kredy
   n'a qu'un thème. */
html {
    background: var(--cream);
    color-scheme: light;
}

/* Turbo affiche une barre de progression au-delà d'une demi-seconde d'attente.
   Servis depuis le cache du service worker, les écrans arrivent bien avant :
   elle ne se voit que sur une vraie attente — et ce jour-là, elle doit être de
   la maison plutôt que du bleu par défaut de Turbo. */
.turbo-progress-bar {
    height: 3px;
    background: var(--amber-brand);
}

/* Sans cela, `display: flex` l'emporterait sur l'attribut `hidden` et le voile
   resterait visible. */
[hidden] {
    display: none !important;
}

body {
    margin: 0;
    background: var(--cream);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: 15px;
    line-height: 1.45;
    -webkit-text-size-adjust: 100%;
}

input,
select,
button,
textarea,
a {
    font-family: inherit;
}

a {
    color: var(--amber);
}

@keyframes fadeUp {
    from {
        opacity: 0;
        transform: translateY(10px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

@keyframes pulse {
    0%,
    100% {
        opacity: 1;
    }

    50% {
        opacity: 0.35;
    }
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* ─── Écrans d'authentification ───────────────────────────────────────────*/
.auth {
    min-height: 100%;
    display: flex;
    justify-content: center;
    align-items: stretch;
}

.auth__col {
    width: 100%;
    display: flex;
    flex-direction: column;
    padding: 32px 24px;
    animation: fadeUp 0.35s ease both;
}

.auth__logo {
    width: 56px;
    height: 56px;
    border-radius: 15px;
    margin-bottom: 24px;
}

.auth__back {
    font-size: 14.5px;
    color: var(--text-2);
    margin-bottom: 22px;
    text-decoration: none;
    align-self: flex-start;
    padding: 4px 0;
}

.auth__title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 30px;
    line-height: 1.05;
    letter-spacing: -0.035em;
    color: var(--ink);
    margin: 0 0 8px;
}

.auth__subtitle {
    font-size: 15px;
    color: var(--text-2);
    margin: 0 0 28px;
}

.auth__title--alone {
    margin-bottom: 28px;
}

.auth__spacer {
    flex: 1;
    min-height: 24px;
}

.auth__link {
    font-size: 14px;
    color: var(--amber);
    font-weight: 700;
    margin-top: 14px;
    text-decoration: none;
    align-self: flex-start;
}

.auth__note {
    font-size: 14.5px;
    color: var(--text-2);
    margin: 0 0 14px;
}

/* ─── Champs ──────────────────────────────────────────────────────────────*/
.field {
    display: flex;
    flex-direction: column;
    margin-bottom: 22px;
}

.field:last-of-type {
    margin-bottom: 10px;
}

.field__label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-2);
    margin-bottom: 7px;
}

.field__input {
    border: none;
    border-bottom: 2px solid var(--field-line);
    background: none;
    padding: 12px 2px;
    font-size: 17px;
    color: var(--ink);
    border-radius: 0;
    outline: none;
    width: 100%;
}

.field__input:focus {
    border-bottom-color: var(--amber);
}

.field__input--code {
    font-size: 20px;
    letter-spacing: 10px;
}

.field__error,
.form-error {
    color: var(--error);
    font-size: 13.5px;
    margin: 0 0 8px;
}

/* La phrase sous un champ : ce que la valeur va servir à faire, ou pourquoi
   elle ne se change pas ici. */
.field__hint {
    margin: 8px 0 0;
    font-size: 13px;
    color: var(--text-3);
}

/* Le plafond de crédit : un champ encadré, et non souligné comme les deux qui
   le précèdent. C'est le design qui le distingue ainsi — il est facultatif, et
   il porte une unité que le nom et le téléphone n'ont pas. */
.limit {
    display: flex;
    align-items: center;
    gap: 10px;
    border: 1px solid var(--field);
    border-radius: 14px;
    background: var(--surface);
    padding: 0 15px;
}

.limit__input {
    flex: 1;
    min-width: 0;
    border: none;
    background: none;
    padding: 14px 0;
    font-family: inherit;
    font-size: 15.5px;
    color: var(--ink);
    outline: none;
}

.limit__currency {
    flex: none;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-3);
}

/* Le téléphone du Profil : affiché, jamais saisissable. Il garde l'aplomb des
   autres champs pour qu'on voie que c'est une valeur, pas un oubli. */
.field__fixed {
    margin: 0;
    padding: 12px 2px;
    font-size: 17px;
    color: var(--text-2);
    border-bottom: 2px solid var(--field-line);
}

/* Les deux écrans de compte : mêmes champs que l'authentification, dans la
   coquille de l'application. Les boutons se suivent, le second est un retour —
   même écart qu'entre les gestes du Profil, l'application n'a qu'un rythme. */
.profile__form {
    display: flex;
    flex-direction: column;
    max-width: 26rem;
}

.profile__form .btn {
    margin-top: 18px;
}

/* La phrase qui précède les boutons n'est pas un champ : sans cette marge, elle
   se collerait au premier d'entre eux. */
.profile__form .field__hint {
    margin-bottom: 8px;
}

/* Les gestes de compte du Profil. Ils s'empilent, largement espacés : chacun
   mène ailleurs, et le dernier de la pile est une déconnexion — un doigt qui
   vise « Changer mon code » ne doit pas tomber dessus. */
.profile__links {
    display: flex;
    flex-direction: column;
    gap: 18px;
    margin-bottom: 28px;
}

/* ─── Boutons ─────────────────────────────────────────────────────────────*/
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    border: none;
    font-weight: 700;
    font-size: 16px;
    border-radius: 14px;
    padding: 17px;
    cursor: pointer;
    transition: transform 0.1s;
    text-decoration: none;
    width: 100%;
}

.btn:active {
    transform: scale(0.98);
}

.btn--primary {
    background: var(--amber);
    color: #FFF;
}

.btn--ink {
    background: var(--ink);
    color: var(--cream);
}

.btn--outline {
    background: none;
    border: 1.5px solid var(--field-line);
    color: var(--error);
}

/* ─── Écran de bienvenue ──────────────────────────────────────────────────*/
.welcome {
    min-height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 32px;
    text-align: center;
    background: var(--ink);
    animation: fadeUp 0.3s ease both;
}

.welcome__mark {
    width: 72px;
    height: 72px;
    margin-bottom: 22px;
}

.welcome__title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 26px;
    letter-spacing: -0.03em;
    color: var(--cream);
    margin: 0 0 8px;
}

.welcome__subtitle {
    font-size: 15px;
    color: var(--on-ink-2);
    margin: 0;
}

/* ─── Bascule desktop ─────────────────────────────────────────────────────*/
@media (min-width: 900px) {
    .auth__col {
        max-width: 440px;
        padding: 56px 32px;
    }
}

/* ─── Coquille applicative ────────────────────────────────────────────────*/
.shell {
    min-height: 100%;
    display: flex;
    flex-direction: column;
}

.shell__main {
    flex: 1;
    min-width: 0;
}

.page {
    padding: 20px 20px 28px;
    animation: fadeUp 0.3s ease both;
}

.page__header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
}

.page__title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 26px;
    letter-spacing: -0.03em;
    margin: 0;
}

.page__count {
    font-size: 13px;
    color: var(--text-3);
}

/* ─── Navigation ──────────────────────────────────────────────────────────*/
.nav {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 20;
    background: var(--surface);
    border-top: 1px solid var(--border);
    padding: 10px 20px 14px;
}

.nav__brand {
    display: none;
}

.nav__list {
    display: flex;
    justify-content: space-between;
    align-items: center;
    list-style: none;
    margin: 0;
    padding: 0;
}

.nav__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    min-width: 48px;
    min-height: 48px;
    justify-content: center;
    text-decoration: none;
    color: var(--tab-off);
}

.nav__item.is-active {
    color: var(--amber);
}

.nav__icon svg {
    width: 22px;
    height: 22px;
    display: block;
}

.nav__label {
    font-size: 10.5px;
    font-weight: 700;
}

/* La barre basse est fixe : le contenu doit pouvoir défiler au-dessus. */
.shell__main {
    padding-bottom: 84px;
}

/* ─── Recherche et ajout ──────────────────────────────────────────────────*/
.search {
    display: flex;
    gap: 10px;
    margin-bottom: 18px;
}

.search__input {
    flex: 1;
    min-width: 0;
    background: var(--surface);
    border: 1px solid var(--field);
    border-radius: 14px;
    padding: 13px 15px;
    font-size: 14.5px;
    color: var(--ink);
    outline: none;
}

.search__input:focus {
    border-color: var(--amber);
}

.search__add {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-width: 48px;
    padding: 0 14px;
    background: var(--ink);
    color: var(--cream);
    border-radius: 14px;
    font-weight: 700;
    font-size: 18px;
    text-decoration: none;
}

.search__add-label {
    display: none;
    font-size: 14.5px;
}

/* ─── Liste des clients ───────────────────────────────────────────────────*/
.clients {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Le filet est sur la ligne, pas sur le lien : le lien vit dans la couche
   avant du glissement, qui se déplace — il emporterait la séparation avec lui,
   et la couche révélée la recouvrirait de toute façon. Même partage que sur une
   ligne d'opération. */
.clientrow {
    border-bottom: 1px solid var(--border);
}

.client {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 0;
    text-decoration: none;
    color: inherit;
}

.client__avatar {
    flex: none;
    width: 42px;
    height: 42px;
    border-radius: 50%;
    background: var(--ink);
    color: var(--cream);
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 15px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.client__identity {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

/* Le nom et son point de plafond : le nom prend la place qu'il peut, le point
   ne se coupe jamais — c'est le seul signal de l'écran, il ne s'élide pas. */
.client__title {
    display: flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
}

.client__name {
    font-size: 15px;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* L'état **atteint**, jamais la tendance : orange, la couleur des crédits, et
   jamais le rouge d'une alerte — le plafond informe, il n'accuse pas. */
.client__dot {
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--amber-brand);
}

.client__sub {
    font-size: 12.5px;
    color: var(--text-2);
}

/* ─── États vides ─────────────────────────────────────────────────────────*/
.empty {
    padding: 36px 0;
    text-align: center;
}

.empty__title {
    font-size: 16px;
    font-weight: 600;
    margin: 0 0 6px;
}

.empty__text {
    font-size: 14.5px;
    color: var(--text-2);
    margin: 0 0 18px;
}

/* ─── Fiche client ────────────────────────────────────────────────────────*/
.detail__head {
    background: var(--ink);
    padding: 18px 20px 26px;
    animation: fadeUp 0.3s ease both;
}

/* Le retour et l'édition se partagent la première ligne, chacun à son bord. */
.detail__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 18px;
}

/* Une pastille pleine, pas un texte gris : sur un écran d'entrée de gamme en
   plein soleil, seul le contraste d'un fond se voit encore. */
.detail__back {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 40px;
    padding: 0 15px 0 11px;
    border: 1px solid var(--nav-outline);
    border-radius: 20px;
    background: var(--ink-raised);
    font-size: 14px;
    font-weight: 700;
    color: var(--on-ink-strong);
    text-decoration: none;
}

.detail__back:active {
    transform: scale(0.97);
}

/* Un bouton, pas un lien : il ouvre une feuille, il ne mène nulle part.

   Seul geste de l'en-tête depuis que le « ⋯ » a disparu, et porté à 44 px : il
   n'a plus de voisin avec qui partager la place, et c'est la hauteur de cible
   que le design demande partout ailleurs. */
.detail__edit {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 44px;
    padding: 0 10px;
    border: none;
    border-radius: 22px;
    background: none;
    font-size: 14px;
    font-weight: 700;
    color: var(--nav-active-text);
    cursor: pointer;
}

.detail__edit:hover {
    background: var(--ink-raised);
}

/* Le libellé s'efface sur les très petits écrans, et le crayon suffit. La
   raison d'origine — ne pas renvoyer le « ⋯ » à la ligne suivante — a disparu
   avec lui ; la contrainte de largeur, non. */
@media (max-width: 339px) {
    .detail__edit-label {
        display: none;
    }
}

/* Le retrait d'une fiche vit en bas de l'écran, après l'historique : un geste
   irréversible ne se croise pas en venant lire un solde. Pleine largeur et
   44 px au moins, comme toute cible qui n'est pas une pastille. */
.detail__remove {
    display: flex;
    align-items: center;
    gap: 9px;
    width: 100%;
    min-height: 44px;
    margin-top: 28px;
    padding: 15px 2px;
    border: none;
    border-top: 1px solid var(--border);
    background: none;
    color: var(--error);
    font-family: inherit;
    font-size: 14.5px;
    font-weight: 700;
    text-align: left;
    cursor: pointer;
}

.detail__remove svg {
    flex: none;
    width: 18px;
    height: 18px;
}

.detail__name {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 26px;
    letter-spacing: -0.03em;
    color: var(--cream);
    margin: 0;
}

.detail__phone {
    font-size: 13.5px;
    color: var(--on-ink-4);
    margin: 2px 0 0;
}

.detail__body {
    padding: 18px 20px 28px;
}

/* ─── Feuilles et formulaires de page ─────────────────────────────────────*/
.sheet__form {
    display: flex;
    flex-direction: column;
}

.sheet__actions {
    display: flex;
    gap: 10px;
    margin-top: 8px;
}

/* La feuille de saisie s'allonge avec le forfait et le profil grossiste : ses
   boutons restent sous le pouce, clavier ouvert. L'ombre pleine couvre le
   rembourrage du bas, que le défilement laisserait sinon voir sous eux. */
.sheet--entry .sheet__actions {
    position: sticky;
    bottom: 0;
    padding-top: 12px;
    background: var(--surface);
    box-shadow: 0 28px 0 var(--surface);
}

.btn--ghost {
    background: none;
    border: 1.5px solid var(--field-strong);
    color: var(--ink);
    flex: 1;
}

.btn--wide {
    flex: 2;
}

/* ─── Dialogue de confirmation ────────────────────────────────────────────*/
/* Un seul composant pour les trois questions de l'itération 3 : retirer une
   opération, retirer un client, dépasser un plafond.

   `z-index: 55` : au-dessus de la feuille de saisie (40) et de la page de choix
   du client (50), sous le toast (60). Le handoff nomme 20 / 26 / 28 sur
   l'échelle du prototype ; ce qui compte est l'ordre, et c'est celui-là.
   Le toast reste au-dessus, et c'est voulu — « Crédit supprimé. » s'affiche
   alors que la feuille de saisie peut encore être ouverte derrière.

   Centré dans les deux modes, jamais en bas : ce n'est pas une feuille, et un
   dialogue destructeur ne doit pas surgir là où le pouce vient d'appuyer. */
.confirm {
    position: fixed;
    inset: 0;
    z-index: 55;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: var(--veil);
    animation: veil 0.18s ease both;
}

.confirm__panel {
    width: 100%;
    max-width: 380px;
    background: var(--surface);
    border-radius: 22px;
    padding: 24px;
    box-shadow: 0 20px 50px rgb(20 11 5 / 35%);
    animation: fadeUp 0.22s ease both;
}

.confirm__title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 21px;
    letter-spacing: -0.03em;
    margin: 0 0 9px;
}

.confirm__body {
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--text-2);
    margin: 0 0 22px;
}

.confirm__actions {
    display: flex;
    gap: 10px;
}

/* Rouge pour ce qui disparaît, orange pour un plafond dépassé — jamais rouge
   pour le second : le plafond informe, il n'accuse pas, et le handoff en fait
   une règle transverse. */
.confirm__actions .btn--confirm {
    background: var(--error);
    color: #FFF;
    border: none;
}

.confirm[data-tone="limit"] .btn--confirm {
    background: var(--amber);
}

/* Un constat n'accuse personne et ne détruit rien : il n'a qu'un bouton, et ce
   bouton est celui de l'encre. Le rouge dirait « attention », alors qu'il n'y a
   plus rien à décider — le geste a déjà été refusé. */
.confirm[data-tone="neutral"] .btn--confirm {
    background: var(--ink);
    color: var(--cream);
}

/* ─── Toast ───────────────────────────────────────────────────────────────*/
/* Au-dessus de tout, voile et page de choix compris : depuis que créer un
   client se fait sans quitter la feuille, un toast peut s'afficher alors qu'une
   superposition est encore ouverte — « Awa est dans votre cahier. » n'a aucun
   intérêt si elle passe derrière le voile. */
.toast {
    position: fixed;
    left: 16px;
    right: 16px;
    bottom: 96px;
    z-index: 60;
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--ink);
    color: var(--cream);
    font-size: 14px;
    border-radius: 16px;
    padding: 14px 16px;
    margin: 0;
    box-shadow: 0 10px 24px rgb(20 11 5 / 35%);
    animation: fadeUp 0.3s ease both;
}

/* Le texte prend la place qui reste : l'action, quand il y en a une, garde la
   sienne à droite et ne se laisse pas pousser hors de l'écran. */
.toast__text {
    flex: 1;
    min-width: 0;
}

/* L'action d'un toast est du **texte**, pas un bouton plein : le seul bouton
   plein de cette surface est celui du bandeau de mise à jour, qui porte une
   décision et ne disparaît pas seul. Les deux partagent leur mise en place et
   se séparent sur l'apparence, juste en dessous. */
.toast__action {
    flex: none;
    background: none;
    border: none;
    color: var(--on-ink-action);
    font-family: inherit;
    font-size: 14px;
    font-weight: 700;
    padding: 4px 2px 4px 12px;
    cursor: pointer;
}

/* La barre colorée dit la nature de ce qui vient d'être noté sans un mot de plus. */
.toast__bar {
    flex: none;
    width: 4px;
    height: 26px;
    border-radius: 2px;
    background: var(--amber-brand);
}

.toast--payment .toast__bar {
    background: var(--olive-bright);
}

/* ─── Solde dans la liste des clients ─────────────────────────────────────*/
.client__amount {
    flex: none;
    text-align: right;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
}

.client__value {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 17px;
    letter-spacing: -0.02em;
}

.client__currency {
    font-size: 11px;
    color: var(--text-3);
}

/* Un solde à zéro se lit d'un coup d'œil : c'est la bonne nouvelle de l'écran. */
.client__amount--clear .client__value {
    color: var(--olive-text);
}

/* ─── Bandeau de la fiche client ──────────────────────────────────────────*/
/* Le montant, sa devise et son libellé sur une seule ligne. La marge haute est
   portée ici plutôt que par le téléphone : la fiche d'un client sans numéro
   n'affiche pas de téléphone, et le chiffre se retrouverait collé au nom. */
.detail__amount {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 38px;
    line-height: 1;
    letter-spacing: -0.04em;
    color: var(--cream);
    margin: 20px 0 0;
}

.detail__currency {
    font-size: 15px;
    font-weight: 600;
    letter-spacing: 0;
    color: var(--amber-brand);
}

/* Poussé au bord droit : « Reste à payer », ou « Solde à jour » à zéro. */
.detail__label {
    margin-left: auto;
    font-family: var(--font-body);
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--on-ink-3);
    white-space: nowrap;
}

/* Les deux cumuls aux deux bords : ce qui a été prêté à gauche, ce qui est
   revenu à droite, et l'œil n'a qu'une colonne à suivre pour chacun. */
.sums {
    display: flex;
    justify-content: space-between;
    gap: 22px;
    margin: 20px 0 0;
    padding-top: 16px;
    border-top: 1px solid var(--chip-on-ink);
}

.sums__item:last-child {
    text-align: right;
}

.sums__label {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--on-ink-label);
    margin-bottom: 4px;
}

.sums__value {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 17px;
    color: var(--on-ink-strong);
    margin: 0;
}

.sums__value--paid {
    color: var(--olive-light);
}

/* ─── Corps de la fiche client ────────────────────────────────────────────*/
.detail__actions {
    display: flex;
    gap: 10px;
    margin-bottom: 10px;
}

.detail__actions .btn {
    font-size: 15px;
    padding: 15px;
    white-space: nowrap;
}

/* La barre basse disparaît de la fiche client — en mobile seulement : la barre
   latérale du desktop reste le fil qui ramène au reste de l'application. */
.shell--bare .nav {
    display: none;
}

.shell--bare .shell__main {
    padding-bottom: 0;
}

.section__label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-2);
    margin: 0 0 4px;
}

/* ─── Glissement d'une ligne ──────────────────────────────────────────────*/
/* Une seule définition, pour ses deux usages : la ligne d'opération, qui
   révèle Modifier et Supprimer, et la carte client, qui ne révèle que
   Supprimer. Un modificateur porte la seule différence — la largeur. Ne pas en
   redéfinir un troisième : c'est la règle du contrôle segmenté, pour la même
   raison, deux gestes qui se ressemblent doivent se ressembler tout à fait.

   La largeur vit ici et **seulement** ici : le contrôleur la mesure sur la
   couche révélée plutôt que de la recopier, et les 42 % du verrouillage s'en
   déduisent. */
.swipe {
    position: relative;
    overflow: hidden;
}

/* Toujours dessous, jamais masquée : les deux boutons sont de vrais boutons,
   atteignables au clavier et annoncés par un lecteur d'écran. Le focus sur
   l'un d'eux ouvre la ligne — c'est le contrôleur qui s'en charge. */
.swipe__reveal {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    display: flex;
    width: 178px;
}

.swipe--client .swipe__reveal {
    width: 104px;
}

/* Opaque, sinon la couche révélée transparaît au repos. `pan-y` laisse le
   défilement de liste prioritaire tant que le mouvement est vertical, et
   `user-select` évite qu'un glissement à la souris ne sélectionne la ligne. */
.swipe__front {
    position: relative;
    display: flex;
    align-items: center;
    background: var(--cream);
    touch-action: pan-y;
    user-select: none;
    transition: transform 190ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* Aucune transition pendant que le doigt est posé : la ligne le suit au
   pixel. */
.swipe__front.is-sliding {
    transition: none;
}

/* L'action destructrice est toujours la plus extérieure : un demi-geste ne
   peut pas atteindre Supprimer. La hauteur est celle de la ligne, donc
   toujours au-delà des 44 px de cible minimale. */
.swipe__act {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 0;
    border: none;
    background: var(--swipe-edit);
    color: #FFF;
    font-family: inherit;
    font-size: 11.5px;
    font-weight: 800;
    cursor: pointer;
}

.swipe__act--danger {
    background: var(--error);
}

/* Les deux icônes partagées ne font pas la même taille — 16 px le crayon,
   19 px la corbeille — et côte à côte, à 89 px l'une de l'autre, l'écart se
   voit. Le handoff les veut à 17 px toutes les deux. */
.swipe__act svg {
    width: 17px;
    height: 17px;
}

/* La poignée : elle signale la prise, elle ne l'est pas — d'où
   `pointer-events: none`. Trois traits, jamais trois points empilés, qui
   redonneraient l'apparence du menu « ⋯ » que ce geste remplace. */
.swipe__grip {
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 3px;
    padding-left: 6px;
    pointer-events: none;
}

.swipe__grip i {
    width: 10px;
    height: 1.5px;
    border-radius: 1px;
    background: var(--handle);
}

/* ─── Actions de ligne à la souris ────────────────────────────────────────*/
/* Le glissement est un geste ; ceci n'en est pas un. À la souris la ligne ne
   bouge pas : ses gestes sont là, au bord droit, discrets tant qu'on ne la
   survole pas.

   Les deux présentations ne coexistent **jamais**, et rien ici ne pose la
   question : `data-pointer` est posé sur `<html>` par la coquille, une fois,
   depuis la seule requête média du projet. Une seconde ici en ferait deux à
   tenir d'accord.

   Les boutons sont toujours dans le flux, jamais créés au survol : apparaître
   pousserait le montant de 76 px à chaque ligne survolée, et la liste
   tressauterait sous la souris. Seule l'opacité change. */
.rowacts {
    display: none;
    flex: none;
    align-items: center;
    gap: 6px;
    margin-left: 10px;
    opacity: 0.3;
    transition: opacity 140ms ease;
}

[data-pointer="fine"] .rowacts {
    display: flex;
}

/* Le survol se lit sur la **ligne**, pas sur le bouton : viser un carré de
   30 px pour faire apparaître ce qu'on vise n'aurait aucun sens. Le focus les
   allume aussi — c'est la voie du clavier, celle que la couche révélée sert au
   doigt. */
.swipe__front:hover .rowacts,
.rowacts:focus-within {
    opacity: 1;
}

.rowacts__btn {
    flex: none;
    width: 30px;
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid var(--field);
    border-radius: 9px;
    background: #FFF;
    color: var(--rowact-ink);
    cursor: pointer;
}

/* Les deux icônes partagées ne font pas la même taille — 16 px le crayon,
   19 px la corbeille — et il faut les ramener à la même, ici 15 px, comme la
   couche révélée les ramène à 17. */
.rowacts__btn svg {
    width: 15px;
    height: 15px;
}

/* Le handoff demande oklch(0.94 0.01 60) ; `--chip` vaut oklch(0.94 0.01 70),
   un degré de teinte plus loin et rigoureusement invisible. Un jeton de plus
   pour cet écart-là serait le vrai coût. */
.rowacts__btn:hover {
    background: var(--chip);
}

/* Le rouge ne sert qu'à ce bouton-là, et il ne s'allume qu'au survol : au
   repos, deux boutons de couleurs différentes au bout de chaque ligne feraient
   du journal une alerte. */
.rowacts__btn--danger {
    color: var(--error);
}

.rowacts__btn--danger:hover {
    background: var(--rowact-danger-bg);
    border-color: var(--rowact-danger-line);
}

/* Ce que la souris fait disparaître.

   La poignée annoncerait un geste qui n'existe pas ; le chevron de l'indice
   montrerait un sens de glissement qui n'existe pas davantage. La couche
   révélée, elle, part pour une raison de plus : ses boutons sont de vrais
   boutons, et les laisser sous une ligne qui ne s'ouvre plus mettrait deux
   arrêts de tabulation morts par ligne — exactement ce que le v4 refusait déjà
   sur l'accueil. `display: none` et non `visibility` : c'est la sortie du
   tabulateur qui compte. */
[data-pointer="fine"] .swipe__grip,
[data-pointer="fine"] .swipe__reveal,
[data-pointer="fine"] .swipehint svg {
    display: none;
}

/* Les deux phrases de l'indice sont rendues, une seule s'affiche. Le défaut
   est le doigt : si l'attribut manquait, c'est le geste tactile qui reste
   annoncé, et il marche partout. */
[data-when-pointer="fine"] {
    display: none;
}

[data-pointer="fine"] [data-when-pointer="fine"] {
    display: inline;
}

[data-pointer="fine"] [data-when-pointer="coarse"] {
    display: none;
}

/* L'indice en tête de liste. Il reste affiché en permanence : le geste est
   invisible par nature, le cahier s'ouvre quelques fois par jour, et un indice
   qui s'efface se paie en appels au support. */
.swipehint {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 0 8px;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--tab-off);
}

/* 14 px, contre les 17 px que le chevron sert ailleurs : c'est une marque
   discrète en tête de liste, pas un bouton de retour. */
.swipehint svg {
    flex: none;
    width: 14px;
    height: 14px;
}

/* ─── Lignes d'historique ─────────────────────────────────────────────────*/
.history {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Le rang porte sa bordure, et le mécanisme de glissement porte son
   `overflow: hidden` : les deux ne peuvent pas vivre au même endroit, sinon la
   couche révélée recouvrirait le filet qui sépare deux lignes.

   Sous la ligne, et hors de la couche avant, le retrait d'une écriture
   refusée : il ne glisse pas avec elle. */
.entry {
    border-bottom: 1px solid var(--border);
}

/* Toute la ligne est cliquable là où elle mène quelque part : une cible de la
   largeur de l'écran vaut mieux qu'un nom de 80 px à viser au pouce. Là où elle
   ne mène nulle part — l'historique d'une fiche — le tap ouvre la correction,
   et c'est le contrôleur de glissement qui s'en charge. */
.entry__link {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 14px 0;
    color: inherit;
    text-decoration: none;
}

.entry__bar {
    flex: none;
    width: 5px;
    height: 34px;
    border-radius: 3px;
    background: var(--ink);
}

.entry__identity {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.entry__kind {
    font-size: 14.5px;
    font-weight: 600;
}

.entry__sub {
    font-size: 13px;
    color: var(--text-3);
}

.entry__amount {
    flex: none;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 16px;
    letter-spacing: -0.02em;
}

.entry--payment .entry__bar {
    background: var(--olive-text);
}

.entry--payment .entry__amount {
    color: var(--olive-text);
}

/* ─── Bouton « Noter » et actions de la barre ─────────────────────────────*/
.nav__note {
    width: 56px;
}

.fab {
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    color: var(--ink);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    transform: translateY(-16px);
}

.fab__disc {
    width: 54px;
    height: 54px;
    border-radius: 50%;
    background: var(--amber);
    color: #FFF;
    font-size: 26px;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 8px 18px rgb(166 60 0 / 42%);
}

.fab:active .fab__disc {
    transform: scale(0.96);
}

.nav__actions {
    display: none;
}

/* ─── Voile et feuilles ───────────────────────────────────────────────────*/
@keyframes sheetUp {
    from {
        transform: translateY(100%);
    }

    to {
        transform: none;
    }
}

@keyframes veil {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

@keyframes modalIn {
    from {
        opacity: 0;
        transform: translateY(12px) scale(0.99);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

.veil {
    position: fixed;
    inset: 0;
    z-index: 40;
    display: flex;
    align-items: flex-end;
    background: var(--veil);
    animation: veil 0.2s ease both;
}

/* La feuille défile seule : le fond bougerait sous les doigts sans ce verrou. */
body.is-locked {
    overflow: hidden;
}

.sheet {
    width: 100%;
    max-height: 92%;
    overflow: auto;
    box-sizing: border-box;
    background: var(--surface);
    border-radius: 18px 18px 0 0;
    padding: 24px 22px 26px;
    animation: sheetUp 0.28s cubic-bezier(0.2, 0.8, 0.2, 1) both;
}

.sheet__handle {
    display: block;
    width: 40px;
    height: 4px;
    border-radius: 2px;
    background: var(--handle);
    margin: 0 auto 20px;
}

.sheet__title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 22px;
    letter-spacing: -0.03em;
    margin: 0 0 16px;
}

.sheet--menu .btn {
    justify-content: flex-start;
    font-size: 15.5px;
    padding: 16px;
    margin-bottom: 10px;
}

.sheet__input {
    width: 100%;
    box-sizing: border-box;
    background: #FFF;
    border: 1px solid var(--field);
    border-radius: 14px;
    padding: 14px 15px;
    font-size: 15.5px;
    color: var(--ink);
    outline: none;
}

.sheet__input:focus {
    border-color: var(--amber);
}

.sheet__hint {
    font-size: 12.5px;
    color: var(--text-2);
    margin: 8px 0 16px;
}

.sheet .field__label {
    display: block;
}

/* Deux champs qui se suivent dans une feuille : la marge se porte sur le
   libellé du second, pas sur l'input du premier — un input peut être suivi
   d'un rappel ou d'une erreur, un libellé jamais. */
.sheet__input + .field__label {
    margin-top: 18px;
}

.sheet__input + .field__error {
    margin-top: 10px;
}

/* ─── Contrôle segmenté ───────────────────────────────────────────────────
   Une seule définition pour les trois usages : la nature des opérations
   (Activité), les filtres de la liste des clients, et la bascule Crédit /
   Remboursement de la feuille. Les deux premiers peignent la pastille active en
   blanc ; la feuille, elle, la remplit de la couleur de la nature — c'est le
   seul écart, et il tient dans les règles `[data-type]` plus bas. */
.seg {
    display: flex;
    gap: 4px;
    background: var(--rail);
    padding: 4px;
    border-radius: 13px;
    margin-bottom: 18px;
}

.sheet .seg {
    margin-bottom: 20px;
}

.seg__item {
    flex: 1;
    border: none;
    background: none;
    border-radius: 9px;
    padding: 11px 6px;
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text-2);
    text-align: center;
    /* Un libellé coupé en deux lignes déformerait tout le rail. */
    white-space: nowrap;
    cursor: pointer;
}

.seg__item.is-on {
    background: #FFF;
    color: var(--ink);
    box-shadow: 0 1px 3px rgb(20 11 5 / 18%);
}

.sheet--entry[data-type="credit"] .seg__item--credit,
.sheet--entry[data-type="payment"] .seg__item--payment {
    color: #FFF;
}

.sheet--entry[data-type="credit"] .seg__item--credit {
    background: var(--amber);
}

.sheet--entry[data-type="payment"] .seg__item--payment {
    background: var(--olive);
}

/* La nature d'une opération corrigée ne se change pas : la pastille active
   reste — elle rappelle ce qu'on est en train de modifier — et l'autre est
   retirée. Même posture que le champ client, et la même raison : basculer un
   crédit de 50 000 en remboursement déplacerait la fiche de 100 000 d'un seul
   appui, et une correction n'a pas d'« Annuler » dans son toast. Se tromper de
   côté se rattrape en supprimant la ligne et en la re-notant — ce geste-là,
   lui, s'annule pendant cinq secondes. Le contrôleur refuse la bascule de son
   côté : la feuille de style ne fait jamais foi sur ce genre de règle. */
.sheet--entry[data-mode="edit"][data-type="credit"] .seg__item--payment,
.sheet--entry[data-mode="edit"][data-type="payment"] .seg__item--credit {
    display: none;
}

.sheet--entry[data-mode="edit"] .seg__item {
    cursor: default;
}

/* Les libellés des deux natures sont écrits dans le gabarit ; la nature active
   décide lequel s'affiche, ce qui garde les textes hors du JavaScript. */
.sheet--entry[data-type="credit"] [data-when="payment"],
.sheet--entry[data-type="payment"] [data-when="credit"] {
    display: none;
}

/* Le mode — création ou correction — se lit de la même façon, et les deux
   attributs se croisent : « Modifier le crédit » est le libellé qui porte les
   deux. Un seul état de contrôleur (`editUuid`) commande les deux règles. */
.sheet--entry[data-mode="create"] [data-when-mode="edit"],
.sheet--entry[data-mode="edit"] [data-when-mode="create"] {
    display: none;
}

/* Le profil grossiste, de la même façon : « N° de facture » et « Livré par »
   n'existent que pour lui. Sans l'attribut, la feuille est celle de tous. */
.sheet--entry:not([data-wholesale="yes"]) [data-when-wholesale="yes"],
.sheet--entry[data-wholesale="yes"] [data-when-wholesale="no"] {
    display: none;
}

/* Le client d'une opération corrigée ne se change pas : le champ garde son nom,
   perd la loupe et le chevron — donc l'annonce d'une page à ouvrir — et cesse
   de se donner comme un bouton. Le contrôleur refuse de l'ouvrir de son côté :
   la feuille de style ne fait jamais foi sur ce genre de règle. */
.sheet--entry[data-mode="edit"] .picker__field {
    cursor: default;
}

/* ─── Montant et raccourcis ───────────────────────────────────────────────*/
.amount {
    display: flex;
    align-items: baseline;
    gap: 10px;
    border-bottom: 2px solid var(--amber);
    margin-bottom: 18px;
}

.sheet--entry[data-type="payment"] .amount {
    border-bottom-color: var(--olive);
}

.amount__input {
    flex: 1;
    min-width: 0;
    border: none;
    background: none;
    padding: 8px 2px;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 34px;
    letter-spacing: -0.03em;
    color: var(--ink);
    outline: none;
}

.amount__currency {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 15px;
    color: var(--text-3);
}

/* Une seule pastille, alignée à gauche — « Solder tout le compte ». Sa
   visibilité tient à un solde, que le document ignore : c'est le contrôleur qui
   l'ouvre, pas une règle `[data-type]` comme du temps des trois raccourcis. */
/* L'avertissement de plafond, sous le montant. Orange et jamais rouge : le
   handoff en fait une règle transverse — le plafond informe, il n'accuse pas,
   et rien n'est bloqué. C'est la même barre verticale que le résumé de retard
   de la fiche, pour la même raison : elle marque sans crier. */
.overlimit {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin: 0 0 18px;
    padding: 11px 13px;
    border: 1px solid var(--limit-line);
    border-radius: 12px;
    background: var(--limit-wash);
    font-size: 13.5px;
    font-weight: 600;
    line-height: 1.45;
    color: var(--limit-text);
}

.overlimit__bar {
    flex: none;
    width: 4px;
    height: 30px;
    border-radius: 2px;
    background: var(--amber-brand);
}

.shortcuts {
    display: flex;
    margin-bottom: 18px;
}

.shortcut--whole {
    border: none;
    background: var(--olive-soft);
    color: var(--olive-text);
    border-radius: 11px;
    padding: 10px 15px;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
    white-space: nowrap;
}

/* ─── Choix du client ─────────────────────────────────────────────────────
   Le champ a l'apparence d'un `<select>` et n'en est plus un : il ouvre une
   page. Il porte `sheet__input` pour cela — bordure, rayon, retrait et cadre de
   focus viennent de là, et ne peuvent pas s'écarter de ceux des vrais champs de
   la feuille. Les deux signes à droite disent lequel des deux gestes attend —
   la loupe pour chercher, le chevron pour la page qui s'ouvre. */
.picker__field {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 8px;
    text-align: left;
    cursor: pointer;
}

.picker__field.is-empty {
    color: var(--placeholder);
}

.picker__chosen {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.picker__signs {
    display: flex;
    align-items: center;
    gap: 9px;
    flex: none;
}

.picker__signs svg:first-child {
    color: var(--text-3);
}

.picker__signs svg:last-child {
    color: var(--placeholder);
}

/* La page elle-même : posée par-dessus la feuille, elle en couvre le voile.
   En mobile c'est une page pleine, en desktop une modale — même balisage. */
.picker {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: flex;
    flex-direction: column;
    background: var(--surface);
    animation: fadeUp 0.22s ease both;
}

.picker__panel {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
}

.picker__head {
    display: flex;
    align-items: center;
    gap: 13px;
    padding: 16px 16px 14px;
    border-bottom: 1px solid var(--border);
}

/* Une pastille, pas une flèche nue : le retour doit se viser au pouce. */
.picker__back {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 20px;
    border: 1px solid var(--field);
    background: #FFF;
    color: var(--ink);
    cursor: pointer;
}

.picker__title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 19px;
    letter-spacing: -0.03em;
    margin: 0;
}

.picker__search {
    padding: 14px 16px 10px;
}

.picker__body {
    flex: 1;
    min-height: 0;
    overflow: auto;
    padding: 0 16px 24px;
}

.picker__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.pick {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    border: none;
    border-bottom: 1px solid var(--border);
    background: none;
    padding: 13px 2px;
    text-align: left;
    cursor: pointer;
}

.pick__avatar {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--rail);
    color: var(--chip-text);
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 14px;
}

.pick__identity {
    flex: 1;
    min-width: 0;
}

.pick__name {
    display: block;
    font-size: 15.5px;
    font-weight: 500;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Le téléphone, ou « Pas de numéro » — jamais un montant : cette page sert à
   retrouver quelqu'un, pas à comparer des dettes. */
.pick__sub {
    display: block;
    font-size: 12.5px;
    color: var(--text-3);
}

/* Le client déjà retenu se reconnaît de trois façons : le commerçant qui
   rouvre la page doit voir où il en était sans relire la feuille dessous. */
.pick--current .pick__avatar {
    background: var(--ink);
    color: var(--cream);
}

.pick--current .pick__name {
    font-weight: 700;
}

.pick__check {
    flex: none;
    display: flex;
    color: var(--amber);
}

.picker__create {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    border: none;
    background: none;
    padding: 15px 2px;
    font-size: 15px;
    font-weight: 700;
    color: var(--amber);
    text-align: left;
    cursor: pointer;
}

.picker__plus {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--amber-wash);
    font-size: 21px;
    font-weight: 700;
}

.picker__empty {
    padding: 26px 4px;
    font-size: 14.5px;
    color: var(--text-2);
    margin: 0;
}

/* ─── Boutons colorés par nature ──────────────────────────────────────────*/
.btn--credit {
    background: var(--amber);
    color: #FFF;
}

.btn--payment {
    background: var(--olive);
    color: #FFF;
}

.btn--payment-outline {
    background: none;
    border: 1.5px solid var(--nav-outline);
    color: var(--olive-light);
}

.sheet--entry[data-type="credit"] .btn--type {
    background: var(--amber);
    color: #FFF;
}

.sheet--entry[data-type="payment"] .btn--type {
    background: var(--olive);
    color: #FFF;
}

/* ─── Bascule desktop ─────────────────────────────────────────────────────*/
@media (min-width: 900px) {
    .shell {
        flex-direction: row;
    }

    .shell__main {
        padding-bottom: 0;
    }

    .nav {
        position: sticky;
        top: 0;
        inset: auto;
        align-self: flex-start;
        height: 100vh;
        width: 248px;
        flex: none;
        background: var(--ink);
        border-top: none;
        padding: 26px 18px;
    }

    .nav__brand {
        display: flex;
        align-items: center;
        gap: 10px;
        color: var(--cream);
        font-family: var(--font-display);
        font-weight: 800;
        font-size: 20px;
        margin-bottom: 24px;
    }

    .nav__brand img {
        border-radius: 8px;
    }

    .nav__list {
        flex-direction: column;
        align-items: stretch;
        gap: 4px;
    }

    .nav__item {
        flex-direction: row;
        justify-content: flex-start;
        gap: 12px;
        padding: 12px 14px;
        border-radius: 12px;
        color: var(--nav-inactive);
    }

    .nav__item.is-active {
        background: var(--nav-active-bg);
        color: var(--nav-active-text);
    }

    .nav__icon svg {
        width: 20px;
        height: 20px;
    }

    .nav__label {
        font-size: 14.5px;
    }

    .page {
        max-width: 860px;
        margin: 0 auto;
        padding: 38px 40px 56px;
    }

    .search__add {
        font-size: 15px;
    }

    .search__add-label {
        display: inline;
    }

    .detail {
        max-width: 860px;
        margin: 0 auto;
        padding: 38px 40px 56px;
    }

    .detail__head {
        border-radius: 22px;
        padding: 26px 28px;
    }

    .detail__body {
        max-width: 520px;
        padding: 18px 0 0;
    }

    .toast {
        left: 50%;
        right: auto;
        transform: translateX(-50%);
        max-width: 460px;
        bottom: 22px;
    }

    /* Le bouton flottant est une réponse au pouce : la barre latérale a la
       place d'afficher les deux natures en toutes lettres. */
    .nav {
        display: flex;
        flex-direction: column;
    }

    .shell--bare .nav {
        display: flex;
    }

    .nav__note,
    .sheet--menu {
        display: none;
    }

    .nav__actions {
        display: flex;
        flex-direction: column;
        gap: 10px;
        margin-top: auto;
    }

    .nav__actions .btn {
        font-size: 15px;
        padding: 14px;
    }

    .veil {
        align-items: center;
        justify-content: center;
        padding: 32px;
    }

    .sheet {
        max-width: 460px;
        border-radius: 22px;
        padding: 28px;
        animation: modalIn 0.24s ease both;
    }

    .sheet__handle {
        display: none;
    }

    /* La page de choix devient une modale sur voile, comme les feuilles : un
       panneau plein écran sur un écran de bureau n'aurait aucun sens, et
       l'application garde une seule grammaire de superposition. */
    .picker {
        align-items: center;
        justify-content: center;
        padding: 32px;
        background: var(--veil);
        animation: veil 0.2s ease both;
    }

    .picker__panel {
        flex: none;
        width: 100%;
        max-width: 460px;
        height: 560px;
        max-height: 100%;
        background: var(--surface);
        border-radius: 22px;
        overflow: hidden;
        box-shadow: 0 20px 50px rgb(20 11 5 / 30%);
        animation: modalIn 0.24s ease both;
    }
}

/* ─── Accueil ─────────────────────────────────────────────────────────────*/
.home__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 22px;
}

.home__brand {
    display: flex;
    align-items: center;
    gap: 9px;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 17px;
    letter-spacing: -0.03em;
}

.home__brand img {
    border-radius: 8px;
}

.home__who {
    font-size: 13px;
    color: var(--text-3);
}

/* La salutation est le titre du desktop ; en mobile, la marque tient ce rôle. */
.home__hello {
    display: none;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 30px;
    letter-spacing: -0.035em;
    margin: 0 0 22px;
}

.home__top {
    display: flex;
    flex-direction: column;
    margin-bottom: 14px;
}

/* ─── Carte du reste à recevoir ───────────────────────────────────────────*/
.total {
    position: relative;
    flex: 1;
    overflow: hidden;
    background: var(--ink);
    border-radius: 22px;
    padding: 24px 22px;
}

/* Le motif de la marque, trois bâtons — décor, donc masqué aux lecteurs d'écran. */
.total__mark {
    position: absolute;
    top: 20px;
    right: 20px;
    display: flex;
    gap: 5px;
    opacity: 0.5;
}

.total__mark i,
.blank__mark i {
    display: block;
    width: 4px;
    height: 26px;
    border-radius: 2px;
    background: var(--amber-brand);
}

.total__mark i:last-child {
    background: var(--olive-bright);
}

.total__label {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--on-ink-3);
    margin: 0 0 12px;
}

.total__value {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 44px;
    line-height: 1;
    letter-spacing: -0.04em;
    color: var(--cream);
    margin: 0;
}

.total__currency {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 17px;
    color: var(--amber-brand);
    margin: 4px 0 0;
}

.total__chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 18px 0 0;
}

.chip-ink {
    font-size: 12.5px;
    color: var(--on-ink-chip);
    background: var(--chip-on-ink);
    border-radius: 20px;
    padding: 6px 12px;
}

.chip-ink--paid {
    color: var(--olive-light);
}

/* ─── Cartes du jour — desktop seulement ──────────────────────────────────*/
.cards {
    display: none;
}

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 22px;
    padding: 22px;
}

.card__label {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-2);
    margin: 0 0 10px;
}

.card__value {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 30px;
    letter-spacing: -0.03em;
    margin: 0;
}

.card__value--paid {
    color: var(--olive-text);
}

/* ─── Actions de l'accueil ────────────────────────────────────────────────*/
.home__actions {
    display: flex;
    gap: 10px;
    margin-bottom: 30px;
}

.home__actions .btn {
    flex: 1;
    font-size: 15.5px;
    border-radius: 16px;
    padding: 16px;
}

.section {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 6px;
}

.section .section__label {
    margin: 0;
}

.section__link {
    font-size: 12.5px;
    font-weight: 700;
    color: var(--amber);
    text-decoration: none;
}

/* Quatre lignes au pouce, six à l'écran large — le serveur en envoie six. */
.history--recent .entry:nth-child(n+5) {
    display: none;
}

/* ─── Cahier vierge ───────────────────────────────────────────────────────*/
.blank {
    text-align: center;
    padding: 48px 8px;
}

.blank__mark {
    display: flex;
    justify-content: center;
    gap: 7px;
    margin-bottom: 26px;
}

.blank__mark i {
    width: 6px;
    height: 44px;
    border-radius: 3px;
    background: var(--field);
}

.blank__mark i:last-child {
    background: var(--amber-brand);
    opacity: 0.5;
}

.blank__title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 22px;
    letter-spacing: -0.03em;
    margin: 0 0 8px;
}

.blank__text {
    color: var(--text-2);
    font-size: 14.5px;
    line-height: 1.6;
    max-width: 250px;
    margin: 0 auto 26px;
}

.btn--inline {
    width: auto;
    font-size: 15px;
    padding: 15px 26px;
}

/* ─── Activité ────────────────────────────────────────────────────────────*/
.page__title--activity {
    margin-bottom: 12px;
}

.page__title--profile {
    margin-bottom: 22px;
}

/* Le journal a une mesure de lecture : au-delà, l'œil perd la ligne entre le
   nom, à gauche, et le montant, au bord droit. En mobile, la page est déjà plus
   étroite que ce plafond. */
.activity > * {
    max-width: 520px;
}

/* Seule sur cet écran, la recherche n'a pas de bouton à côté d'elle. */
.search--alone {
    margin-bottom: 10px;
}

.journal {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Une journée porte ses propres flux : c'est ce qui a remplacé la barre de
   résumé, et le filtre de période avec elle. */
.day__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin: 24px 0 0;
    padding-bottom: 8px;
    border-bottom: 2px solid var(--ink);
}

.day__label {
    font-size: 13.5px;
    font-weight: 700;
}

.day__flows {
    display: flex;
    gap: 10px;
}

.day__credits,
.day__payments {
    font-size: 12.5px;
    font-weight: 700;
}

.day__credits {
    color: var(--amber);
}

.day__payments {
    color: var(--olive-text);
}

/* Les puces d'échéance de la feuille de saisie : un délai se choisit d'un
   doigt, et la rangée s'enroule quand cinq puces ne tiennent pas. Les filtres,
   eux, sont passés au contrôle segmenté. */
.chip {
    color: var(--chip-text);
    border-radius: 20px;
    padding: 8px 13px;
    font-size: 12.5px;
    font-weight: 700;
    white-space: nowrap;
    text-decoration: none;
}

.chip--soft {
    background: none;
    border: 1.5px solid var(--field);
    padding: 7px 12px;
    color: var(--text-2);
}

.chip--soft.is-on {
    border-color: var(--ink);
    color: var(--ink);
}

/* Le journal n'a pas d'état vide illustré : une phrase, là où la première
   ligne se serait trouvée. */
.activity__empty {
    padding: 38px 4px;
    color: var(--text-2);
    font-size: 14.5px;
}

.activity__more {
    margin: 16px 0 0;
    font-size: 13px;
    color: var(--text-3);
}

/* ─── Profil ──────────────────────────────────────────────────────────────*/
.profile {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 18px;
    padding: 4px 18px;
    margin: 0 0 22px;
}

.profile__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 0;
    border-bottom: 1px solid var(--border);
}

.profile__row:last-child {
    border-bottom: none;
}

.profile__label {
    font-size: 13.5px;
    color: var(--text-2);
}

.profile__value {
    margin: 0;
    font-size: 14.5px;
    font-weight: 600;
    text-align: right;
}

/* Le lien légal du Profil : présent, jamais en travers du chemin. Il se lit
   comme un pied de page, parce que c'en est un. */
.profile__legal {
    display: block;
    margin: 32px 0 0;
    font-size: 13px;
    color: var(--text-3);
    text-align: center;
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* ─── Bascule desktop — écrans de l'étape 6 ───────────────────────────────*/
@media (min-width: 900px) {
    .home__head {
        display: none;
    }

    .home__hello {
        display: block;
    }

    .home__top {
        flex-direction: row;
        align-items: stretch;
        gap: 14px;
        margin-bottom: 34px;
    }

    .cards {
        display: flex;
        flex: 1;
        flex-direction: column;
        gap: 14px;
    }

    /* Le desktop a ses deux boutons dans la barre latérale. */
    .home__actions {
        display: none;
    }

    .history--recent .entry:nth-child(n+5) {
        display: list-item;
    }

    /* Colonne de lecture : l'activité et le profil sont des listes, pas des
       tableaux de bord — les étirer sur 860 px éloignerait le montant du nom.
       Les dernières opérations de l'accueil, elles, suivent la carte solde. */
    .filters,
    .totals,
    .totals + .history,
    .activity__empty,
    .activity__more,
    .profile,
    .profile + form {
        max-width: 520px;
    }
}

/* ─── Appeler et relancer ─────────────────────────────────────────────────*/
.detail__reach {
    display: flex;
    gap: 10px;
    margin-bottom: 28px;
}

/* Actions secondaires : elles se voient, sans concurrencer les deux boutons
   pleins qui, eux, écrivent dans le cahier. */
/* `width: 100%` du bouton de base ferait ici une base flex de la largeur du
   conteneur : les deux liens se disputeraient toute la rangée. */
.btn--reach {
    flex: 1;
    width: auto;
    background: none;
    border: 1.5px solid var(--field-strong);
    color: var(--ink);
    font-size: 14.5px;
    padding: 14px;
}

/* « Appeler » est court : il prend la place de son libellé, pas la moitié. */
.btn--call {
    flex: none;
    padding: 14px 18px;
}

/* ─── Bandeau de mise à jour ──────────────────────────────────────────────*/
/* Le design n'a pas d'état « nouvelle version » : c'est le toast qui le porte,
   avec un bouton d'action et sans disparition automatique. */
.toast--update {
    align-items: center;
    gap: 10px;
}

/* Ici, et ici seulement, l'action est un bouton plein : elle demande une
   décision, et le bandeau attend qu'on la prenne. */
.toast--update .toast__action {
    background: var(--amber);
    color: #FFF;
    border-radius: 12px;
    padding: 9px 14px;
    font-size: 13.5px;
}

.toast__action[disabled] {
    opacity: 0.6;
    cursor: default;
}

.toast__close {
    flex: none;
    background: none;
    border: none;
    color: var(--on-ink-2);
    font-size: 15px;
    line-height: 1;
    padding: 6px;
    cursor: pointer;
}

/* ─── Installation ────────────────────────────────────────────────────────
   Trois points d'entrée, une seule feuille. Le bandeau de l'accueil et la carte
   du Profil partagent leur intérieur — icône, titre, sous-titre — et ne
   diffèrent que par leur cadre : ambre et effaçable pour l'un, neutre et
   permanent pour l'autre.                                                  */
.install {
    display: flex;
    align-items: center;
    gap: 13px;
    width: 100%;
    box-sizing: border-box;
    border-radius: 18px;
    padding: 15px 18px;
    /* La carte « Application installée » est un `<p>` : sans marge explicite,
       elle hériterait de celle du navigateur par le haut. La marge basse est
       celle de la pile de gestes qui suit — l'écran garde un seul rythme. */
    margin: 0 0 18px;
    text-align: left;
}

.install--go {
    background: var(--surface);
    border: 1px solid var(--border);
    cursor: pointer;
}

/* Installée : la carte constate, elle ne mène plus nulle part — d'où le vert
   du remboursement, la couleur de ce qui est réglé, et aucun curseur. */
.install--done {
    background: var(--olive-wash);
    border: 1px solid var(--olive-line);
}

.install__icon {
    flex: none;
    border-radius: 9px;
}

.install__icon--large {
    border-radius: 14px;
}

.install__lines {
    flex: 1;
    min-width: 0;
}

.install__title {
    display: block;
    font-size: 14.5px;
    font-weight: 700;
    color: var(--ink);
}

.install__sub {
    display: block;
    font-size: 12.5px;
    color: var(--text-2);
}

.install__go {
    flex: none;
    font-size: 13.5px;
    font-weight: 700;
    color: var(--amber);
    white-space: nowrap;
}

/* Le bandeau de l'accueil : la même invitation, en tête d'écran, dans le ton
   ambre de la marque — et avec de quoi la faire taire. */
.install-banner {
    display: flex;
    align-items: center;
    gap: 12px;
    background: var(--install-bg);
    border: 1px solid var(--install-line);
    border-radius: 16px;
    padding: 11px 12px;
    margin-bottom: 14px;
}

.install-banner .install__title {
    font-size: 14px;
}

.install-banner__go {
    flex: none;
    border: none;
    background: var(--amber);
    color: #FFF;
    border-radius: 11px;
    padding: 11px 15px;
    font-size: 13.5px;
    font-weight: 700;
    cursor: pointer;
}

/* Une croix se vise mal : la zone de touche fait 32px, le signe en fait 19. */
.install-banner__close {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: none;
    background: none;
    color: var(--text-3);
    font-size: 19px;
    line-height: 1;
    cursor: pointer;
}

/* La feuille : l'identité de l'application, puis ce qu'installer veut dire. */
.install__head {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 16px;
}

.install__name {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 20px;
    letter-spacing: -0.03em;
    line-height: 1.2;
    margin: 0;
}

.install__host {
    font-size: 13px;
    color: var(--text-3);
    margin: 3px 0 0;
}

.install__body {
    font-size: 14.5px;
    line-height: 1.6;
    color: var(--text-2);
    margin: 0 0 22px;
}

/* iOS ne sait pas installer sur commande : à la place du bouton, les deux
   gestes à faire, écrits noir sur blanc. */
.install__steps {
    color: var(--text-2);
    font-size: 14px;
    line-height: 1.7;
    margin: 0 0 22px;
    padding-left: 20px;
}

/* ─── Bandeau réseau ──────────────────────────────────────────────────────*/
/* Le design ne montre rien quand tout va bien : « l'absence de message est le
   signal ». Ce bandeau ne dit donc jamais « synchronisé », et jamais un
   décompte — la file d'attente doit rester invisible, seule sa traduction en
   langage courant apparaît ici. */
.netbar {
    margin: 0;
    padding: 9px 18px;
    font-size: 12px;
    text-align: center;
    color: #FFF;
}

.netbar--offline {
    background: var(--ink);
    color: var(--on-ink-strong);
}

.netbar--syncing {
    background: var(--olive);
    animation: pulse 1.4s ease-in-out infinite;
}

.netbar--error {
    background: var(--error);
}

/* ─── Badge « En attente d'envoi » ────────────────────────────────────────*/
/* Sur la ligne concernée, et nulle part ailleurs : c'est ce que le design
   demande, et c'est aussi ce qui évite d'inquiéter sur tout un écran pour une
   seule écriture qui n'est pas encore partie. */
.badge {
    align-self: flex-start;
    margin-top: 4px;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--olive-soft);
    color: var(--olive-text);
    font-size: 11.5px;
    font-weight: 700;
}

/* Un refus n'est pas une attente : il ne se résoudra pas tout seul. */
.badge--rejected {
    background: rgb(190 34 42 / 12%);
    color: var(--error);
    font-weight: 600;
    border-radius: 10px;
    white-space: normal;
}

@supports (color: oklch(0.5 0.1 60)) {
    .badge--rejected {
        background: oklch(0.52 0.19 25 / 12%);
    }
}

/* La ligne refusée reste lisible mais ne se donne plus comme un montant du
   cahier : elle ne compte dans aucun solde. */
.entry--rejected .entry__amount {
    color: var(--error);
    text-decoration: line-through;
}

.entry--rejected .entry__bar {
    background: var(--error);
}

.entry__drop {
    display: block;
    margin: 0 0 12px 17px;
    padding: 6px 0;
    background: none;
    border: none;
    color: var(--error);
    font-family: inherit;
    font-size: 13px;
    font-weight: 700;
    text-decoration: underline;
    cursor: pointer;
}


/* ─── Échéances : saisie ──────────────────────────────────────────────────
   Une seule donnée sort de ce bloc — la date d'échéance. Les délais sont des
   raccourcis de saisie, et le nombre de jours n'est stocké nulle part.     */
.due {
    margin-bottom: 18px;
}

/* Un seul champ de date dans la feuille, et il n'apparaît que sur « Autre
   date » : celle du crédit a disparu — une opération a lieu au moment où on la
   note. D'où `--wide` sans variante étroite en face. */
.due__input {
    border: 1px solid var(--field);
    border-radius: 11px;
    padding: 9px 11px;
    font-family: inherit;
    font-size: 14px;
    color: var(--ink);
    background: var(--surface);
    outline: none;
}

.due__input:focus {
    border-color: var(--amber);
}

.due__input--wide {
    display: block;
    width: 100%;
    margin-top: 10px;
}

.terms {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/* Le commerçant lit une date, pas un délai à retrancher de tête. */
.due__confirm {
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--amber-soft);
    border-radius: 12px;
    padding: 10px 12px;
    margin: 12px 0 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--ink);
}

.due__bar {
    flex: none;
    width: 4px;
    height: 22px;
    border-radius: 2px;
    background: var(--amber-brand);
}

/* ─── Ligne de retard de l'accueil ────────────────────────────────────────
   Une ligne, pas une carte : le retard informe, il ne prend pas le dessus
   sur le reste à recevoir.                                                */
.lateline {
    display: flex;
    align-items: center;
    gap: 12px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 14px 16px;
    margin-bottom: 14px;
    text-decoration: none;
    color: inherit;
}

.lateline__bar {
    flex: none;
    width: 5px;
    height: 36px;
    border-radius: 3px;
    background: var(--amber-brand);
}

.lateline__text {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.lateline__title {
    font-size: 15px;
    font-weight: 700;
}

.lateline__sub {
    font-size: 12.5px;
    color: var(--text-2);
}

.lateline__go {
    flex: none;
    font-size: 13.5px;
    font-weight: 700;
    color: var(--amber);
}

/* ─── Vue « À relancer » ──────────────────────────────────────────────────
   Le total à recevoir et le montant échu sont deux chiffres distincts : on
   relance sur le premier, on priorise sur le second.                       */
.late {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 18px;
    padding: 16px 17px;
    margin-bottom: 10px;
    max-width: 520px;
}

.late__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 14px;
    text-decoration: none;
    color: inherit;
}

.late__identity {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.late__name {
    font-size: 16.5px;
    font-weight: 700;
}

.late__total {
    font-size: 13px;
    color: var(--text-2);
}

.late__box {
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
}

.late__amount {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 19px;
    letter-spacing: -0.02em;
    color: var(--amber);
}

.late__tag {
    font-size: 11px;
    color: var(--text-3);
}

.late__detail {
    display: flex;
    align-items: center;
    gap: 10px;
    border-top: 1px solid var(--border);
    margin-top: 14px;
    padding-top: 12px;
}

.late__bar {
    flex: none;
    width: 4px;
    height: 30px;
    border-radius: 2px;
    background: var(--amber-brand);
}

.late__lines {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.late__days {
    font-size: 13.5px;
    font-weight: 600;
}

.late__oldest,
.late__multi {
    font-size: 12.5px;
    color: var(--text-2);
}

.late__wa {
    display: block;
    margin-top: 14px;
    text-align: center;
    text-decoration: none;
}

/* ─── Bloc Échéances de la fiche ──────────────────────────────────────────*/
.schedule {
    margin-bottom: 24px;
}

.schedule__group {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-2);
    margin: 14px 0 8px;
}

.schedule__group::before {
    content: '';
    width: 4px;
    height: 14px;
    border-radius: 2px;
    background: var(--field-strong);
}

.schedule__group--late {
    color: var(--amber);
}

.schedule__group--late::before {
    background: var(--amber-brand);
}

.dues {
    list-style: none;
    margin: 0;
    padding: 0;
}

.dueline {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 0;
    border-bottom: 1px solid var(--border);
}

/* Une échéance dépassée mérite une carte ; une échéance à venir, une ligne. */
.dueline--late {
    background: var(--surface);
    border: 1px solid var(--amber-line);
    border-radius: 14px;
    padding: 14px 15px;
    margin-bottom: 8px;
}

.dueline__identity {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.dueline__date {
    font-size: 15px;
    font-weight: 700;
}

.dueline__rel {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-2);
}

.dueline--late .dueline__rel {
    color: var(--amber);
}

.dueline__origin {
    font-size: 12.5px;
    color: var(--text-3);
}

.dueline__box {
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
}

.dueline__amount {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 17px;
    letter-spacing: -0.02em;
}

.dueline__tag {
    font-size: 11px;
    color: var(--text-3);
}

/* La part échue du solde, sous le montant du bandeau de la fiche. */
.detail__late {
    display: flex;
    align-items: center;
    gap: 8px;
    /* 12px sous le montant, et la marge de `.sums` fait le reste : c'est
       l'espacement du prototype, pas un chiffre choisi à l'œil. */
    margin: 12px 0 0;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--on-ink-late);
}

.detail__late-bar {
    flex: none;
    width: 4px;
    height: 18px;
    border-radius: 2px;
    background: var(--amber-brand);
}

/* ─── Barre de plafond ────────────────────────────────────────────────────*/
/* Sous le montant, après le résumé de retard, et seulement si un plafond est
   défini : le design ne veut ni rail vide ni mention « Aucun plafond ». La
   fiche ne gagne qu'une ligne, et seulement quand elle a quelque chose à
   dire. */
.limitbar {
    margin-top: 14px;
}

.limitbar__rail {
    display: block;
    height: 3px;
    border-radius: 2px;
    background: var(--limit-rail);
    overflow: hidden;
}

/* Le remplissage est plafonné à 100 % par le contrôleur : un dépassement se lit
   dans le libellé de droite, il ne déborde pas du rail. */
.limitbar__fill {
    display: block;
    height: 100%;
    border-radius: 2px;
    background: var(--limit-ok);
    transition: width 0.3s ease;
}

.limitbar[data-state="near"] .limitbar__fill {
    background: var(--limit-near);
}

.limitbar[data-state="over"] .limitbar__fill {
    background: var(--amber-brand);
}

.limitbar__labels {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    margin: 7px 0 0;
    font-size: 12px;
}

.limitbar__cap {
    color: var(--on-ink-4);
}

/* Sous le plafond, le chiffre de droite est une information ; à partir de
   80 %, il prend la couleur de l'état — c'est le seul endroit où le
   dépassement se lit en clair. */
.limitbar__state {
    font-weight: 600;
    color: var(--on-ink-chip);
    white-space: nowrap;
}

.limitbar[data-state="near"] .limitbar__state {
    font-weight: 700;
    color: var(--limit-near-text);
}

.limitbar[data-state="over"] .limitbar__state {
    font-weight: 700;
    color: var(--limit-over-text);
}

/* La ligne Crédits / Déjà remboursé se resserre d'autant quand la barre
   s'intercale : le bandeau ne s'allonge pas de deux espacements. */
.limitbar:not([hidden]) + .sums {
    margin-top: 18px;
}

/* Les filtres de la liste des clients : une seule rangée, sans étiquette. */
.filters--clients {
    margin-bottom: 14px;
}

/* ─── Squelettes de chargement ────────────────────────────────────────────*/
/* De la forme du contenu final, jamais une roue qui tourne : l'écran doit
   déjà ressembler à ce qu'il va devenir. */
.sk {
    background: var(--skeleton);
    border-radius: 8px;
    /* Le cahier est local : la plupart du temps IndexedDB répond en quelques
       millisecondes, et un squelette qui apparaît pour disparaître aussitôt se
       lit comme un clignotement de plus. Il garde donc sa place dans la page —
       `visibility`, pas `display` : aucun saut de mise en page — mais ne se
       montre qu'au-delà de 200 ms, c'est-à-dire quand l'attente est réelle.

       Le retard est porté par une seconde animation plutôt que par une
       transition : `prefers-reduced-motion` raccourcit les durées sans toucher
       aux délais, et le squelette reste donc discret là aussi. */
    visibility: hidden;
    animation: pulse 1.4s ease-in-out infinite, sk-late 0.01s linear 0.2s forwards;
}

@keyframes sk-late {
    to {
        visibility: visible;
    }
}

.sk--card {
    height: 150px;
    border-radius: 22px;
    margin-bottom: 14px;
}

.sk--actions {
    height: 54px;
    border-radius: 14px;
    margin-bottom: 26px;
}

.sk--line {
    height: 15px;
    margin-bottom: 14px;
}

.sk--row {
    height: 44px;
    margin-bottom: 14px;
}

.sk--60 {
    width: 60%;
}

.sk--75 {
    width: 75%;
}
