/*
 * La recherche : le champ de la barre du haut, le panneau qu'il ouvre, et la page où les mêmes
 * réponses tiennent en entier.
 *
 * Une seule mise en forme pour les deux : `.search-results` est rendu tel quel sous le champ et
 * dans la carte de la page. Ce qui ne vaut que pour le panneau flottant — sa hauteur, son ombre —
 * est écrit sous `.search-panel`, et la page n'en hérite pas.
 *
 * Rien n'est écrit en dur : chaque couleur, chaque espacement et chaque rayon vient d'un alias du
 * design system, ce qui fait suivre les palettes sans une règle de plus.
 */

/* ═══ Le champ, dans la barre ══════════════════════════════════════════════════════════ */

/*
 * Le champ et le bouton de création tiennent ensemble au milieu de la barre, dans la colonne que
 * la grille de l'en-tête leur réserve.
 *
 * La largeur suit celle de l'écran jusqu'à une largeur de lecture, puis s'arrête : un champ aussi
 * large que la page ferait courir l'œil du curseur à sa première réponse.
 */
.search-bar {
    /* La mesure commune du champ et du bouton : deux formes voisines ne s'alignent l'une sur
       l'autre qu'en la partageant, et la régler ici les fait grandir ensemble. */
    --search-height: calc(var(--app-space-2xl) + var(--app-space-sm));

    display: flex;
    align-items: center;
    gap: var(--app-space-sm);
    width: clamp(18rem, 40vw, 34rem);
}

.search {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
}

.search-form {
    display: flex;
    align-items: center;
}

/*
 * Le voile qui met la recherche en avant : le reste de l'écran s'éteint le temps qu'on cherche.
 *
 * Il vit dans la barre du haut, laquelle est déjà posée au-dessus de la page : il couvre donc
 * tout ce qui défile dessous, menu latéral compris, sans avoir à inventer un étage.
 *
 * Fermé, il est **invisible et non seulement transparent** : transparent, il continuerait
 * d'attraper les clics de toute la page.
 */
.search-veil {
    position: fixed;
    inset: 0;
    z-index: 1;
    background: var(--app-backdrop);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--app-speed) var(--app-ease), visibility var(--app-speed);
}

.search[data-open] .search-veil {
    opacity: 1;
    visibility: visible;
}

/*
 * Ce que le voile ne couvre pas : le champ, son bouton, et les réponses. Tout le reste passe
 * dessous — le titre de la page comme le compte —, faute de quoi la barre du haut serait à
 * moitié éteinte et à moitié allumée, sans que rien ne dise pourquoi.
 */
.search-form,
.search-add {
    position: relative;
    z-index: 2;
}

/*
 * La loupe se pose dans le champ plutôt qu'à côté : elle dit ce qu'on peut y faire, et une icône
 * posée dehors aurait pris la largeur qui manque au texte tapé.
 */
.search-icon {
    position: absolute;
    left: var(--app-space-md);
    /* Centrée sur la hauteur du champ, et non posée là où le flux l'aurait laissée : le champ
       grandit avec le texte du lecteur, la loupe doit suivre. */
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    font-size: var(--app-text-lg);
    color: var(--app-ink-muted);
    pointer-events: none;
}

.search-field {
    flex: 1;
    min-width: 0;
    height: var(--search-height);
    padding: 0 var(--app-space-md);
    /* La place de la loupe, et son écart de chaque côté : le texte tapé commence après elle. */
    padding-left: calc(var(--app-space-md) * 2 + var(--app-text-lg));
    border: 1px solid var(--app-line-control);
    border-radius: var(--app-radius-pill);
    background: var(--app-surface);
    color: var(--app-ink);
    font: inherit;
    font-size: var(--app-text);
}

.search-field:focus-visible {
    outline: none;
    border-color: var(--app-accent);
    box-shadow: var(--app-shadow-focus);
}

/*
 * Le bouton qui ouvre ce qu'on peut créer : rond, de la taille du champ, et sans texte — son
 * étiquette accessible le nomme, et le dessin suffit à le reconnaître.
 *
 * Cerclé et non plein : il vit à côté du champ, pas au bout d'un formulaire. Un rond de couleur
 * pleine dans la barre du haut serait le point le plus appuyé de l'écran, pour un geste qu'on
 * fait moins souvent que de chercher.
 */
.search-add-button {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: var(--search-height);
    height: var(--search-height);
    border: 1px solid var(--app-line-control);
    border-radius: var(--app-radius-pill);
    background: var(--app-surface);
    color: var(--app-ink);
    font-size: var(--app-text-lg);
    cursor: pointer;
}

.search-add-button:hover {
    background: var(--app-hover);
}

/* Le dessin est centré par sa boîte, et non par sa ligne de texte : sans cela, le trait
   horizontal du plus tombe un cheveu sous le milieu du cercle. */
.search-add-icon {
    display: flex;
}

/*
 * Les dessins des entrées du menu, pour la même raison et avec le même remède.
 *
 * Laissée en bloc ordinaire, la boîte du dessin prend la hauteur de la LIGNE — vingt-trois
 * pixels pour un dessin de quinze — et le dessin s'y pose sur la ligne de base du texte, donc
 * deux pixels au-dessus du milieu du mot qu'il accompagne. Sept entrées, sept décalages, et une
 * colonne qui tremble à la lecture.
 *
 * `flex` supprime la ligne de base : la boîte épouse le dessin, et c'est l'alignement du menu
 * qui la centre sur le mot.
 */
.search-add .app-menu-item > [data-controller="icon"] {
    display: flex;
    flex: 0 0 auto;
    color: var(--app-ink-muted);
}

/* ═══ Le panneau qui flotte sous le champ ══════════════════════════════════════════════ */

/*
 * Centré sous le champ, et non accroché à l'un de ses bords : il est plus large que lui, et
 * déborder également des deux côtés le laisse là où l'œil vient de lire — sous le curseur.
 */
.search-panel {
    position: absolute;
    top: calc(100% + var(--app-space-xs));
    left: 50%;
    transform: translateX(-50%);
    z-index: var(--app-z-dropdown);
    width: max(100%, 42rem);
    max-width: calc(100vw - var(--app-space-lg) * 2);
    background: var(--app-surface);
    border: 1px solid var(--app-line);
    border-radius: var(--app-radius);
    box-shadow: var(--app-shadow-pop);
    overflow: hidden;
}

/* ═══ Les deux colonnes ════════════════════════════════════════════════════════════════ */

.search-results {
    display: grid;
    grid-template-columns: minmax(0, 13rem) minmax(0, 1fr);
}

/* Les familles, le long du bord gauche. Un filet les sépare des réponses : ce sont deux listes,
   et non une liste à deux niveaux. */
.search-categories {
    display: flex;
    flex-direction: column;
    gap: var(--app-space-2xs);
    padding: var(--app-space-xs);
    border-right: 1px solid var(--app-line);
    background: var(--app-bg);
}

.search-category {
    display: flex;
    align-items: center;
    gap: var(--app-space-sm);
    padding: var(--app-space-sm) var(--app-space-md);
    border-radius: var(--app-radius-ui);
    color: var(--app-ink-soft);
    font-size: var(--app-text);
    text-decoration: none;
}

/* Le fond dit le survol ; un soulignement le dirait une seconde fois, et ferait sauter la
   ligne d'un pixel là où l'œil suit une colonne. */
.search-category:hover {
    background: var(--app-hover);
    color: var(--app-ink);
    text-decoration: none;
}

/* La famille regardée : l'état est celui qu'un lecteur d'écran lit déjà, la teinte ne fait que
   le doubler pour l'œil. */
.search-category[aria-current="page"] {
    background: var(--app-accent-soft);
    color: var(--app-accent-ink);
    font-weight: var(--app-weight-medium);
}

.search-category-icon {
    display: flex;
    flex: 0 0 auto;
    font-size: var(--app-text-lg);
    color: var(--app-ink-muted);
}

.search-category[aria-current="page"] .search-category-icon {
    color: inherit;
}

/* L'intitulé prend la place qui reste et se replie sur deux lignes s'il le faut : le décompte,
   lui, ne bouge pas de la fin de la ligne — c'est une colonne de nombres qu'on parcourt. */
.search-category-label {
    flex: 1;
    min-width: 0;
}

/*
 * Ce que la famille porte en tout. En chiffres tabulaires : sans cela, les nombres d'une ligne
 * à l'autre ne s'alignent pas, chaque chiffre ayant sa propre largeur.
 */
.search-category-count {
    flex: 0 0 auto;
    font-size: var(--app-text-sm);
    font-variant-numeric: tabular-nums;
    color: var(--app-ink-muted);
}

.search-category[aria-current="page"] .search-category-count {
    color: inherit;
}

/* Les familles où rien n'a été cherché, sous celles qui l'ont été. */
.search-refused {
    margin: var(--app-space-xs) 0 0;
    padding: var(--app-space-xs);
    font-size: var(--app-text-sm);
    color: var(--app-ink-muted);
}

/* ═══ Les réponses ═════════════════════════════════════════════════════════════════════ */

.search-hits {
    padding: var(--app-space-xs);
}

/* Le panneau se retire aux bords, et la page aussi : ce qui s'affiche à la place des deux
   colonnes n'a pas leur filet pour le tenir. */
.search-nothing {
    padding: var(--app-space-lg);
}

/* Le panneau ne grandit pas sans fin : passé sa hauteur, les réponses défilent, et la barre du
   haut reste où elle est. La page, elle, n'a pas de plafond — c'est ce pour quoi on l'ouvre. */
.search-panel .search-hits {
    max-height: min(30rem, 66vh);
    overflow-y: auto;
}

.search-group + .search-group {
    margin-top: var(--app-space-sm);
}

.search-group-title {
    margin: 0;
    padding: var(--app-space-xs) var(--app-space-md);
    font-size: var(--app-text-xs);
    font-weight: var(--app-weight-semibold);
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--app-ink-muted);
}

.search-hit {
    display: flex;
    align-items: center;
    gap: var(--app-space-md);
    padding: var(--app-space-sm) var(--app-space-md);
    border-radius: var(--app-radius-ui);
    color: var(--app-ink);
    text-decoration: none;
}

/*
 * Le survol et la réponse désignée au clavier se peignent pareil, et c'est voulu : ce sont deux
 * façons de dire la même chose — c'est celle-là qui s'ouvrira.
 */
.search-hit:hover,
.search-hit[data-active] {
    background: var(--app-hover);
    text-decoration: none;
}

.search-hit-icon {
    display: flex;
    flex: 0 0 auto;
    font-size: var(--app-text-lg);
    color: var(--app-ink-muted);
}

.search-hit-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: var(--app-leading-tight);
}

.search-hit-title {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--app-text);
}

/* Ce qui situe la réponse — le projet qui la porte, la liste où elle vit, sa référence. En
   dessous et en plus discret : on la lit après avoir reconnu le titre, ou pas du tout. */
.search-hit-subtitle {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--app-text-sm);
    color: var(--app-ink-muted);
}

/*
 * Ce qu'un groupe ne montre pas, sous ses lignes. Aligné sur elles et non centré : c'est la
 * suite de la liste, pas un pied de page.
 */
.search-group-more,
.search-group-capped {
    display: block;
    margin: 0;
    padding: var(--app-space-xs) var(--app-space-md);
    font-size: var(--app-text-sm);
    color: var(--app-ink-muted);
}

.search-group-more {
    border-radius: var(--app-radius-ui);
    color: var(--app-accent);
}

.search-group-more:hover {
    background: var(--app-hover);
    text-decoration: none;
}

/* L'espace n'est nommé que lorsque l'écran en montre plusieurs, et il se range au bout de la
   ligne : c'est ce qui distingue deux réponses de même nom, pas ce qui les présente. */
.search-hit-workspace {
    margin-left: auto;
    flex: 0 0 auto;
}

/* Le lien vers la page entière, sous les deux colonnes : il appartient à la réponse tout
   entière, pas à l'une de ses familles. */
.search-more {
    grid-column: 1 / -1;
    padding: var(--app-space-sm) var(--app-space-md);
    border-top: 1px solid var(--app-line);
    background: var(--app-bg);
    color: var(--app-ink-soft);
    font-size: var(--app-text-sm);
    text-align: center;
    text-decoration: none;
}

.search-more:hover {
    background: var(--app-hover);
    color: var(--app-ink);
    text-decoration: none;
}

/* ═══ La page des résultats ════════════════════════════════════════════════════════════ */

/*
 * La carte laisse les deux colonnes toucher ses bords : le filet qui les sépare doit courir d'un
 * bout à l'autre, et un retrait l'aurait laissé flotter au milieu.
 */
.search-page {
    padding: 0;
    overflow: hidden;
}

/* ═══ Sur un écran étroit ══════════════════════════════════════════════════════════════ */

/*
 * Les familles passent au-dessus des réponses et défilent de côté : en colonne, elles auraient
 * pris la moitié de la largeur d'un téléphone pour ne montrer que des étiquettes.
 */
@media (max-width: 48em) {
    /* Il n'y a plus de milieu à tenir : le champ prend ce que le titre et le compte lui
       laissent, au lieu d'une largeur qu'ils n'ont plus à lui accorder. */
    .search-bar {
        width: auto;
        flex: 1 1 auto;
        min-width: 0;
    }

    .search-results {
        grid-template-columns: minmax(0, 1fr);
    }

    .search-categories {
        flex-direction: row;
        overflow-x: auto;
        border-right: 0;
        border-bottom: 1px solid var(--app-line);
    }

    .search-category {
        flex: 0 0 auto;
    }

    /*
     * Le panneau se règle sur la barre du haut, et non plus sur le champ : centré sous un champ
     * étroit, il déborderait du bord gauche — là où commencent les intitulés qu'on vient
     * chercher. La barre étant collée en haut, elle est déjà positionnée : il suffit que le
     * champ cesse de l'être pour qu'elle devienne la référence.
     */
    .search {
        position: static;
    }

    .search-panel {
        top: 100%;
        left: var(--app-space-sm);
        right: var(--app-space-sm);
        width: auto;
        max-width: none;
        transform: none;
    }
}
