/*
 * La feuille du projet. Elle est vide au départ, et le reste : ce qui vaut pour tous les
 * écrans appartient à `base.css`, ce qui se répète appartient à `components.css`.
 *
 * Ce qui s'écrit ici : le décalage propre à un projet — une police, un rayon, un accent — en
 * réécrivant un alias de `tokens.css`, jamais en recopiant une couleur.
 *
 *     :root {
 *         --app-accent: #0e7490;
 *         --app-radius: 8px;
 *     }
 *
 * Un écran qui demande ses propres règles prend sa feuille, `styles/<zone>/<gabarit>.css`,
 * importée depuis `app.js`.
 *
 * Une palette, elle, prend son fichier dans `styles/themes/` : le paquet l'y lit, la sert et
 * la propose sans qu'aucune ligne soit à écrire ici.
 */

/*
 * La barre du haut reste en vue pendant le défilement. Le paquet le prévoit derrière
 * `data-sticky`, mais son gabarit pose la balise `header` en dur : l'attribut ne peut pas s'y
 * ajouter sans recopier tout le bloc. Les trois lignes ci-dessous disent la même chose, avec
 * le jeton du paquet plutôt qu'une valeur inventée.
 */
.app-header {
    position: sticky;
    top: 0;
    z-index: var(--app-z-sticky);
}

/*
 * La barre de debug se pose par-dessus la page, et non à sa suite.
 *
 * En développement, Symfony insère sa barre en fin de `body`, après une charpente qui occupe
 * déjà toute la hauteur de la fenêtre. Ce qu'on voit en bas de l'écran est bien collé là par
 * l'outil, mais la boîte qui le porte, elle, reste dans le flux : trente-six pixels de plus
 * que la fenêtre, donc une barre de défilement sur chaque page alors que rien ne dépasse.
 *
 * La sortir du flux rend la page à sa hauteur. Le dessin ne bouge pas d'un pixel : ce qui est
 * à l'intérieur était déjà fixé au bas de la fenêtre.
 *
 * Rien à retirer le jour venu : ce sélecteur ne rencontre aucune balise en production, où la
 * barre n'est pas rendue.
 */
body > .sf-toolbar {
    position: fixed;
    inset: auto 0 0 0;
}

/* ═══ La charpente ═════════════════════════════════════════════════════════════════════ */

/*
 * La fenêtre est le cadre. La charpente en prend exactement la hauteur, et c'est le contenu qui
 * défile à l'intérieur, jamais la page : le menu latéral et la barre du haut tiennent en place
 * d'eux-mêmes, et rien ne dépasse par le bas.
 *
 * Le contenu prend la rangée du milieu — `minmax(0, …)` et non `1fr` seul, sans quoi une page
 * longue imposerait sa hauteur à la rangée et la fenêtre serait de nouveau dépassée.
 *
 * Seulement là où le menu est une colonne : plus bas, il occupe une rangée de plus, la barre du
 * haut passe dessous, et une page qui défile normalement est ce qu'on attend d'un téléphone.
 */
@media (min-width: 60em) {
    .app-shell[data-layout="sidebar"] {
        height: 100dvh;
        grid-template-rows: auto minmax(0, 1fr) auto;
    }

    .app-shell[data-layout="sidebar"] > .app-main {
        overflow-y: auto;
    }

    /*
     * La page ne défile plus d'elle-même : la place que le socle réserve à sa barre de
     * défilement resterait vide le long du bord droit, et cette bande-là est plus large que la
     * gouttière qu'elle vient doubler.
     */
    html:has(.app-shell[data-layout="sidebar"]) {
        scrollbar-gutter: auto;
    }
}

/* ═══ La gouttière ═════════════════════════════════════════════════════════════════════ */

/*
 * Une seule mesure d'écart pour toute l'application : le retrait des bords de la page, l'espace
 * entre deux panneaux et la marge intérieure d'une carte valent la même chose.
 *
 * Les écarts du paquet sont taillés pour une page qui se lit en une colonne, où de larges marges
 * posent le texte au milieu de l'écran. Ici, une page porte plusieurs panneaux côte à côte, et
 * trois retraits différents empilés le long d'un même bord se voient — d'autant qu'ils prennent
 * la place de ce qu'ils encadrent.
 */
.app-main {
    padding: var(--app-space-lg);
}

.app-card {
    padding: var(--app-space-lg);
}

/*
 * La barre du haut se retire d'autant que la page : le titre tombe alors sur la marge où
 * commencent les cartes, au lieu de flotter un centimètre plus loin.
 */
.app-header {
    padding-inline: var(--app-space-lg);
}

/*
 * Le contenu commence au bord et non au milieu. La largeur de lecture du paquet reste un
 * plafond, mais centrer ce qui n'y arrive pas décalerait la page de sa barre de titre, qui,
 * elle, part du bord. Seulement là où un menu latéral tient la gauche : une page seule — la
 * connexion — garde son contenu au centre de l'écran, qui est tout ce qu'elle porte.
 */
.app-shell[data-layout="sidebar"] > .app-main {
    margin-inline: 0;
}

/* ═══ La barre de titre ════════════════════════════════════════════════════════════════ */

/*
 * L'en-tête ne porte plus que le nom de ce qu'on regarde, et ce qu'on peut en faire. Un titre
 * de page y prend donc la taille d'un intitulé de barre, et non celle d'un titre de document :
 * la charpente est déjà pleine de repères — la marque, le menu, la page surlignée — et une
 * capitale de deux centimètres écraserait tout le reste.
 */
.page-title {
    font-size: var(--app-text-lg);
    /* Un nom de projet plus long que la barre s'arrête en points de suspension plutôt que de
       repousser les commandes hors de l'écran. */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*
 * Le compte, au bout de la barre : une pastille, une adresse, et rien qui ressemble à un bouton
 * tant que le curseur n'est pas dessus. Il ouvre le menu qui porte le profil et la déconnexion.
 */
.account {
    display: flex;
    align-items: center;
    gap: var(--app-space-sm);
    padding: var(--app-space-2xs);
    border-radius: var(--app-radius-ui);
    cursor: pointer;
}

.account:hover {
    background: var(--app-hover);
}

.account-email {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--app-text-sm);
    color: var(--app-ink-soft);
}

/* Sur un téléphone, la barre porte déjà un titre et le bouton du menu : l'adresse s'efface, la
   pastille suffit à dire où l'on clique. */
@media (max-width: 40em) {
    .account-email {
        display: none;
    }
}

/* ═══ Le menu latéral ══════════════════════════════════════════════════════════════════ */

/*
 * La colonne prend la couleur d'accent : la seule surface pleine de l'interface, et ce qui
 * donne à l'application son visage avant qu'on ait lu un mot.
 *
 * Aucune couleur n'est inventée ici — c'est le ton du thème, tel quel. Ce qui s'y pose s'écrit
 * en « sur accent », l'encre que le paquet réserve à ce fond, et les fonds de survol sont des
 * voiles de cette même encre. Une palette qui change l'accent emporte donc la colonne avec
 * elle, les cinq à la fois.
 *
 * Une palette faite pour Basile viendra plus tard donner à cette colonne son ton propre : elle
 * n'aura qu'à réécrire `--app-accent`, sans qu'une règle d'ici ne bouge.
 */
.app-sidebar {
    --rail-veil: color-mix(in srgb, var(--app-on-accent) 14%, transparent);
    --rail-veil-strong: color-mix(in srgb, var(--app-on-accent) 26%, transparent);
    --rail-ink-soft: color-mix(in srgb, var(--app-on-accent) 78%, transparent);

    background: var(--app-accent);
    color: var(--app-on-accent);
    border-color: var(--rail-veil);
}

/* Les filets de la charpente sont dessinés pour un fond clair : sur l'accent, ils disparaissent
   ou tranchent. Ils deviennent des voiles, comme le reste. */
.app-sidebar .app-sidebar-head {
    border-bottom-color: var(--rail-veil);
}

/* En tiroir, le panneau reprend le fond du paquet : il faut le lui redire, sans quoi la couleur
   s'arrêterait au bord de l'écran étroit. */
.app-sidebar[data-drawer] > .app-sidebar-panel[open] {
    background: var(--app-accent);
    border-left-color: var(--rail-veil);
}

/* Les deux boutons de la charpente — ouvrir le tiroir, le refermer — sont des boutons du
   paquet, faits pour un fond clair. Sur l'accent, ils s'effacent et ne gardent que leur voile. */
.app-sidebar :is(.app-sidebar-toggle, .app-sidebar-close) {
    background: transparent;
    border-color: var(--rail-veil);
    color: inherit;
}

.app-sidebar :is(.app-sidebar-toggle, .app-sidebar-close):hover {
    background: var(--rail-veil);
}

/*
 * La marque : le dessin, puis le nom. Le paquet ne pose qu'un mot ; l'image demande une ligne
 * qui les aligne, et c'est tout ce qui s'ajoute ici.
 */
.app-brand {
    display: flex;
    align-items: center;
    gap: var(--app-space-sm);
    color: inherit;
}

/* La pousse est dessinée dans la couleur d'accent : posée telle quelle sur un fond de cette
   même couleur, elle disparaîtrait. Elle garde donc son carré clair, comme un logo. */
.app-brand img {
    width: 1.875rem;
    height: 1.875rem;
    padding: var(--app-space-2xs);
    border-radius: var(--app-radius-ui);
    background: var(--app-surface);
}

/*
 * Une entrée du menu porte son dessin devant son nom. Le composant du paquet est fait pour du
 * texte seul sur un fond clair : ces règles lui donnent la ligne d'alignement qui manque et
 * l'encre du fond coloré, sans toucher à ce qu'il décide — le retrait, le rayon, la page en
 * cours.
 */
.app-nav-item {
    display: flex;
    align-items: center;
    gap: var(--app-space-sm);
    /* La hauteur d'une cible qu'on vise sans regarder, et la même une fois la colonne repliée :
       le dessin garde alors son carré, au lieu de flotter dans une ligne de texte. */
    min-height: 2.75rem;
    padding-inline: var(--app-space-sm);
    color: var(--rail-ink-soft);
}

.app-nav-item:hover {
    background: var(--rail-veil);
    color: var(--app-on-accent);
}

/* La page où l'on se trouve : un voile plus dense que celui du survol, et l'encre pleine. */
.app-nav-item[aria-current="page"] {
    background: var(--rail-veil-strong);
    color: var(--app-on-accent);
}

/* Le dessin ne dit rien que le nom ne dise déjà : il suit la teinte de son entrée, sans la
   devancer. Sa taille est celle d'une icône de navigation — le double du texte, à peu près,
   parce que c'est tout ce qui reste quand la colonne est repliée. */
.rail-icon {
    display: inline-flex;
    flex: 0 0 auto;
    font-size: 1.5rem;
    color: inherit;
}

/* Le repli, seul au pied de la colonne, du côté du bord qu'il déplace. */
.rail-footer {
    display: flex;
    justify-content: flex-end;
    margin-top: auto;
}

/* La commande de repli : la même discrétion que celles de la barre de saisie — sans fond, elle
   ne s'allume qu'au survol. */
.rail-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
    border: none;
    border-radius: var(--app-radius-ui);
    background: none;
    color: var(--rail-ink-soft);
    font-size: 1.25rem;
    cursor: pointer;
    transition: background 150ms var(--app-ease), color 150ms var(--app-ease);
}

.rail-toggle:hover {
    background: var(--rail-veil);
    color: var(--app-on-accent);
}

/*
 * Le menu replié : les dessins restent, les mots s'effacent, et la page gagne onze rem de
 * largeur. L'infobulle de chaque entrée rend le nom à qui la survole.
 *
 * Seulement là où le menu est une colonne : plus bas, il se replie déjà derrière son bouton, et
 * un tiroir large de quatre rem n'aurait aucun sens. C'est la césure du paquet, reprise telle
 * quelle.
 *
 * L'état est porté par le bouton lui-même, seule balise que l'application pose dans cette
 * charpente ; `:has()` va le lire d'où il se trouve.
 */
@media (min-width: 60em) {
    .app-shell:has(.rail-toggle[data-rail="narrow"]) {
        --app-sidebar-width: 3.5rem;
    }

    /* Les marges intérieures suivent : celles d'une colonne de quinze rem laisseraient au
       dessin moins de place qu'au vide autour de lui. */
    .app-sidebar:has(.rail-toggle[data-rail="narrow"]) :is(.app-sidebar-head, .app-sidebar-panel) {
        padding-inline: var(--app-space-xs);
    }

    .app-sidebar:has(.rail-toggle[data-rail="narrow"]) :is(.app-sidebar-head, .app-nav-item, .rail-footer) {
        justify-content: center;
    }

    .app-sidebar:has(.rail-toggle[data-rail="narrow"]) .app-nav-item {
        padding-inline: 0;
    }

    .app-sidebar:has(.rail-toggle[data-rail="narrow"]) :is(.rail-brand-name, .rail-label) {
        display: none;
    }
}

/* ═══ Les intitulés de cadre ═══════════════════════════════════════════════════════════ */

/*
 * Ce qui nomme un panneau : un dessin, puis le nom en petites capitales, posés sur un filet qui
 * les sépare de ce qu'ils annoncent.
 *
 * Le même d'un cadre à l'autre — le fil, la discussion, les réglages, le profil — pour qu'ils se
 * lisent comme les faces d'une même page. L'intitulé reste en retrait : ce qui compte est le
 * contenu, et un titre en gras de deux centimètres le disputerait à ce qu'il présente.
 */
.panel-title {
    display: flex;
    align-items: center;
    gap: var(--app-space-xs);
    margin: 0;
    padding-bottom: var(--app-space-sm);
    border-bottom: 1px solid var(--app-line);
    font-size: var(--app-text-sm);
    font-weight: var(--app-weight-semibold);
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--app-ink-muted);
}

/* Le dessin est la seule couleur de la ligne, et le seul repère qui distingue un cadre d'un
   autre au coup d'œil. Sa taille se relève : le texte est celui d'un intitulé, et une icône à
   sa mesure disparaîtrait. */
.panel-title-icon {
    display: inline-flex;
    flex: 0 0 auto;
    font-size: var(--app-text-lg);
    color: var(--app-accent);
}

/* ═══ Les pages d'un seul formulaire ═══════════════════════════════════════════════════ */

/*
 * Créer un projet, le renommer : une page, un champ. Le paquet a une charpente pour ça — la
 * colonne étroite et centrée — mais un menu latéral l'emporte sur elle, et c'est bien ainsi :
 * la navigation ne disparaît pas parce qu'on remplit un champ. La carte garde donc sa largeur
 * de lecture par elle-même, avec la mesure du paquet plutôt qu'une valeur inventée.
 */
.form-page {
    max-width: var(--app-content-narrow);
}

