/* Page-local accent alias kept (legacy aliases come from design_system) */
:root { --bg: var(--paper-2); }

/* Page header bar */
.page-header-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    background: var(--card-bg);
    border-radius: var(--r-md);
    padding: 14px 20px;
    box-shadow: var(--sh-1);
    gap: 12px;
}
.page-header-bar__title {
    font-size: 1.15rem;
    font-weight: 600;
    margin: 0;
    color: var(--text-primary);
}
.page-header-bar__trail {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Filter bar (.filter-bar / .filter-bar__search / .filter-bar__select /
   .fdd* / .filter-bar__count / .filter-favorites) is now canonical in
   design_system.html. */

/* ══════════════════════════════════════════════════════════════════════
   BARRE DE FILTRES — une seule mise en page (2026-09-08)

   Avant cette date, cette page portait DEUX barres. Au-dessus de 900px,
   #firmFiltersPanel etait `display: contents` et #firmFiltersToggle
   `display: none` : les 7 .fdd s'etalaient dans la barre, qui prenait
   112px sur deux rangees. Sous 900px, l'inverse. Deux mises en page pour
   une seule question, donc deux endroits a verifier a chaque filtre ajoute.

   Desormais le bouton "Filters" existe partout et le panneau aussi. La
   barre tient sur une ligne (environ 56px) et les filtres CHOISIS se lisent
   sous elle, en pastilles retirables (.ds-filter-chips, design_system.html)
   posees par renderFilterChips() depuis la meme liste que le compteur du
   bouton : le badge ne peut pas annoncer un nombre que les pastilles ne
   montrent pas.

   Ce qui depend encore de la largeur, et c'est legitime : la POSITION du
   panneau. Une feuille du bas pleine largeur sur un ecran de 1440px serait
   lourde, un popover de 420px sur un telephone serait a l'etroit. Le
   contenu du panneau, lui, est identique partout.
   ══════════════════════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════════
   Panneau de filtres. La recherche reste visible ; les 7 .fdd +
   #btnFavorites + #filterReset vivent derriere le bouton "Filters"
   (#firmFiltersToggle), A TOUTES LES LARGEURS depuis 2026-09-08.
   Seule la GEOMETRIE du panneau depend encore de la largeur : feuille
   du bas sous 900px (ci-dessous), popover ancre a la barre au-dessus
   (bloc min-width: 901px). Son CONTENU, lui, est le meme partout. */

/* Bouton "Filters" : revele, a cote de la recherche. Pastille de
   comptage (#firmFiltersBadge) geree par cabinets.js — une seule
   source de verite, dans applyFilters(). */
#firmFiltersToggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 44px;
    padding: 0 14px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--white);
    color: var(--ink-500);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: var(--transition);
}
#firmFiltersToggle .material-icons { font-size: 17px; line-height: 1; }
/* Etat ouvert : meme traitement visuel que .fdd.open .fdd-btn
   (design_system.html) — le bouton se distingue par la couleur
   d'accent pendant que son panneau est affiche. */
#firmFiltersToggle[aria-expanded="true"] {
    border-color: var(--accent);
    color: var(--accent);
}
.firm-filters-toggle__badge {
    /* Masquee par defaut (pas de "0" litteral affiche) : classe
       .is-active posee par cabinets.js quand au moins un filtre est
       actif — jamais [hidden], meme motif que le panneau ci-dessous. */
    display: none;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 999px;
    background: var(--accent);
    color: var(--white);
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
}
.firm-filters-toggle__badge.is-active { display: inline-flex; }

/* Panneau : masque par defaut, revele par la classe .open — motif
   canonique .ds-modal-overlay (design_system.html) : display:none puis
   display:<x> sur .open/.show, JAMAIS [hidden] (qui perd contre toute
   regle display d'un ancetre/soi-meme portant une classe — repere 6 fois
   dans ce depot, voir CLAUDE.md).

   La regle de BASE est la ligne DANS la carte, pas la feuille du bas :
   c'est la forme qui ne demande aucun JS. Le panneau est un enfant
   ordinaire de .filter-bar et prend sa propre ligne par flex-basis:100%,
   exactement le mecanisme de .ds-filter-chips (design_system.html) et pas
   une regle nouvelle. La carte grandit a l'ouverture ; plus rien ne flotte
   au-dessus de la page, donc plus rien a positionner ni a recalculer au
   defilement (les ~60 lignes de placeFilterPanel sont parties avec).

   ⚠️ Ce qui rend ce retour possible, et qu'il faut relire avant de
   retoucher : le popover d'avant etait en `position: fixed` parce qu'un
   ancetre a `overflow: hidden` (.community-tabs-block) le rognait. C'est
   un ROGNAGE, qu'aucun z-index ne repare. Un enfant DANS LE FLUX fait
   grandir la boite de son ancetre au lieu de s'y faire couper : le
   probleme n'est pas contourne, il ne se pose plus. Ne jamais repasser
   ce panneau en `position: absolute` sans avoir relu ce paragraphe.

   La feuille du bas vit desormais dans le bloc mobile, plus bas dans ce
   fichier : c'est une vraie difference de largeur (un budget de place au
   doigt), pas un correctif de composant range dans une requete media.
   ⚠️ Ecrit en toutes lettres et pas avec le littoral de la requete : les
   tests de ce depot extraient le bloc mobile en cherchant ce littoral et
   en comptant les accolades a partir de la. Le poser dans un commentaire
   AVANT le vrai bloc leur fait extraire la regle qui suit ce commentaire
   — 60 tests rouges, aucun rapport avec le defaut. Un commentaire compte
   comme du code pour un test qui scanne une source. */
#firmFiltersPanel {
    display: none;
    flex-wrap: wrap;
    align-items: center;
    flex-basis: 100%;
    min-width: 0;
    gap: 10px;
}
#firmFiltersPanel.open { display: flex; }

@media (min-width: 901px) {
    /* Le bouton s'aligne sur la hauteur du champ de recherche qu'il cotoie
       (38px, design_system.html). Les 44px de la regle de base sont un
       plancher TACTILE (S2) : au doigt il les garde, a la souris il n'a
       aucune raison de depasser de 6px le champ d'a cote. C'est bien une
       difference qui depend de la largeur, pas un defaut repare d'un seul
       cote du palier. */
    #firmFiltersToggle { min-height: 38px; }

    /* Un seul "Clear all" a l'ecran. Depuis que le panneau est une ligne de
       la carte (2026-09-11) il n'est plus un popover qui recouvrait la
       ligne de pastilles : les deux boutons se retrouvaient visibles
       ensemble, a 40px l'un de l'autre, pour la meme action.

       C'est celui du PANNEAU qui part, pas celui des pastilles : la ligne de
       pastilles est le lieu des filtres actifs, c'est la qu'on les lit et
       qu'on les retire un par un. Avec un seul filtre pose, le composant ne
       rend pas de "Clear all" (il en faut deux) et la croix de l'unique
       pastille fait le meme travail en un clic.

       ⚠️ `display: none` et pas un retrait : #filterReset RESTE le
       mecanisme. Le "Clear all" des pastilles fait `#filterReset.click()`
       (cabinets.js, opts.onClearAll), et un bouton display:none repond
       parfaitement a un .click() programmatique. C'est la doctrine deja
       posee pour les croix des pastilles — repasser par le controle
       d'origine plutot que dupliquer son effet. Le retirer du gabarit
       casserait le bouton visible. Au doigt il reste affiche : les
       pastilles, elles, sont masquees sous 900px. */
    #firmFiltersPanel #filterReset { display: none; }
}

/* Table.
   One horizontal scroller for the header AND the rows. Kept on .cabinet-list
   alone, the rows scrolled while the header did not, so at 400px of scroll the
   "Practices" label sat above the Links column.
   The name track is minmax(160px, 250px) and not 1fr: the header and the rows
   are two INDEPENDENT grids, so a track whose minimum depends on content
   resolves differently on each (the header cannot shrink below the word
   "FIRM", a row can, since .cabinet-name clips). That alone offset every row
   by 28px. A fixed floor makes both grids compute the same track. The 250px
   ceiling replaced 1fr after user feedback that Firm stretched too wide on
   large screens — no track absorbs the freed space, it's just left as
   trailing padding past the Links column on wide viewports.
   --cab-table-min is the sum of the tracks plus the nine 14px gaps, PLUS the
   32px of horizontal padding and the 2px border: everything here is
   border-box, so a min-width holding only the tracks leaves a content box 34px
   too narrow and the Links column spills past the card. Recompute it when a
   column width, the padding or the border changes.
   The header carries the same transparent 1px border as the rows for that
   arithmetic to hold on both, which also lines their content boxes up to the
   pixel instead of the 1px the border alone used to offset.
   First track went 40px -> 56px when the wishlist button joined the heart in
   that cell: two buttons scaled down to 26px (.cabinet-row-actions .btn--icon)
   + 4px gap = 56px, then 56px -> 86px when the offer-alerts bell joined them
   (three 26px buttons + two 4px gaps). Recompute --cab-table-min by the same
   delta whenever it changes again.
   Links track went 80px -> 114px when the careers-page button joined LinkedIn
   and Website (three 34px buttons + two 6px gaps), then 114px -> 96px when
   they took the admin link-icon look (three 28px tiles + two 6px gaps). */
:root { --cab-table-min: 1455px; }  /* 1421 tracks+gaps + 32 padding + 2 border */

.cabinet-table {
    overflow-x: auto;
    /* rows carry a shadow the scroller would otherwise clip */
    padding-bottom: 4px;
}

/* Header row */
.cabinet-header {
    display: grid;
    grid-template-columns: 86px 48px minmax(160px, 250px) 70px 100px 165px 110px 235px 225px 96px;
    gap: 14px;
    padding: 4px 16px;
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    /* geometry must match .cabinet-row exactly, see --cab-table-min */
    border: 1px solid transparent;
    min-width: var(--cab-table-min);
}

/* Cabinet list */
.cabinet-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* Cabinet row */
.cabinet-row {
    background: var(--card-bg);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 12px 16px;
    display: grid;
    grid-template-columns: 86px 48px minmax(160px, 250px) 70px 100px 165px 110px 235px 225px 96px;
    align-items: center;
    gap: 14px;
    transition: var(--transition);
    border: 1px solid transparent;
    min-width: var(--cab-table-min);
}
.cabinet-row:hover {
    box-shadow: var(--shadow-md);
    border-color: var(--border);
}
.cabinet-row.hidden { display: none; }
/* Au-dela de la page courante sur telephone (cabinets.js, applyPaging).
   Classe distincte de .hidden : .hidden dit "ne correspond pas aux
   filtres", celle-ci "correspond, mais pas encore affiche". */
.cabinet-row.is-paged-out { display: none; }

.cabinet-row-actions {
    display: flex;
    align-items: center;
    gap: 4px;
}
/* Scoped-down icon buttons: the global .btn--icon (34px, design_system.html)
   is too wide for two side by side in a table row — shrink just this pair. */
.cabinet-row-actions .btn--icon {
    width: 26px;
    height: 26px;
}
.cabinet-row-actions .btn--icon .material-icons {
    font-size: 15px;
}

.heart-icon {
    width: 15px;
    height: 15px;
    display: block;
}
.heart-icon .heart-path {
    fill: #ccc;
    transition: fill 0.2s ease;
}
.cabinet-row[data-favorite="true"] .heart-icon .heart-path {
    fill: var(--primary);
}

/* Offer-alerts bell (firm-follow.js): same off/on colours as the wishlist. */
.firm-follow .material-icons {
    color: var(--ink-200);
    transition: color 0.2s ease;
}
.firm-follow[data-following="true"] .material-icons {
    color: var(--primary);
}

.wishlist-btn .material-icons {
    color: #ccc;
    transition: color 0.2s ease;
}
.wishlist-btn[data-in-pipeline="true"] .material-icons {
    color: var(--primary);
}

/* Logo */
.cabinet-logo {
    width: 48px;
    height: 48px;
    border-radius: var(--r-sm);
    background: var(--bg);
    border: 1px solid var(--border);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
.cabinet-logo img { width: 100%; height: 100%; object-fit: contain; }
.cabinet-logo .material-icons { font-size: 24px; color: var(--text-secondary); }

/* Name */
.cabinet-name {
    font-size: 0.88rem;
    font-weight: 600;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Pill columns */
.cabinet-col-ville,
.cabinet-col-type,
.cabinet-col-practices,
.cabinet-col-industries {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    min-width: 0;
}

/* Links column: same tiles as /admin/firms (admin-cabinets.css .link-icon),
   bluish, rounded; greyed when the firm has no such link. */
.cabinet-col-links {
    display: flex;
    align-items: center;
    gap: 6px;
}
.link-icon {
    width: 28px;
    height: 28px;
    border-radius: var(--r-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: var(--transition);
    text-decoration: none;
    flex-shrink: 0;
}
.link-icon.has-link { background: var(--blue-100); color: var(--blue-600); }
.link-icon.has-link:hover { background: var(--blue-200); }
.link-icon.no-link { background: var(--bg); color: var(--ink-300); cursor: default; }
.link-icon svg { width: 14px; height: 14px; flex-shrink: 0; }

/* Pills */
.pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 9px;
    border-radius: 999rem;
    font-size: 0.72rem;
    font-weight: 500;
    white-space: nowrap;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}
.pill .material-icons { font-size: 13px; flex-shrink: 0; }
.pill-bureau   { background: #eff6ff; color: #1d4ed8; }
.pill-type     { background: #fef3c7; color: #92400e; }
.pill-practice { background: #ede9fe; color: #5b21b6; }
.pill-industry { background: #dcfce7; color: #166534; }
.pill-headcount { background: #f1f5f9; color: #475569; }
.pill-offers    { background: #dcfce7; color: #166534; }
.pill-offers .material-icons { font-size: 12px; }
.cabinet-col-offers { display: flex; align-items: center; min-width: 0; }

/* No results */
.no-results {
    display: none;
    text-align: center;
    padding: 40px;
    color: var(--text-secondary);
    font-size: 0.9rem;
}
.no-results.visible { display: block; }

/* Modal overlay — cabinet creation */
.modal-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(10,23,51,.45);
    z-index: 10300;
    align-items: flex-start;
    justify-content: center;
    padding: 40px 16px;
    overflow-y: auto;
}
.modal-overlay.active { display: flex; }
/* Tete collante (2026-09-29, QA mobile) : modale plus haute que l'ecran,
   la croix partait avec le contenu. Chrome et WebKit collent un sticky
   SOUS le padding du conteneur qui defile (le voile, padding 40px) : top negatif pour
   coller au bord, et le padding haut de la boite (28px) repris par la
   tete (marge negative + padding) pour masquer le contenu qui passe
   au-dessus. Au repos, la mise en page ne bouge pas. Aux deux largeurs. */
#cabinetModal .modal > .modal-head {
    position: sticky; top: -40px; z-index: 3;
    background: var(--card-bg);
    margin-top: -28px; padding-top: 28px;
}
.modal {
    background: var(--card-bg);
    border-radius: var(--radius);
    padding: 28px;
    width: 100%;
    max-width: 700px;
    box-shadow: var(--shadow-lg);
    display: flex;
    flex-direction: column;
    gap: 14px;
    margin: auto;
}
/* Drop zone */
.drop-zone {
    border: 2px dashed var(--border);
    border-radius: var(--r-md);
    padding: 20px;
    text-align: center;
    background: var(--bg);
    cursor: pointer;
    transition: var(--transition);
    position: relative;
}
.drop-zone:hover, .drop-zone.drag-over {
    border-color: var(--primary);
    background: var(--accent-soft);
}
.drop-zone input[type="file"] {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
    width: 100%;
    height: 100%;
}
.drop-zone .drop-icon { font-size: 32px; color: var(--text-secondary); display: block; margin-bottom: 6px; }
.drop-zone p { font-size: 0.82rem; color: var(--text-secondary); margin: 0; }
.drop-zone small { font-size: 0.7rem; color: #94a3b8; }
.drop-preview {
    width: 64px;
    height: 64px;
    object-fit: contain;
    border-radius: var(--r-sm);
    margin: 0 auto 6px;
    display: none;
    border: 1px solid var(--border);
}

/* Form elements */
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.form-group { display: flex; flex-direction: column; gap: 5px; }
.form-label {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-secondary);
}
.form-control {
    padding: 9px 12px;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    font-size: 0.85rem;
    font-family: 'Poppins', sans-serif;
    color: var(--text-primary);
    background: var(--bg);
    transition: var(--transition);
    width: 100%;
    box-sizing: border-box;
}
.form-control:focus {
    border-color: var(--primary);
    background: var(--card-bg);
}
textarea.form-control { resize: vertical; min-height: 72px; }
.form-section-title {
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--text-secondary);
    padding-bottom: 8px;
    border-bottom: 1px solid var(--border);
    margin-top: 4px;
}

/* Bureaux tags */
.bureaux-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 6px;
    min-height: 28px;
}
.bureaux-tag {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: #e0f2fe;
    color: #0369a1;
    border-radius: 999rem;
    padding: 2px 10px 2px 8px;
    font-size: 0.78rem;
    font-weight: 500;
}
.bureaux-tag .remove-tag { cursor: pointer; font-size: 0.9rem; opacity: 0.6; line-height: 1; }
.bureaux-tag .remove-tag:hover { opacity: 1; }
.bureaux-autocomplete-list {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: var(--white);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    z-index: 100;
    display: none;
    box-shadow: none;
}
.bureaux-autocomplete-list div { padding: 6px 12px; cursor: pointer; font-size: 0.85rem; }
.bureaux-autocomplete-list div:hover { background: #f1f5f9; }

/* Chips multi-select */
.chips-group {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 4px;
}
.chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px;
    border-radius: 999rem;
    font-size: 0.78rem;
    font-weight: 500;
    cursor: pointer;
    border: 1.5px solid var(--border);
    background: var(--bg);
    color: var(--text-secondary);
    transition: var(--transition);
    user-select: none;
}
.chip.selected {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--white);
}
.chip:hover:not(.selected) { border-color: var(--primary); color: var(--primary); }
.btn-select-all {
    font-size: 0.72rem;
    color: var(--primary);
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    text-decoration: underline;
    opacity: 0.8;
}
.btn-select-all:hover { opacity: 1; }
.add-custom-row {
    display: flex;
    gap: 6px;
    margin-top: 8px;
}
.add-custom-input {
    flex: 1;
    padding: 4px 10px;
    border: 1.5px solid var(--border);
    border-radius: var(--r-md);
    font-size: 0.8rem;
    background: var(--bg);
    color: var(--text-primary);
}
.add-custom-input:focus { border-color: var(--primary); }
/* ── Cabinet rows are clickable (navigate to /cabinets/{id}) ───────────────── */
.cabinet-row { cursor: pointer; }
.cabinet-row .btn { cursor: default; }
.cabinet-row a { cursor: pointer; }

/* ══════════════════════════════════════════════════════════════════════
   MOBILE — sous 900px (phase 3, tache 1). La ligne devient une carte.

   Mesure sur un vrai iPhone (Safari, 402pt de large) avant ce chantier :
   .cabinet-row est une grille a 10 pistes portant min-width:
   var(--cab-table-min) (1409px, voir le commentaire au-dessus de cette
   variable) — seuls le nom du cabinet et la pastille Offers etaient
   visibles, les huit autres pistes existaient derriere un scroll
   horizontal invisible sur telephone. .cabinet-header porte le MEME
   min-width (deliberement, pour que ses pistes s'alignent sur celles des
   lignes, voir son propre commentaire) : neutraliser la ligne seule sans
   neutraliser aussi l'en-tete le laisse epingle a 1409px, ce qui rouvre
   le scroll horizontal que ce bloc existe a fermer.

   La ligne garde sa liste plate de dix <div> soeurs, INCHANGEE (aucun
   markup deplace — voir task-1-brief.md) : passer .cabinet-row en flex et
   reordonner via `order` reflue ces memes enfants en deux lignes. Le
   pseudo-element ::before est l'astuce flexbox standard pour forcer un
   retour a la ligne sans ajouter de markup : une boite vide, de hauteur
   nulle, avec flex-basis:100% — rien ne tient a cote d'elle, donc chaque
   enfant reel ordonne apres elle demarre une nouvelle ligne, alors qu'elle
   ne prend elle-meme aucune hauteur visible. */
@media (max-width: 900px) {
    /* Acte III, echelle typographique (2026-09-06). Consigne d'Adrien :
       10px pour les pastilles, telephone uniquement. Firms les portait a
       0.72rem, soit 12px -- la valeur la plus grosse des quatre pages de
       reference, contre 10px sur le Dashboard qui fait foi. La regle de
       base en rem reste intacte au-dessus de 900px : la portee est le
       telephone, l'ordinateur ne change pas d'un pixel.
       L'icone suit la meme reduction (13 -> 11px) : la laisser a 13px sur
       un texte de 10px ferait un glyphe plus haut que son etiquette. */
    .pill { font-size: 11px; }
    .pill .material-icons { font-size: 11px; }

    /* Neutralise les deux min-width qui epinglent les deux grilles a
       1409px. Sans ca, rien de ce qui suit n'a d'effet : la ligne et
       l'en-tete debordent simplement de leur contenu reel et la page garde
       son scroll horizontal. */
    .cabinet-row,
    .cabinet-header {
        min-width: 0;
    }

    /* Les libelles de colonnes ("FIRM", "OFFERS", "HEADCOUNT"...) nomment
       des pistes de grille ; une fois la ligne du dessous devenue une
       carte sans piste, ils ne nomment plus rien. */
    .cabinet-header {
        display: none;
    }

    /* Hors de la grille a 10 colonnes, vers deux lignes flex construites
       depuis les memes enfants via `order` (voir le commentaire du bloc). */
    .cabinet-row {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        column-gap: 8px;
        row-gap: 8px;
    }
    .cabinet-row::before {
        content: "";
        flex-basis: 100%;
        height: 0;
        order: 4;
    }

    /* Ligne 1 : logo, nom, puis les deux boutons d'action epingles a la
       fin de la ligne — TOUJOURS sur cette meme ligne, instruction produit
       explicite d'Adrien apres mesure sur un nom long ("Alvarez & Marsal -
       equipe strategie", 35 caracteres, 265px). flex-basis:0 (pas `auto`)
       est le point qui compte : l'algorithme de retour a la ligne du
       flexbox decide quels enfants tiennent sur une ligne en utilisant la
       taille HYPOTHETIQUE de chaque enfant, c-a-d sa taille de contenu
       AVANT tout retrecissement — flex-shrink n'intervient qu'APRES que
       les enfants d'une ligne sont figes. Avec flex-basis:auto, la taille
       hypothetique du nom EST son contenu (265px pour ce nom), donc
       logo+nom+actions ne tenaient plus jamais ensemble sur la ligne 1 des
       qu'un nom depassait la largeur restante, et les actions atterrissaient
       seules sur la ligne 2 — repere a l'oeil sur un vrai iPhone : y du nom
       2402, y des actions 2445, deux lignes differentes. flex-basis:0 fait
       entrer le nom dans le calcul avec une taille hypothetique de 0 : les
       trois tiennent alors TOUJOURS ensemble sur la ligne 1 quelle que soit
       la longueur du nom, et c'est seulement ENSUITE que flex-grow:1 lui
       redonne l'espace restant, tronque par l'ellipse deja posee en regle
       bureau (white-space:nowrap + overflow:hidden + text-overflow:ellipsis,
       l.163-165). */
    .cabinet-logo { order: 1; }
    .cabinet-name {
        order: 2;
        flex: 1 1 0%;
        min-width: 0;
    }
    .cabinet-row-actions {
        order: 3;
        flex: 0 0 auto;
        flex-shrink: 0; /* jamais retrecies ni repoussees, cf. commentaire du nom */
    }
    /* Taille peinte 34px (pas 44px) : direction produit d'Adrien apres
       capture, deux boutons a 44px mangeaient un quart de la largeur de la
       carte. Meme arbitrage que .resource-filter-pill (community.css,
       TestResourceFilterPills) — Adrien y a deja choisi 34px SOUS le seuil
       tactile pour une pastille de filtre — mais resolu differemment ici :
       une pastille de filtre est un span sans zone de tap separable de sa
       boite peinte, alors qu'un bouton icone peut porter un pseudo-element
       invisible qui etend sa zone de TAP au-dela de sa boite PEINTE. Le
       ::after ci-dessous fait exactement ca : 34px peints, 44px de zone de
       tap reelle (verifie par document.elementFromPoint a 4px hors de
       chaque bord peint, voir le rapport de ce chantier). */
    .cabinet-row-actions .btn--icon {
        width: 34px;
        height: 34px;
        position: relative; /* ancre le ::after ci-dessous */
    }
    .cabinet-row-actions .btn--icon .material-icons {
        font-size: 18px; /* meme rapport icone/bouton que .btn--icon canonique a 34px (design_system.html) */
    }
    /* .btn (design_system.html) porte border:1px solid transparent avec
       box-sizing:border-box : le containing block d'un ::after absolu vise
       le PADDING-box de son ancetre position:relative, pas sa boite visible
       (border-box) — 1px plus petit de chaque cote. Sans en tenir compte,
       un inset de -5px n'atteint que borderBoxEdge-4px (mesure : height
       calculee a 42px au lieu de 44px). Les valeurs ci-dessous compensent
       ce pixel de bordure pour que la zone de tap atteigne bien 44px
       MESUREE DEPUIS LE BORD VISIBLE (verifie par
       document.elementFromPoint a 4px hors de chaque bord peint, voir le
       rapport de ce chantier). */
    .cabinet-row-actions .btn--icon::after {
        content: "";
        position: absolute;
        top: -6px;
        bottom: -6px;
    }
    /* Les deux boutons partagent 4px de gap (.cabinet-row-actions, regle
       bureau, gap:4px) : chacun etend son cote INTERIEUR de 2px seulement
       (2+2 = les 4px du gap exactement, sans empieter sur la boite peinte
       du voisin) et son cote EXTERIEUR de 8px (34+2+8 = 44px au total,
       comme les 6px hauts/bas ci-dessus : 34+6+6-2(bordure) = 44px). */
    .cabinet-row-actions .btn--icon:first-child::after {
        left: -9px;
        right: -3px;
    }
    .cabinet-row-actions .btn--icon:last-child::after {
        left: -3px;
        right: -9px;
    }
    /* La cloche (2026-09-29) est entre les deux : 3px de chaque cote, soit
       34+3+3-2 = 38px de large. Plus serait empieter sur la zone de tap
       d'un voisin, le gap de 4px ne laisse pas davantage. Sans cette regle
       le ::after du milieu n'aurait ni left ni right, donc aucune largeur. */
    .cabinet-row-actions .btn--icon:not(:first-child):not(:last-child)::after {
        left: -3px;
        right: -3px;
    }

    /* Ligne 2 : les pastilles assez courtes pour resumer un cabinet d'un
       coup d'oeil. */
    /* Sur telephone il n'y a plus d'en-tete au-dessus de ces pastilles pour
       donner un sens a un tiret nu : quand une valeur manque, le gabarit
       rend un tiret SANS la classe de pastille correspondante (Cabinets.html,
       branche {% else %} de chacune des 4 cellules) — un tiret esseule ne
       veut plus rien dire une fois la colonne sans en-tete, c'est la meme
       perte de sens que celle qui a fait retirer Practices/Industries/Links
       plus bas : si on les rend un jour a la carte sans leur re-donner un
       en-tete ou un libelle equivalent, elles retomberont dans le meme
       piege. :not(:has(*)) (utilise ailleurs pour l'actionbar de
       community.css) ne convient a AUCUNE des 4 : la cellule N'EST JAMAIS
       vide, elle contient toujours un <span> bien reel (juste sans la
       classe de pastille) — il faut cibler l'ABSENCE de la pastille
       elle-meme, pas l'absence de tout enfant.
       Round 1 n'avait applique ce traitement qu'a Offers ; revue finale
       phase 3 (M3), verifie une par une les 3 autres branches {% else %} de
       Cabinets.html — meme forme exacte (span nu sans classe), seule la
       classe de pastille qui distingue la branche peuplee differe :
         - Headcount -> .pill-headcount
         - Cities    -> .pill-bureau (le 1er bureau porte toujours cette
           classe quand la liste n'est pas vide, meme si un "+N" supplementaire
           suit sans classe de pastille propre)
         - Type      -> .pill-type
       Le principe s'applique donc desormais identiquement aux 4. */
    .cabinet-col-offers:not(:has(.pill-offers)) { display: none; }
    .cabinet-col-headcount:not(:has(.pill-headcount)) { display: none; }
    .cabinet-col-ville:not(:has(.pill-bureau)) { display: none; }
    .cabinet-col-type:not(:has(.pill-type)) { display: none; }
    .cabinet-col-offers { order: 5; }
    .cabinet-col-headcount { order: 6; }
    .cabinet-col-ville { order: 7; }
    .cabinet-col-type { order: 8; }

    /* Practices, Industries et Links quittent la carte, ils ne sont pas
       perdus : ce sont des listes ouvertes qui ne tiennent pas dans un
       resume largeur telephone, et chacune d'elles est a un tap de la
       fiche du cabinet — cliquer une carte navigue deja vers /firms/{id}
       (cabinets.js, le gestionnaire de clic de #cabinetList), ou les trois
       sont affichees en entier. */
    .cabinet-col-practices,
    .cabinet-col-industries,
    .cabinet-col-links {
        display: none;
    }


    /* Feuille du bas ("bottom sheet") plutot qu'un plein ecran : ca laisse
       une zone visible AU-DESSUS (recherche + bouton Filters, et le haut de
       la page derriere) sur laquelle taper pour fermer — un panneau plein
       ecran n'aurait plus aucun "dehors" a cliquer. C'est la SEULE chose du
       panneau qui depende vraiment de la largeur ; display, .open et gap
       viennent des regles de base et ne sont pas redits.
       `flex-wrap: nowrap` n'est pas decoratif : la base enroule, et une
       colonne enroulee sous `max-height: 75vh` repartirait les filtres en
       plusieurs colonnes des que la feuille touche son plafond. */
    #firmFiltersPanel {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 10200;
        max-height: 75vh;
        overflow-y: auto;
        flex-direction: column;
        flex-wrap: nowrap;
        align-items: stretch;
        padding: 16px;
        background: var(--white);
        border-top: 1px solid var(--line);
        border-radius: 16px 16px 0 0;
        box-shadow: var(--sh-3);
    }

    /* Les 7 .fdd sont larges de 160px (design_system.html) : dans la feuille
       empilee ils prennent toute la largeur disponible. */
    #firmFiltersPanel .fdd { width: 100%; }


    /* Cibles tactiles a 44px : le conteneur, pas une liste de classes —
       couvre tout bouton/lien/etiquette/champ present ou futur dans le
       panneau (boutons .fdd-btn, lignes .fdd-item, #filterReset,
       #btnFavorites, recherches .fdd-search), au lieu d'egrener chaque
       classe et d'en oublier une (lecon de la phase 2 : une liste de
       classes avait rate une textarea et onze champs sans classe).
       min-height gagne toujours sur un height plus petit deja pose
       ailleurs (.fdd-btn/.filter-favorites a 38px, design_system.html) :
       c'est une regle de l'algorithme de boite, pas de la cascade — la
       hauteur utilisee est le plus grand des deux, quel que soit l'ordre
       des regles.
       Exclusion checkbox/radio (revue finale phase 3, I3) : .fdd-item
       input[type="checkbox"] (design_system.html) ne pose ni width ni
       height — c'est un widget a taille NATIVE, pas un champ de saisie —
       et min-height s'applique bel et bien a un widget de formulaire.
       Sans cette exclusion, chaque case de chaque dropdown ouvert devenait
       haute de 44px pour une largeur native inchangee (~13px) : une case
       etiree, verticale, avec sa coche native deformee. La <label>
       .fdd-item, elle, garde son propre 44px (regle generique
       ci-dessus) — c'est deja elle qui porte la ligne cliquable pleine
       largeur, la case elle-meme n'a jamais eu besoin d'atteindre 44px. */
    #firmFiltersPanel :is(button, label, a, input:not([type="checkbox"]):not([type="radio"]), select) {
        min-height: 44px;
    }

    /* Anti-zoom iOS : sous 16px, Safari zoome au focus d'un champ texte
       et la mise en page saute (mesure reelle sur iPhone 17 simulator,
       voir le rapport de ce chantier). Meme lecon de conteneur que
       ci-dessus, appliquee au champ de recherche (#filterSearch, en
       dehors du panneau) ET aux recherches internes des dropdowns
       (.fdd-search, dans le panneau) : les deux vivent sous .filter-bar,
       donc ce scope generique les couvre l'un et l'autre sans les nommer
       — et sans toucher aux <select> (deja epargnes par ce risque). */
    .filter-bar :is(input, select, textarea) { font-size: 16px; }

    /* Meme defaut que .filter-bar__select (design_system.html, corrige au
       round 3) : .form-control (ligne 313, INCONDITIONNEL) est la classe
       de champ de la modale "Add a firm", posee aussi bien sur des <input>
       et <textarea> QUE sur un vrai <select id="cabinetEffectif">
       (Cabinets.html). Une seule classe (0,1,0) bat le `select`/`textarea`
       nus du socle (0,0,1) sans le moindre id -- input y est deja protege
       (0,2,1 grace aux deux :not() du socle), repris ici par symetrie.
       Distinct du scope .filter-bar ci-dessus : cette modale ne vit pas
       sous .filter-bar. Correctif source-order, sans !important : cette
       regle, plus tardive dans le fichier a specificite egale, gagne deja
       la cascade sans lui. */
    .form-control { font-size: 16px; }

    /* .add-custom-input (ligne 421, <input type=text> uniquement dans les
       2 gabarits qui l'utilisent, jamais un <select>) est deja SANS
       RISQUE : une classe seule (0,1,0) reste sous le 0,2,1 du socle sur
       input (ses deux :not()). Reprise ici par symetrie et pour que le
       garde-fou de source reconnaisse la resolution explicitement. */
    .add-custom-input { font-size: 16px; }
}
