/* Product listing density: compact controls and higher offer volume. */
.public-product-list-page {
    --hp-offer-card-min: 142px;
}

.public-product-list-page .public-catalog-shell {
    padding-top: 2px;
}

.public-product-list-hero {
    min-height: 34px;
    padding: 0 0 4px;
}

.public-product-list-hero h1 {
    font-size: clamp(1.42rem, 6.8vw, 2.05rem);
    line-height: .92;
}

.public-product-list-count {
    display: inline-flex;
    min-height: 28px;
    flex: 0 0 auto;
    align-items: center;
    padding: 0 10px;
    border: 1px solid var(--hp-border-strong);
    border-radius: 999px;
    background: rgba(255, 253, 247, .92);
    color: var(--hp-green);
    font-size: 0.7rem;
    font-weight: 700;
    line-height: 1;
}

/* LA BOITE DES RAYONS N'EST PLUS UNE BOITE.
 *
 * Elle portait bordure, fond et ombre autour d'une rangee de pastilles qui
 * portent DEJA bordure et fond : deux cadres emboites pour un seul reglage.
 * Julien : « plus jeune, plus moderne ». Ce qui se voit, ce sont les
 * pastilles ; le cadre autour ne fait que les enfermer. */
.public-product-list-page .public-catalog-navigation {
    gap: 5px;
    margin: 0 0 8px;
    padding: 0;
    border: 0;
    background: transparent;
    box-shadow: none;
}

.public-product-list-page .public-catalog-filters {
    --catalog-filter-margin: 0;
    --catalog-filter-padding: 0;
    --catalog-filter-border: transparent;
    --catalog-filter-radius: 0;
    --catalog-filter-bg: transparent;
    --catalog-filter-shadow: none;
    --catalog-filter-label-gap: 0;
    --catalog-filter-control-height: var(--tap-size);
    --catalog-filter-control-radius: 14px;
    --catalog-filter-control-size: .72rem;
    --catalog-action-height: var(--tap-size);
    --catalog-action-radius: 13px;
    --catalog-action-size: .66rem;
    grid-template-columns: minmax(0, 1fr) 54px;
    grid-template-areas: "search submit";
}

.public-product-list-page .public-catalog-filters.catalog-filter-form--has-departments {
    grid-template-columns: minmax(0, 1fr) 54px;
    grid-template-areas:
        "search submit"
        "department department";
}

.public-product-list-page .public-catalog-filters label > span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

.public-product-list-page .public-catalog-filters .catalog-filter-form__field--department {
    display: grid;
}

.public-product-list-page .public-catalog-filters select {
    height: var(--tap-size);
    padding-inline: 11px 32px;
    border-radius: 12px;
    font-size: 0.7rem;
    font-weight: 700;
}

.public-product-list-page .public-catalog-filters input {
    padding-inline: 12px;
    box-shadow: inset 0 0 0 1px rgba(255, 253, 247, .74);
}

.public-product-list-page .public-catalog-filters .catalog-filter-form__submit {
    width: 54px;
    min-width: 54px;
    padding-inline: 0;
}

.public-product-list-page .public-catalog-filters .catalog-filter-form__submit .ui-icon {
    display: none;
}

.public-product-list-page .public-catalog-filters .catalog-filter-form__submit span {
    display: inline;
}

.public-product-list-page .public-catalog-nav {
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    gap: 4px;
}

/* LE RAIL DES RAYONS EST LA COMMANDE DE RAYON, A TOUTES LES LARGEURS.
 *
 * Il etait masque sous 640px, ou un select « Tous les rayons » prenait le
 * relais dans le formulaire de filtre. Deux commandes pour un meme reglage,
 * chacune sur sa moitie de l'echelle des largeurs — et le formulaire tout
 * entier redessinait par ailleurs la recherche de l'en-tete.
 *
 * Le formulaire ne se rend plus que sur une recherche active. Le rail devient
 * donc la commande unique : une seule mecanique a tenir, et chaque pastille
 * porte son compte d'offres, ce que le select ne faisait pas.
 *
 * IL DEFILE HORIZONTALEMENT, A TOUTES LES LARGEURS. Onze rayons qui
 * s'enroulent coutent quatre rangees au pouce — plus que le select qu'ils
 * remplacent — et deux rangees sur un ecran large, ce que Julien a vu et
 * nomme. Un rail qui defile n'a qu'une hauteur, quel que soit le nombre de
 * rayons du catalogue.
 *
 * ET LE LIBELLE « RAYONS » NE PREND PLUS SA PROPRE LIGNE : deux etages pour
 * une commande qui en vaut un. Il passe a gauche, sur la meme ligne, et le
 * rail prend tout ce qui reste. */
.public-product-list-page .public-catalog-nav__group--departments {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    column-gap: 7px;
}

.public-product-list-page .public-catalog-nav__group {
    gap: 4px;
}

.public-product-list-page .public-catalog-nav__label {
    padding-left: 1px;
    font-size: 0.7rem;
    line-height: 1;
}

.public-product-list-page .public-catalog-nav__rail {
    flex-wrap: nowrap;
    gap: 4px;
    overflow-x: auto;
    overscroll-behavior-inline: contain;
}

.public-product-list-page .public-catalog-nav__group--shortcuts .public-catalog-nav__rail {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

/* LA VRAIE CAUSE DE LA TRONCATURE, ET ELLE N'ETAIT PAS DANS LE LIBELLE.
 *
 * `flex: 0 1 auto` rend la pastille RETRECISSABLE. Dans un rail `nowrap`, un
 * navigateur prefere toujours retrecir ses elements plutot que deborder :
 * onze rayons dans 335 pixels, et chaque pastille etait comprimee sous sa
 * largeur naturelle. Le `text-overflow: ellipsis` qui suivait ne creait pas la
 * coupe, il la CACHAIT — et le rail ne defilait jamais, puisqu'il n'y avait
 * plus rien qui depassait.
 *
 * `flex: 0 0 auto` : chaque pastille garde sa largeur, la rangee deborde, et
 * c'est le rail qui absorbe — ce pour quoi il porte `overflow-x: auto`. */
.public-product-list-page .public-catalog-nav__chip,
.public-product-list-page .public-catalog-nav__shortcut {
    min-width: var(--tap-size);
    min-height: var(--tap-size);
    flex: 0 0 auto;
    font-size: 14px;
}

/* AUCUN LIBELLE DE RAYON NE SE FAIT RABOTER.
 *
 * `overflow: hidden` + `text-overflow: ellipsis` coupaient la pastille
 * lorsqu'elle manquait de place. Elles ne manquent plus de place — le libelle
 * est court a la source — et si un rayon arrive sans libelle court, il doit se
 * voir ENTIER : le rail defile, c'est lui qui absorbe la longueur.
 * apps/core/test_libelles_de_rayon.py le mesure au navigateur. */
.public-product-list-page .public-catalog-nav__chip span,
.public-product-list-page .public-catalog-nav__shortcut span {
    min-width: 0;
}

.public-product-list-page .public-catalog-nav__chip {
    padding: 0 6px 0 9px;
}

.public-product-list-page .public-catalog-nav__shortcut {
    gap: 3px;
    padding: 0 5px;
}

.public-product-list-page .public-catalog-nav__chip strong {
    min-width: 18px;
    min-height: 18px;
    padding: 0 4px;
    font-size: 0.7rem;
}

.public-product-list-page .public-catalog-results {
    gap: 5px;
}

.public-product-list-page .public-offer-grid {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--hp-offer-card-min)), 1fr));
    gap: 6px;
}

.public-product-list-page .public-offer-card {
    border-radius: 11px;
    box-shadow: 0 8px 18px rgba(27, 29, 24, .045);
}

.public-product-list-page .public-offer-card__media img {
    aspect-ratio: 16 / 7.25;
}

/* LE BADGE NE COUPE PLUS, ET IL N'A PLUS DE QUOI COUPER.
 *
 * `text-overflow: ellipsis` sur `max-width: calc(100% - 10px)` rendait
 * « Cremerie et produits laiti… » et « Oeufs, viandes et charcute… ». Les
 * points de suspension n'etaient pas la maladie : ils etaient le symptome
 * d'un nom d'administration pose dans une pastille de 130 pixels.
 *
 * Le libelle est court a la source (apps/catalog/models.py), donc la coupe
 * n'a plus lieu d'etre — et on la retire, pour qu'un rayon absent du registre
 * se voie ENTIER plutot que de se faire raboter en silence. Le seul repli est
 * le retour a la ligne. */
.public-product-list-page .public-offer-card__media span {
    top: 5px;
    left: 5px;
    max-width: calc(100% - 10px);
    padding: 3px 6px;
    font-size: 0.7rem;
    line-height: 1.15;
}

.public-product-list-page .public-offer-card__body {
    gap: 3px;
    padding: 6px 6px 5px;
}

.public-product-list-page .public-offer-card__title {
    min-height: var(--tap-size);
    /* La page produits reserrait encore le titre sous la mesure commune. Elle
       reprend la meme : c'est le nom du produit, la page ne peut pas le dire
       plus bas que les autres. */
    font-size: 16px;
    line-height: 1.2;
}

.public-product-list-page .public-offer-card__producer {
    overflow: hidden;
    font-size: 14px;
    line-height: 1.15;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ==========================================================================
 * LE PRIX ET LE LIEU — DEUX INFORMATIONS, PLUS DEUX BOITES
 *
 * Julien : « prix et ville en double boite grise -> alleger : prix en fort,
 * ville avec sa pastille de lieu, pas de boites ».
 *
 * Deux rectangles gris de meme graisse ne disent pas ce qu'ils portent : il
 * fallait les LIRE pour savoir lequel etait le prix. La boite ne hierarchise
 * rien, elle ajoute seulement deux blocs de couleur dans une carte qui en a
 * deja trois — l'image, le badge, le bouton.
 *
 * La hierarchie passe donc dans le texte : le prix porte la graisse et
 * l'encre pleine, le lieu passe en retrait derriere sa pastille.
 * ========================================================================== */
.public-product-list-page .public-offer-card__meta {
    grid-template-columns: auto minmax(0, 1fr);
    align-items: baseline;
    gap: 4px 8px;
}

.public-product-list-page .public-offer-card__meta div {
    padding: 0;
    border-radius: 0;
    background: transparent;
}

.public-product-list-page .public-offer-card__meta div:nth-child(3) {
    display: none;
}

.public-product-list-page .public-offer-card__meta dd {
    font-size: 14px;
}

.public-product-list-page .public-offer-card__price dd {
    color: var(--hp-ink);
    /* Le prix decide l'achat : il se lit d'un coup d'oeil, pas a la loupe. */
    font-size: 16px;
    font-weight: 700;
}

/* La pastille de lieu et sa ville tiennent la meme ligne de base. Le `dt`
   « Lieu » reste dans le balisage — masque par listing.css — parce qu'un
   pictogramme ne se lit pas a voix haute. */
.public-product-list-page .public-offer-card__place {
    display: flex;
    min-width: 0;
    align-items: center;
    gap: 3px;
    color: var(--hp-muted);
}

.public-product-list-page .public-offer-card__place dd {
    min-width: 0;
    overflow: hidden;
    color: var(--hp-muted);
    font-weight: 600;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.public-product-list-page .public-offer-card__place .ui-icon {
    width: 12px;
    height: 12px;
    flex: 0 0 auto;
}

@media (min-width: 640px) {
    .public-product-list-page {
        --hp-offer-card-min: 150px;
    }

    .public-product-list-page .public-catalog-shell {
        padding-top: 4px;
    }

    /* LA COLONNE DE GAUCHE N'EXISTE QUE S'IL Y A UN FORMULAIRE A Y METTRE.
     *
     * Cette grille etait posee sans condition, et le formulaire de recherche
     * ne se rend QUE sur une recherche active. Sans recherche, le rail des
     * rayons se retrouvait donc dans une colonne de `.52fr` — la moitie de
     * l'ecran — avec du vide a sa droite, et il s'enroulait sur deux rangees.
     * C'est la « boite RAYONS sur deux rangees » de la capture : pas une
     * question de nombre de rayons, une colonne fantome. */
    .public-product-list-page .public-catalog-navigation:has(.public-catalog-filters) {
        grid-template-columns: minmax(280px, .52fr) minmax(0, 1fr);
        align-items: center;
        gap: 8px;
    }

    .public-product-list-page .public-catalog-nav {
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: end;
        gap: 8px;
    }

    .public-product-list-page .public-catalog-nav__group--shortcuts .public-catalog-nav__rail {
        display: flex;
    }

    .public-product-list-page .public-catalog-nav__group--shortcuts {
        min-width: auto;
    }

    .public-product-list-page .public-offer-grid {
        gap: 7px;
    }

}

/* `(hover: hover)` ET PLUS SEULEMENT UNE LARGEUR. Ce masquage repose sur la
   pastille « Voir » du visuel, qui ne se leve qu'au survol : sur une tablette
   large, il retirait le bouton nomme SANS que rien ne le remplace. */
@media (min-width: 640px) and (hover: hover) {
    .public-product-list-page .public-offer-card__actions {
        display: none;
    }
}

@media (min-width: 980px) {
    .public-product-list-page {
        --hp-offer-card-min: 158px;
    }

    .public-product-list-hero {
        min-height: 40px;
    }

    .public-product-list-hero h1 {
        font-size: clamp(1.9rem, 2.4vw, 2.5rem);
    }

    /* Meme condition qu'a 640 : pas de colonne pour un formulaire absent. */
    .public-product-list-page .public-catalog-navigation:has(.public-catalog-filters) {
        grid-template-columns: minmax(360px, .38fr) minmax(0, 1fr);
    }

    .public-product-list-page .public-catalog-navigation {
        margin-bottom: 9px;
    }
}

/* Product catalogue sections: ecommerce rails, proximity first. */
.public-product-section-stack {
    display: grid;
    gap: 18px;
}

.public-product-section {
    display: grid;
    min-width: 0;
    gap: 8px;
}

.public-product-section__header {
    display: flex;
    min-width: 0;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.public-product-section__header h2 {
    margin: 0;
    color: var(--hp-green);
    font-size: clamp(1.08rem, 5.8vw, 1.55rem);
    font-weight: 700;
    line-height: 1;
}

.public-product-section__header a {
    display: inline-flex;
    min-width: var(--tap-size);
    min-height: var(--tap-size);
    flex: 0 0 auto;
    align-items: center;
    gap: 3px;
    color: var(--hp-orange);
    font-size: 0.7rem;
    font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
}

/* ==========================================================================
 * LE RAIL EN EST ENFIN UN — UNE RANGEE, JAMAIS DEUX
 *
 * Julien : « carte orpheline seule en deuxieme rangee -> grille equilibree ».
 *
 * La cause n'est pas reparable en repartissant mieux : une grille a deux
 * colonnes remplie par un nombre QUELCONQUE de cartes laisse un orphelin des
 * que ce nombre est impair. Un rayon a trois offres, un autre en a cinq, un
 * autre une seule — aucun reglage de colonnes ne rend ca equilibre, et le
 * serveur ne sait pas combien de colonnes le navigateur posera.
 *
 * Une RANGEE ne peut pas etre desequilibree : il n'y a pas de seconde ligne
 * ou laisser quelqu'un seul. Une carte ou huit, la section a la meme forme et
 * la meme hauteur. C'est aussi ce que le nom de la classe annonçait depuis le
 * debut, et c'est la forme e-commerce que le pouce attend.
 *
 * La largeur de carte est fixe et non `1fr` : `1fr` rendrait une carte unique
 * large de toute la section, ce qui est exactement l'air d'un orphelin. */
.public-product-section__rail {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 46%;
    gap: 7px;
    min-width: 0;
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    scrollbar-width: none;
    padding: 1px 0 4px;
}

.public-product-section__rail::-webkit-scrollbar {
    display: none;
}

/* LA SECTION QUI EST LA LISTE SE REND EN GRILLE.
   Le rail est un echantillon qu'on fait defiler ; une fois le rayon demande,
   la page porte toutes ses offres et elles se parcourent du regard, pas au
   doigt. `auto-fill` avec `min(100%, …)` laisse le navigateur poser le nombre
   de colonnes : une seule sur un telephone etroit, autant que la place le
   permet ensuite. */
.public-product-section__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 146px), 1fr));
    gap: 7px;
    min-width: 0;
    padding: 1px 0 4px;
}

.public-product-section__item {
    min-width: 0;
}

.public-product-list-page .public-product-section .public-offer-card {
    position: relative;
    height: 100%;
    grid-template-rows: auto 1fr;
}

.public-product-list-page .public-product-section .public-offer-card__media img {
    aspect-ratio: 4 / 3;
}

.public-product-list-page .public-product-section .public-offer-card__body {
    padding-bottom: calc(var(--tap-size) + 7px);
}

.public-product-list-page .public-product-section .public-offer-card__actions {
    position: absolute;
    right: 7px;
    bottom: 7px;
    display: block;
    padding: 0;
}

.public-product-list-page .public-product-section .public-offer-card__action button,
.public-product-list-page .public-product-section .public-offer-card__booking-action {
    position: relative;
    width: var(--tap-size);
    min-width: var(--tap-size);
    height: var(--tap-size);
    min-height: var(--tap-size);
    padding: 0;
    border: 1px solid rgba(200, 97, 56, .58);
    border-radius: 999px;
    background: rgba(255, 253, 247, .96);
    color: var(--hp-orange);
    box-shadow: 0 8px 18px rgba(27, 29, 24, .08);
}

/* ==========================================================================
 * L'ACTION DE CARTE : UN PICTOGRAMME DU REGISTRE, PAS UN CARACTERE
 *
 * Julien : « actions de carte incoherentes : "›" sur certaines, "+" sur
 * d'autres. UNE logique unique. »
 *
 * Ces deux signes etaient poses ICI, en `content:` — un chevron typographique
 * et un plus, deux caracteres d'une police de texte, a deux graisses et deux
 * corps differents — pendant que la VRAIE icone du gabarit etait masquee juste
 * en dessous. Le dessin du bouton vivait donc dans la feuille, hors du
 * registre, invisible a qui lit le gabarit. Rien ne pouvait les tenir
 * coherents : personne ne les voyait ensemble.
 *
 * Le registre reprend la main. La regle tient en une phrase, et elle est
 * ecrite dans le gabarit, la ou on choisit le geste : le PANIER quand le geste
 * touche au panier, la FLECHE quand il ouvre l'offre. Meme trait, meme
 * graisse, meme taille — c'est ce qui fait qu'une rangee de cartes se lit
 * comme un seul systeme.
 *
 * Le NOM reste masque : le bouton est rond et large de 44px, il n'a pas la
 * place d'un mot. Il n'est pas perdu pour autant — chaque bouton porte son
 * `aria-label` complet, avec le titre de l'offre.
 * ========================================================================== */
.public-product-list-page .public-product-section .public-offer-card__action .ui-icon {
    width: 20px;
    height: 20px;
}

/* `span:not(.ui-icon)` ET PAS `span`. LE REGISTRE REND SON PICTOGRAMME DANS UN
   `<span class="ui-icon">` : masquer « tout span » masquait donc AUSSI l'icone,
   avec une specificite superieure a la regle qui la dimensionne juste au-dessus.
   Resultat : trois pastilles rondes parfaitement vides, un bouton sans
   affordance — et rien dans le balisage ne le disait, l'`aria-label` etait
   toujours la. Seule une capture l'a montre. */
.public-product-list-page .public-product-section .public-offer-card__action span:not(.ui-icon) {
    display: none;
}

.public-product-radius-nav {
    display: flex;
    min-width: 0;
    flex-wrap: wrap;
    gap: 5px;
    overflow: visible;
}

.public-product-radius-nav__chip {
    display: inline-flex;
    /* 30px : une commande de filtre se rate au pouce sous 44. */
    min-height: var(--tap-size);
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 0 10px;
    border: 1px solid var(--hp-border-strong);
    border-radius: 999px;
    background: var(--hp-surface);
    color: var(--hp-green);
    font-size: 0.7rem;
    font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
}

.public-product-radius-nav__chip.is-active {
    border-color: rgba(36, 90, 59, .42);
    background: var(--hp-green);
    color: var(--hp-surface);
}

@media (min-width: 640px) {
    /* Meme rangee, cartes a leur largeur nominale : la place ne manque plus,
       elle sert a en montrer davantage, pas a en etirer trois. */
    .public-product-section__rail {
        grid-auto-columns: 150px;
        gap: 8px;
    }

    .public-product-section__grid {
        grid-template-columns: repeat(auto-fill, minmax(min(100%, 150px), 1fr));
        gap: 8px;
    }

    .public-product-section__header h2 {
        font-size: clamp(1.15rem, 2.6vw, 1.55rem);
    }

    .public-product-list-page .public-catalog-filters {
        grid-column: 1;
    }

    .public-product-radius-nav {
        grid-column: 2;
        align-self: center;
        justify-self: start;
    }

    .public-product-list-page .public-catalog-nav {
        grid-column: 1 / -1;
    }
}

@media (min-width: 980px) {
    .public-product-section-stack {
        gap: 22px;
    }

    .public-product-section__grid {
        grid-template-columns: repeat(auto-fill, minmax(min(100%, 158px), 1fr));
        gap: 22px;
    }

    .public-product-section__rail {
        grid-auto-columns: 158px;
        padding-bottom: 0;
    }

    .public-product-section__header a {
        font-size: 0.7rem;
    }
}
