/* StudioHub Elite Palette - FL Studio Gold & ProTools Purple */
:root {
    /* ── Couches d'affichage ──────────────────────────────────────────────────

       L'application comptait deux cent quarante-six déclarations de z-index, dont des 9999 et des
       10000 posés au coup par coup : chaque conflit se réglait par une surenchère, et plus rien
       ne disait quelle couche devait passer devant quelle autre.

       Sept niveaux, dans l'ordre où on les rencontre. Un nouvel élément prend le niveau de sa
       nature, pas un nombre plus grand que le voisin qui le gênait. */
    --sh-z-base: 0;
    --sh-z-sticky: 100;      /* barres fixes, en-têtes de tableau */
    --sh-z-dropdown: 200;    /* listes déroulantes, menus de la barre du haut */
    --sh-z-popover: 300;     /* infobulles riches, sélecteurs flottants */
    --sh-z-panel: 400;       /* panneaux latéraux et leur voile */
    --sh-z-modal: 500;       /* modales et boîtes de dialogue */
    --sh-z-critical: 600;    /* messages bloquants, voile de transaction */

    /* Hauteur de la barre du haut. Elle est collante : ce qui se réserve la place restante — la
       hauteur d'une liste qui défile pour son compte — la retranche de la fenêtre. Cette valeur
       n'est que le point de départ : MainLayout la remplace par la hauteur mesurée
       (studioHubDom.trackHeaderHeight), encoche comprise. */
    --sh-header-h: 4.8rem;

    --sh-black: #050505;
    --sh-gray-950: #080808;
    --sh-gray-900: #0f0f0f;
    --sh-gray-800: #1a1a1a;
    --sh-gray-700: #252525;
    
    /* StudioHub Gold - More yellowish/goldish, less neon */
    --sh-gold: #f0b400;
    --sh-gold-deep: #d4a017;
    --sh-gold-glow: rgba(240, 180, 0, 0.2);
    
    /* ProTools Purple for Artist role */
    --sh-purple: #9b59b6;
    --sh-purple-glow: rgba(155, 89, 182, 0.2);

    /* L'accent de l'espace artiste. Il empruntait le violet, qui sert déjà aux remboursements :
       une même couleur pour « votre argent revient » et « vous êtes ici » se lit mal. */
    --sh-pink: #f06fa8;
    --sh-pink-glow: rgba(240, 111, 168, 0.18);

    /* Engineer role accent — Owner uses --sh-gold (the default brand color), no separate var needed */
    --sh-blue: #4dabf7;
    --sh-blue-glow: rgba(77, 171, 247, 0.2);

    /* Manager role accent */
    --sh-green: #4ade80;
    --sh-green-glow: rgba(74, 222, 128, 0.2);

    /* Premium Amber - warm copper tone matching gold */
    --sh-amber: #d4a574;
    --sh-amber-dark: #b8956a;
    --sh-amber-glow: rgba(212, 165, 116, 0.2);
    
    --sh-white: #ffffff;
    --sh-white-glow: rgba(255, 255, 255, 0.55);
    --sh-white-glow-strong: rgba(255, 255, 255, 0.85);
    --sh-muted: #888888;

    /* Overlays / side panels & modals — valeurs partagées pour un poids visuel cohérent
       entre tous les panneaux latéraux et modales (artiste, studio, PIN, cash...). */
    --sh-overlay-bg: rgba(0, 0, 0, 0.6);
    --sh-overlay-blur: blur(6px);
    --sh-content-blur: blur(4px) saturate(0.72);
    --sh-content-dim-opacity: 0.48;

    /* ---- Dark Aero ----------------------------------------------------------
       Ce que l'Aero apportait vraiment n'était pas le bleu ciel : c'était la
       profondeur, la translucidité et la lumière. Ces jetons portent ça sur la
       base noire de StudioHub, sans virer au plastique brillant qui ruinerait
       la lisibilité des tableaux de chiffres.

       Répartition des rôles chromatiques, à respecter :
         --sh-aqua  interactif, vivant, informatif
         --sh-gold  argent et premium, rien d'autre
       Aujourd'hui l'or porte les deux, ce qui rend un bouton et un montant
       visuellement interchangeables. */
    --sh-aqua: #4fd1e8;
    --sh-aqua-soft: rgba(79, 209, 232, 0.16);
    --sh-aqua-glow: rgba(79, 209, 232, 0.28);

    /* ---- La teinte d'un espace ---------------------------------------------
       Or pour le propriétaire, aqua pour l'ingénieur, rose pour l'artiste.

       Elle ne vivait que dans la feuille du sélecteur d'espaces, en six déclarations qui
       recopiaient les valeurs au chiffre près. Dès que les notifications ont eu à dire de quel
       espace elles parlent, il a fallu la même couleur ailleurs — et une couleur d'identité
       recopiée finit toujours par diverger de son original.

       Trois jetons par espace : le trait, le fond, la bordure. Qui porte deux casquettes
       reconnaît alors son espace à la couleur avant d'avoir lu le mot. */
    --sh-space-owner: var(--sh-gold);
    --sh-space-owner-soft: rgba(240, 180, 0, 0.1);
    --sh-space-owner-edge: rgba(240, 180, 0, 0.3);
    --sh-space-owner-ground: rgba(240, 180, 0, 0.055);

    --sh-space-engineer: var(--sh-aqua);
    --sh-space-engineer-soft: rgba(79, 209, 232, 0.1);
    --sh-space-engineer-edge: var(--sh-aqua-glow);
    --sh-space-engineer-ground: rgba(79, 209, 232, 0.05);

    /* L'artiste porte le rose, et lui seul. L'ambre disait « quelque chose attend une action »
       partout ailleurs : sur un espace, il promettait une urgence qui n'existe pas. */
    --sh-space-artist: var(--sh-pink);
    --sh-space-artist-soft: var(--sh-pink-glow);
    --sh-space-artist-edge: rgba(240, 111, 168, 0.32);
    --sh-space-artist-ground: rgba(240, 111, 168, 0.05);

    /* ── L'accent en cours ─────────────────────────────────────────────────────

       Trois jetons par espace, mais un composant partagé ne sait pas dans quel espace il est
       rendu — et il ne doit pas l'apprendre : la file « à traiter », le bouton « aperçu », la
       ligne d'un tableau vivent dans les trois. Chacun lisait donc la même couleur en dur, l'or
       de la marque ou l'aqua, si bien que l'espace artiste soulignait ses onglets en or et
       montrait ses aperçus en aqua. Le rose ne vivait que dans une pastille.

       D'où un accent « en cours », remis par la coquille de l'espace (« .app-space-shell--… »)
       et hérité par tout ce qu'elle contient. Un composant écrit « var(--sh-accent) » une fois
       et prend la couleur de l'espace où il se trouve, sans le savoir.

       La valeur par défaut est l'or : hors d'un espace — vitrine, connexion, sélecteur — c'est
       la couleur de la marque, et rien ne change là où rien ne doit changer.

       L'accent est réservé à la navigation et à la sélection : où je suis, ce que j'ai choisi,
       ce qui a le focus. L'or de l'argent (« sh-fact--money », « sh-action--pay ») n'en fait
       pas partie — une somme n'est pas rose chez l'artiste et aqua chez l'ingénieur. */
    --sh-accent: var(--sh-gold);
    --sh-accent-soft: var(--sh-space-owner-soft);
    --sh-accent-edge: var(--sh-space-owner-edge);
    --sh-accent-ground: transparent;

    /* ── L'échelle des profondeurs ─────────────────────────────────────────────

       Sept couches de z-index disaient laquelle passe devant l'autre. Deux surfaces seulement
       les portaient — « glass-bg » et « glass-bg-raised » — si bien que chaque menu, chaque
       modale et chaque panneau inventait son ombre : soixante-dix-sept écrites en dur, une
       vingtaine de valeurs différentes pour dire la même chose, « je suis au-dessus ».

       Le résultat n'était pas laid, il était illisible : deux surfaces à la même hauteur
       n'avaient pas la même ombre, et deux surfaces à des hauteurs différentes en avaient
       parfois la même. L'œil ne pouvait plus s'en servir pour ranger l'écran.

       Quatre crans, et chacun tient trois choses à la fois — la lumière vient d'en haut, donc
       ce qui monte s'éclaircit, porte une arête plus nette et jette une ombre plus large :

         1  posée      cartes, sections, lignes de file        ── au ras de la page
         2  collée     barres collantes, en-têtes de tableau   ── décollée d'un cheveu
         3  flottante  menus, listes déroulantes, infobulles   ── clairement au-dessus
         4  couvrante  panneaux latéraux, modales              ── au-dessus de tout

       Les deux premiers crans sont du verre : ils reposent sur le fond de la page, qu'on sait,
       et le laisser paraître est ce qui les y rattache. Les deux derniers ne reposent sur rien
       de connu — ils passent devant un tableau, une grille horaire, une autre carte — et ils
       portent du texte à lire. Leur fond est donc **opaque**, et c'est le voile derrière eux qui
       sépare de la page. L'application le faisait déjà, chacun pour soi : « #111 » dans les
       listes déroulantes, « #131313 » dans les modales, « rgba(20,20,20,.95) » au centre de
       notifications. Trois réponses à la même question, à quatre unités près.

       Les valeurs ne sont pas inventées : ce sont celles que l'application employait déjà le
       plus souvent à chaque hauteur, régularisées. Un cran se prend en entier — fond, bordure
       et ombre — d'où les classes « .sh-elev-N » plus bas, qui évitent de marier le fond d'un
       cran à l'ombre d'un autre. */

    --sh-elev-1-bg: rgba(255, 255, 255, 0.045);
    --sh-elev-1-border: rgba(255, 255, 255, 0.10);
    --sh-elev-1-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);

    --sh-elev-2-bg: rgba(255, 255, 255, 0.07);
    --sh-elev-2-border: rgba(255, 255, 255, 0.12);
    --sh-elev-2-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);

    --sh-elev-3-bg: #121212;
    --sh-elev-3-border: rgba(255, 255, 255, 0.14);
    --sh-elev-3-shadow: 0 18px 44px rgba(0, 0, 0, 0.55);

    /* Plus haut, donc plus clair : quatre unités de gris suffisent à ranger une modale
       au-dessus du menu qui l'a ouverte, sans qu'aucune des deux paraisse grise. */
    --sh-elev-4-bg: #171717;
    --sh-elev-4-border: rgba(255, 255, 255, 0.16);
    --sh-elev-4-shadow:
        0 1px 2px rgba(0, 0, 0, 0.35),
        0 8px 24px rgba(0, 0, 0, 0.40),
        0 24px 56px rgba(0, 0, 0, 0.28);

    /* Le cran 4 ancré à un bord de l'écran — tiroir de navigation, feuille qui monte du bas.
       Une seule arête est visible, et l'ombre du cran, qui tombe vers le bas, ne la dessinerait
       pas : elle part donc vers l'intérieur de l'écran, au même poids. */
    --sh-elev-4-shadow-up: 0 -18px 48px rgba(0, 0, 0, 0.55);
    --sh-elev-4-shadow-right: 24px 0 60px rgba(0, 0, 0, 0.60);

    /* Les anciens noms, conservés le temps de la reprise : ils désignent le cran 1 et le cran 4,
       qui sont ce qu'ils voulaient dire. Rien ne change à l'écran en les aliasant ; ce qui
       change, c'est qu'on peut maintenant migrer un fichier à la fois. */
    --sh-glass-bg: var(--sh-elev-1-bg);
    --sh-glass-bg-raised: var(--sh-elev-2-bg);
    --sh-glass-border: var(--sh-elev-1-border);
    --sh-glass-blur: blur(20px) saturate(170%);

    /* L'arête lumineuse en haut de la surface : à elle seule, c'est ce qui fait
       lire une carte comme du verre plutôt que comme un rectangle gris. */
    --sh-glass-specular: inset 0 1px 0 rgba(255, 255, 255, 0.14);
    --sh-glass-depth: var(--sh-elev-4-shadow);

    /* Franchement arrondi : le panneau central se lit comme une carte posée au-dessus de la
       page, et non comme un encart encastré. Les blocs intérieurs suivent un cran en dessous —
       des angles vifs à l'intérieur d'une carte très arrondie se voient immédiatement. */
    --sh-radius-aero: 28px;
    --sh-radius-aero-sm: 18px;

    /* Décélération liquide : rapide au départ, longue traîne. */
    --sh-ease-liquid: cubic-bezier(0.22, 1, 0.36, 1);
    --sh-duration-aero: 260ms;
}

/* ── Les quatre crans, en classes ─────────────────────────────────────────────

   Un cran se prend en entier. Les trois jetons d'un même niveau — fond, bordure, ombre — sont
   accordés ; les marier d'un niveau à l'autre est précisément ce qui rendait l'écran illisible,
   et une classe l'empêche là où trois déclarations le permettaient.

   L'arête lumineuse vient avec : c'est elle qui fait lire une surface comme du verre plutôt que
   comme un rectangle gris, et elle se renforce en montant. */
.sh-elev-1,
.sh-elev-2,
.sh-elev-3,
.sh-elev-4 {
    border: 1px solid;
}

/* Le flou n'a de sens que là où le fond laisse passer la page. Au-dessus, il coûterait une
   couche de composition pour flouter ce que l'opacité cache déjà. */
.sh-elev-1,
.sh-elev-2 {
    backdrop-filter: var(--sh-glass-blur);
    -webkit-backdrop-filter: var(--sh-glass-blur);
}

.sh-elev-1 {
    background: var(--sh-elev-1-bg);
    border-color: var(--sh-elev-1-border);
    box-shadow: var(--sh-glass-specular), var(--sh-elev-1-shadow);
}

.sh-elev-2 {
    background: var(--sh-elev-2-bg);
    border-color: var(--sh-elev-2-border);
    box-shadow: var(--sh-glass-specular), var(--sh-elev-2-shadow);
}

.sh-elev-3 {
    background: var(--sh-elev-3-bg);
    border-color: var(--sh-elev-3-border);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), var(--sh-elev-3-shadow);
}

/* L'arête des deux crans hauts, à part : un composant qui pose son propre fond — une modale
   teintée, un menu au liseré doré — prend l'ombre du cran sans en reprendre le fond. */
.sh-elev-3-shadow { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), var(--sh-elev-3-shadow); }
.sh-elev-4-shadow { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), var(--sh-elev-4-shadow); }

.sh-elev-4 {
    background: var(--sh-elev-4-bg);
    border-color: var(--sh-elev-4-border);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), var(--sh-elev-4-shadow);
}

/* Surface de verre réutilisable. Composer avec, plutôt que redéclarer le flou
   dans chaque composant : un backdrop-filter dupliqué coûte cher au rendu.

   C'est le cran 1 sous son ancien nom — la plupart des écrans l'emploient déjà, et le renommer
   d'un coup aurait touché quarante fichiers pour ne rien changer à l'écran. */
.sh-aero-surface {
    background: var(--sh-glass-bg);
    border: 1px solid var(--sh-glass-border);
    border-radius: var(--sh-radius-aero);
    box-shadow: var(--sh-glass-specular), var(--sh-glass-depth);
    backdrop-filter: var(--sh-glass-blur);
    -webkit-backdrop-filter: var(--sh-glass-blur);
}

.sh-aero-raised { background: var(--sh-glass-bg-raised); }

/* Saisie d'un code court : chiffres espacés et centrés, pour qu'on compte les
   caractères d'un coup d'œil. */
.sh-pin-input {
    letter-spacing: 0.6em;
    text-align: center;
    font-size: 1.25rem;
    font-weight: 700;
    padding-inline: 0.5rem;
}

/* Action « ouvrir le détail » dans une ligne de tableau. Distincte du clic sur la
   ligne, qui ouvre la vue rapide : deux gestes, deux destinations. */
.row-detail-btn {
    display: inline-grid;
    place-items: center;
    width: 30px;
    height: 30px;
    color: rgba(255, 255, 255, 0.5);
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid var(--sh-glass-border);
    border-radius: 9px;
    font-size: 0.82rem;
    transition: color var(--sh-duration-aero) var(--sh-ease-liquid),
                background var(--sh-duration-aero) var(--sh-ease-liquid),
                border-color var(--sh-duration-aero) var(--sh-ease-liquid);
}

.row-detail-btn:hover,
.row-detail-btn:focus-visible {
    color: var(--sh-accent);
    background: var(--sh-accent-soft);
    border-color: var(--sh-accent-edge);
}

/* ---- Side panels ---------------------------------------------------------
   Un seul comportement pour tous les panneaux latéraux. Ils divergeaient :
   l'un en position relative dans une grille, l'autre en fixed, avec des
   overlays, des rayons et des ombres différents. Composer avec .sh-sidepanel
   plutôt que redéfinir la géométrie dans chaque composant. */
/* Échelle d'empilement, pour que ces nombres cessent d'être arbitraires :

     1500  barre REC — au-dessus de la page, sous le voile
     2000  voile du panneau
     2001  panneau
     9999  modales et toasts, qui doivent couvrir le panneau lui-même

   La barre REC passait auparavant au-dessus du voile, au motif qu'une session en cours ne se
   cache pas. Elle repasse dessous : quand un panneau est ouvert, il est la seule chose nette à
   l'écran, et une bande rouge parfaitement dessinée au milieu d'un shell flouté se lisait comme
   un défaut d'affichage plutôt que comme une information. La session reste visible — floutée,
   comme le reste — et le panneau se referme d'un clic sur le voile. */

/* Le voile couvre l'écran entier, barre supérieure comprise : quand le panneau est ouvert, il
   est la seule chose nette. Il commençait à 70px pour épargner la barre de navigation, ce qui
   laissait une bande franche en haut d'un écran par ailleurs flouté. */
.sh-sidepanel-overlay {
    position: fixed;
    inset: 0;
    z-index: var(--sh-z-panel);
    background: rgba(4, 6, 9, 0.55);
    backdrop-filter: blur(10px) saturate(80%);
    -webkit-backdrop-filter: blur(10px) saturate(80%);
    animation: sh-sidepanel-veil var(--sh-duration-aero) var(--sh-ease-liquid);
}

@keyframes sh-sidepanel-veil {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* ── Le menu d'un espace de travail sur téléphone ─────────────────────────────

   Sur grand écran, un espace se navigue par une colonne à gauche : les onglets les uns sous les
   autres, lisibles d'un coup d'œil. Sous 900 px, cette colonne devenait une bande horizontale
   posée en haut de la page — les onglets à la file, à faire défiler du pouce, sans qu'on voie
   jamais lesquels existent. Un menu qu'on ne peut pas lire en entier n'est plus un menu, c'est
   une bande de boutons.

   Elle redevient donc une colonne, mais posée sur la page plutôt qu'à côté : un tiroir qui entre
   par la gauche, sur un voile flouté qui laisse voir un dixième du fond — de quoi comprendre
   qu'on est au-dessus de son écran, et non parti ailleurs. Le geste pour le refermer est le même
   que pour tout le reste : le voile, Échap, ou changer de page.

   La géométrie vit ici, en un seul endroit, et non recopiée dans les deux coquilles d'espace —
   propriétaire d'un côté, ingénieur et artiste de l'autre. Même raison que .sh-sidepanel : deux
   copies finissent par diverger. */

.sh-workspace-menu { display: none; }

@media (max-width: 900px) {
    .sh-workspace-drawer {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        z-index: calc(var(--sh-z-panel) + 1);
        /* Neuf dixièmes de l'écran : il reste juste assez de fond, flouté, pour qu'on sache que
           la page est toujours là derrière. */
        width: 90vw;
        max-width: 26rem;
        height: auto;
        overflow-y: auto;
        padding: 1rem 0.85rem 2.5rem;
        background: rgba(8, 8, 8, 0.97);
        border-right: 1px solid var(--sh-glass-border);
        border-bottom: 0;
        box-shadow: var(--sh-elev-4-shadow-right);
        transform: translateX(-102%);
        transition: transform 220ms var(--sh-ease-liquid, ease);
        /* Fermé, il sort aussi de l'ordre de tabulation et de l'arbre d'accessibilité : un menu
           invisible qui garde le focus envoie le pouce nulle part. */
        visibility: hidden;
    }

    .sh-workspace-drawer.is-open {
        transform: none;
        visibility: visible;
    }

    /* Le bouton qui l'ouvre. Il dit où l'on est autant qu'il ouvre le menu : sur un écran étroit,
       le nom de l'onglet courant n'est écrit nulle part ailleurs une fois la colonne repliée.
       Il est posé dans la barre de l'espace, au-dessus du retour aux espaces. */
    .sh-workspace-menu {
        display: inline-flex;
        align-items: center;
        gap: 0.55rem;
        max-width: 100%;
        min-height: 40px;
        padding: 0.45rem 0.9rem 0.45rem 0.7rem;
        color: var(--sh-white);
        background: rgba(255, 255, 255, 0.05);
        border: 1px solid var(--sh-glass-border);
        border-radius: 999px;
        font-size: 0.82rem;
        font-weight: 700;
    }

    .sh-workspace-menu:hover,
    .sh-workspace-menu:focus-visible { background: rgba(255, 255, 255, 0.09); }

    .sh-workspace-menu i { color: var(--sh-gold); font-size: 0.95rem; }

    .sh-workspace-menu span {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

@media (prefers-reduced-motion: reduce) {
    .sh-workspace-drawer { transition: none; }
}

/* Panneau central flottant, détaché des quatre bords : il se lit comme posé au-dessus de la
   page plutôt qu'encastré dans son bord droit.

   Le centrage passe par la marge automatique et non par une translation. C'était le défaut :
   translateX(-50%) centrait le panneau, mais l'animation d'entrée animait ce même transform
   de 1.5rem à 0 — donc sans le -50%. Le panneau entrait décentré vers la droite puis sautait
   au centre à la dernière image. L'animation ne touche plus qu'à l'opacité et à l'échelle,
   qui ne portent aucune géométrie. */
.sh-sidepanel {
    position: fixed;
    inset: 0;
    z-index: calc(var(--sh-z-panel) + 1);
    display: flex;
    flex-direction: column;

    /* Centré sur les deux axes par la marge automatique, jamais par une translation : le
       transform est réservé à l'animation d'entrée, et les faire cohabiter était précisément
       le défaut qui faisait sauter le panneau à la dernière image. */
    width: min(42rem, calc(100vw - 4rem));
    height: fit-content;

    /* Sur iOS, 100vh vaut la hauteur barres masquées : tant que la barre d'adresse de Safari
       est affichée, un panneau calé dessus déborde sous elle. dvh suit la hauteur réellement
       visible ; vh reste en repli pour les navigateurs qui l'ignorent. */
    max-height: calc(100vh - 3rem);
    margin: auto;

    /* Le panneau est borné en hauteur ; ce qui dépasse défile dans son corps, jamais dans la
       page. « hidden » ici découpe aux angles arrondis, il ne cache plus rien. */
    overflow: hidden;

    /* Assez translucide pour que le flou se voie — à 0.92 le verre ne se lisait pas — et
       isolé pour que ce flou soit découpé par les angles arrondis plutôt que rendu carré
       derrière eux. */
    background: rgba(12, 13, 16, 0.78);
    isolation: isolate;

    border: 1px solid var(--sh-glass-border);
    border-radius: var(--sh-radius-aero);
    box-shadow: var(--sh-glass-specular), var(--sh-glass-depth);
    backdrop-filter: var(--sh-glass-blur);
    -webkit-backdrop-filter: var(--sh-glass-blur);
    animation: sh-sidepanel-enter var(--sh-duration-aero) var(--sh-ease-liquid);
}

@supports (height: 100dvh) {
    .sh-sidepanel { max-height: calc(100dvh - 3rem); }
}

@keyframes sh-sidepanel-enter {
    from { opacity: 0; transform: scale(0.97); }
    to { opacity: 1; transform: scale(1); }
}


.sh-sidepanel-header {
    flex: 0 0 auto;
    padding: 1.25rem 1.5rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

/* Le corps défile, et le dit.

   Il ne défilait pas : « overflow: hidden » coupait net ce qui dépassait, sans barre, sans
   dégradé, sans rien qui signale qu'il en manquait — la règle « tout doit rentrer » tenait tant
   que les panneaux étaient courts, et une séance soldée avec son historique n'y tenait plus.

   Les quatre fonds ci-dessous sont l'ombre de défilement classique, et elle a une propriété que
   n'a aucun dégradé posé à la main : les deux premiers plans sont attachés au contenu
   (« local »), les deux suivants au cadre (« scroll »). En haut de course, le fond opaque du
   contenu recouvre exactement l'ombre du cadre, qui disparaît ; dès qu'on défile, il s'en va
   avec le contenu et découvre l'ombre. Autrement dit : l'estompe ne paraît que là où il reste
   quelque chose à lire, en haut comme en bas. */
.sh-sidepanel-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 1.25rem 1.5rem;

    background:
        linear-gradient(rgba(12, 13, 16, 0.92), rgba(12, 13, 16, 0)) center top / 100% 2rem no-repeat local,
        linear-gradient(rgba(12, 13, 16, 0), rgba(12, 13, 16, 0.92)) center bottom / 100% 2rem no-repeat local,
        radial-gradient(farthest-side at 50% 0, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0)) center top / 100% 1rem no-repeat scroll,
        radial-gradient(farthest-side at 50% 100%, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0)) center bottom / 100% 1rem no-repeat scroll;
}

.sh-sidepanel-footer {
    flex: 0 0 auto;
    padding: 1rem 1.5rem 1.25rem;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    background: #0f0f0f;
}

.sh-sidepanel-close {
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    color: rgba(255, 255, 255, 0.5);
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid var(--sh-glass-border);
    border-radius: 50%;
    font-size: 0.95rem;
    transition: color var(--sh-duration-aero) var(--sh-ease-liquid),
                background var(--sh-duration-aero) var(--sh-ease-liquid);
}

.sh-sidepanel-close:hover,
.sh-sidepanel-close:focus-visible {
    color: var(--sh-white);
    background: rgba(255, 255, 255, 0.1);
}

/* Sur petit écran le tiroir devient une feuille : elle monte du bas et s'arrête avant le haut,
   pour qu'on voie ce qu'on a laissé derrière et qu'on sache d'où l'on vient.

   Son corps défile. La règle « tout tient sans défilement » vaut sur un bureau, où la hauteur ne
   manque pas ; sur un téléphone elle est intenable, et overflow: hidden coupait alors le contenu
   en silence — sans barre, sans indice, sans rien qui signale qu'il en manque. Les actions
   restent figées en pied : ce sont elles qu'on vient chercher, et les faire défiler hors de vue
   reviendrait à cacher le geste sous le texte qui le justifie.

   Ces règles vivaient dans un second bloc, à 700 px, écrit avant celui-ci et donc perdant sur
   tout ce que les deux déclaraient. Deux conséquences, toutes deux visibles sur un téléphone :
   la hauteur retombait sur « 85vh », sans le repli dvh que l'autre bloc prenait soin de poser —
   or sur iOS, vh vaut la hauteur barres masquées, si bien que le pied du panneau passait sous la
   barre d'adresse de Safari et que le contenu s'arrêtait en pleine section. Et entre 701 et
   720 px, la feuille s'affichait sans que son corps défile : le débordement y était coupé net.
   Un seul bloc, un seul point de rupture. */
@media (max-width: 720px) {
    /* Centré, et non calé en bas.

       Calé en bas, le panneau ne laissait paraître le voile flouté qu'au-dessus de lui : la page
       restait nette juste en dessous, et l'écran se lisait comme un panneau posé sur une page
       intacte plutôt que comme une page mise de côté. Centré, il est entouré de ce qu'il couvre,
       en haut comme en bas — et c'est cette symétrie qui fait qu'on le lit comme au-dessus. */
    .sh-sidepanel {
        inset: 0;
        margin: auto 0.5rem;
        width: auto;
        max-height: 85vh;
        animation: sh-sidepanel-sheet var(--sh-duration-aero) var(--sh-ease-liquid);
    }

    /* dvh suit la hauteur réellement visible ; vh reste en repli pour qui l'ignore. */
    @supports (height: 100dvh) {
        .sh-sidepanel { max-height: 85dvh; }
    }

    .sh-sidepanel-body {
        -webkit-overflow-scrolling: touch;
    }

    .sh-sidepanel-footer {
        position: sticky;
        bottom: 0;
    }

    /* La feuille montait de deux centimètres ; centrée, elle vient de moins loin — un panneau
       qui apparaît au milieu n'a pas de bord d'où sortir. */
    @keyframes sh-sidepanel-sheet {
        from { opacity: 0; transform: translateY(1rem) scale(0.99); }
        to { opacity: 1; transform: translateY(0) scale(1); }
    }
}

@media (prefers-reduced-motion: reduce) {
    :root { --sh-duration-aero: 1ms; }
}

/* Base & Reset */
* {
    box-sizing: border-box;
}

/* Le double-tap n'agrandit plus la page.

   Sur un écran tactile, deux appuis rapprochés valent « zoomer » par défaut. C'est une convention
   de page web, pas d'application : ici, deux appuis rapprochés arrivent surtout quand on répond
   trop vite à un bouton qui n'a pas encore réagi — et l'écran part alors de travers, à moitié
   agrandi, sur un geste que personne n'a voulu.

   « manipulation » retire ce raccourci et garde tout le reste : le défilement au doigt, et surtout
   le pincement. Couper le pincement — par « user-scalable=no » dans le viewport — retirerait à qui
   voit mal le seul moyen de lire un montant ou une heure. iOS l'ignore d'ailleurs depuis longtemps,
   précisément pour cette raison : ce serait du code qui promet ce qu'il ne fait pas. */
html {
    touch-action: manipulation;
}

html, body {
    background-color: var(--sh-black) !important;
    background-image:
        radial-gradient(ellipse 80% 50% at 50% -20%, rgba(240, 180, 0, 0.07), transparent),
        radial-gradient(ellipse 60% 40% at 100% 100%, rgba(240, 180, 0, 0.04), transparent);
    color: var(--sh-white) !important;
    font-family: 'Inter', sans-serif;
    margin: 0;
    padding: 0;
    /* « clip » et non « hidden ».

       « hidden » fait du body un conteneur de défilement à part entière : la barre du haut,
       déclarée collante, se collait alors au scrollport du body — qui ne défile jamais, c'est
       html qui défile. Elle partait donc vers le haut avec la page, `position: sticky` restant
       écrit mais sans effet. « clip » coupe le débordement horizontal de la même façon sans
       créer de conteneur de défilement : la barre retrouve la fenêtre pour repère. */
    overflow-x: clip;
}

/* Page Transitions */
/* L'entrée de page ne laisse aucune transformation derrière elle.
   
   Avec « forwards », l'élément conservait à l'arrêt la transformation finale — translateY(0),
   donc invisible à l'œil. Mais une transformation, même identité, fait de l'élément le bloc
   conteneur de ses descendants en position fixed : le voile d'un panneau, censé couvrir l'écran,
   se retrouvait confiné à la boîte de la page. Il ne couvrait ni la barre du haut, ni la colonne
   latérale, et cliquer dessus ne fermait rien.
   
   L'opacité seule est animée ; le décalage d'entrée passe par une propriété qui ne crée pas de
   contexte, et l'animation ne fige plus rien à la fin. */
.page-fade-in {
    animation: fadeIn 0.4s ease-out;
}

.auth-card-transition {
    animation: authFadeUp 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
}

@keyframes fadeIn {
    from { opacity: 0; translate: 0 10px; }
    to { opacity: 1; translate: 0 0; }
}

@keyframes authFadeUp {
    from { opacity: 0; transform: translateY(30px); }
    to { opacity: 1; transform: translateY(0); }
}

/* Layout */
.page {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}
.sidebar {
    display: none !important;
}

main {
    flex: 1;
    display: flex;
    flex-direction: column;
}

.content {
    width: 100%;
    max-width: 1400px;
    margin: 0 auto;
    padding: 0 2rem !important;
}

/* Navbar — primary app title lives here only */
.sh-site-header {
    position: sticky;
    top: 0;

    /* Les encoches, depuis que « viewport-fit=cover » étend la page sous elles.

       Celle du haut d'abord, et c'est la plus importante : la barre est collée à « top: 0 »,
       c'est-à-dire au bord physique de l'écran et non sous la barre d'état. Ses cinquante-neuf
       premiers pixels passaient donc sous l'heure et la batterie — la marque, le sélecteur
       d'espace et le bouton du menu avec eux, hors d'atteinte du pouce. C'est le prix de
       « cover » : ce qu'il donne au bas, il faut le rendre au haut.

       Les latérales servent en paysage, où l'encoche mord sur le côté. Le rembourrage ne vaut
       que là où il y a quelque chose à éviter : en portrait, ces trois valeurs sont nulles. */
    padding-top: env(safe-area-inset-top, 0px);
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
    /* Juste au-dessus du voile de fermeture des menus : la barre porte les menus eux-mêmes, et
       le voile doit intercepter les clics de la page, pas ceux de la barre. Sinon, cliquer sur
       la cloche pendant que le menu profil est ouvert ne fait que refermer le premier. */
    z-index: calc(var(--sh-z-dropdown) + 1);
    background-color: rgba(5, 5, 5, 0.72) !important;
    backdrop-filter: blur(16px);
    border-bottom: none;
    margin-bottom: 1.5rem;
}

/* Sur écran étroit, la barre cède son flou à sa barre intérieure.

   Un backdrop-filter fait de l'élément le bloc conteneur de tout descendant en position fixed :
   la feuille de menus, censée monter du bas de l'écran, se collait sous la barre du haut. Le flou
   descend d'un cran, l'aspect ne change pas, et la feuille retrouve la fenêtre pour repère. */
@media (max-width: 991.98px) {
    .sh-site-header,
    .sh-site-header > .navbar { backdrop-filter: none; }

    /* Le flou passe sur un calque qui n'est l'ancêtre de personne. Un pseudo-élément ne peut pas
       servir de bloc conteneur au contenu de la barre : la feuille garde la fenêtre pour repère,
       et l'aspect de la barre ne bouge pas. */
    .sh-site-header::before {
        content: "";
        position: absolute;
        inset: 0;
        z-index: -1;
        background: rgba(5, 5, 5, 0.72);
        backdrop-filter: blur(16px);
        -webkit-backdrop-filter: blur(16px);
    }
}

/* Séparation par dégradé, jamais par filet plein : évite la cassure horizontale */
.sh-site-header::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.07) 25%, rgba(255, 255, 255, 0.07) 75%, transparent);
    pointer-events: none;
}

/* L'accueil est une seule surface continue : pas de gouttière sous la navbar */
body:has(.sh-hero-section) .sh-site-header {
    margin-bottom: 0;
}

.navbar {
    background-color: transparent !important;
    border-bottom: none;
    padding: 0.85rem 0 !important;
    margin-bottom: 0;
}

.navbar .container-fluid {
    max-width: 1400px;
    padding: 0 2rem;
}

/* StudioHub wordmark — Studio (gold) + Hub (white glow) */
.sh-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.65rem;
}

.sh-brand-wordmark {
    font-weight: 800;
    letter-spacing: 0.04em;
    line-height: 1;
    white-space: nowrap;
}

.sh-brand-studio,
.sh-brand-inline .sh-brand-studio {
    color: var(--sh-gold);
    text-shadow:
        0 0 8px rgba(240, 180, 0, 0.65),
        0 0 18px rgba(240, 180, 0, 0.35),
        0 0 32px rgba(240, 180, 0, 0.15);
}

.sh-brand-hub,
.sh-brand-inline .sh-brand-hub {
    color: var(--sh-white);
    text-shadow:
        0 0 6px rgba(255, 255, 255, 0.95),
        0 0 14px rgba(255, 255, 255, 0.6),
        0 0 28px rgba(255, 255, 255, 0.28);
}

.sh-brand-inline {
    font-weight: 700;
    white-space: nowrap;
}

.sh-brand--sm .sh-brand-wordmark { font-size: 1.15rem; }
.sh-brand--md .sh-brand-wordmark { font-size: 1.65rem; }
.sh-brand--lg .sh-brand-wordmark { font-size: 2.25rem; }
.sh-brand--xl .sh-brand-wordmark { font-size: clamp(2.5rem, 5vw, 3.75rem); }

.sh-brand-icon {
    width: 40px;
    height: 40px;
    border-radius: 8px;
    object-fit: contain;
    flex-shrink: 0;
}

.sh-brand--sm .sh-brand-icon { width: 28px; height: 28px; border-radius: 6px; }
.sh-brand--lg .sh-brand-icon { width: 56px; height: 56px; border-radius: 12px; }
.sh-brand--xl .sh-brand-icon { width: 70px; height: 70px; border-radius: 14px; }

/* Legacy alias */
.sh-logo-gold .sh-brand-studio,
.sh-logo-gold:not(:has(.sh-brand-studio)) {
    color: var(--sh-gold);
    text-shadow: 0 0 10px var(--sh-gold-glow);
    font-weight: 800;
}

/* Premium Cards */
.card {
    background-color: var(--sh-gray-900) !important;
    border: 1px solid var(--sh-gray-800) !important;
    border-radius: 12px !important;
    transition: all 0.4s cubic-bezier(0.165, 0.84, 0.44, 1);
    overflow: hidden;
}

.sh-interactive-card {
    cursor: pointer;
}

.sh-interactive-card:hover {
    border-color: var(--sh-amber) !important;
    box-shadow: var(--sh-elev-3-shadow);
    transform: translateY(-5px);
}

a.sh-interactive-card:focus-visible {
    outline: 3px solid var(--sh-accent);
    outline-offset: 3px;
    border-color: var(--sh-accent) !important;
}

/* Glassmorphism Studio Card */
.studio-card-glass {
    position: relative;
    border: 1px solid rgba(255, 255, 255, 0.08) !important;
    background: #0f0f0f !important;
    min-height: 280px;
    cursor: pointer;
}

.studio-card-bg-container {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 1;
    overflow: hidden;
}

.studio-card-bg-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
    filter: brightness(0.7) contrast(1.1);
}

.studio-card-glass:hover .studio-card-bg-img {
    transform: scale(1.08);
    filter: brightness(0.8) contrast(1.15);
}

.studio-card-gradient {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(to bottom, 
        rgba(5, 5, 5, 0.2) 0%, 
        rgba(5, 5, 5, 0.5) 50%, 
        rgba(5, 5, 5, 0.95) 100%);
    z-index: 2;
}

.studio-card-content {
    position: relative;
    z-index: 3;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    background: transparent !important;
}

.studio-rating-glass {
    background: rgba(255, 255, 255, 0.1);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.15);
    padding: 6px 12px;
    border-radius: 30px;
    display: flex;
    align-items: center;
    box-shadow: var(--sh-elev-2-shadow);
}

.studio-logo-glass {
    width: 48px;
    height: 48px;
    border: 2px solid rgba(255, 255, 255, 0.2);
    box-shadow: var(--sh-elev-2-shadow);
    object-fit: cover;
    background: #111;
}

.studio-logo-glass-placeholder {
    width: 48px;
    height: 48px;
    background: rgba(255, 255, 255, 0.1);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.15);
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: var(--sh-elev-2-shadow);
}

.studio-title-shadow {
    text-shadow: 0 2px 10px rgba(0,0,0,0.8);
    letter-spacing: -0.02em;
}

.studio-desc-glass {
    text-shadow: 0 1px 4px rgba(0,0,0,0.6);
    line-height: 1.5;
    opacity: 0.9;
}

.smaller { font-size: 0.7rem; }
.tracking-widest { letter-spacing: 0.15em; }

/* Premium Discover Cards */
.discover-card {
    background: rgba(15, 15, 15, 0.6) !important;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.08) !important;
}

.discover-card:hover {
    background: rgba(20, 20, 20, 0.8) !important;
    border-color: rgba(255, 255, 255, 0.15) !important;
}

.btn-outline-purple {
    color: var(--sh-purple) !important;
    border: 1px solid var(--sh-purple) !important;
    background: rgba(155, 89, 182, 0.05) !important;
}

.btn-outline-purple:hover {
    background: var(--sh-purple) !important;
    color: white !important;
    box-shadow: 0 4px 15px var(--sh-purple-glow);
}

.btn-outline-amber {
    color: var(--sh-amber) !important;
    border: 1px solid var(--sh-amber) !important;
    background: rgba(212, 165, 116, 0.05) !important;
}

.btn-outline-amber:hover {
    background: var(--sh-amber) !important;
    color: black !important;
    box-shadow: 0 4px 15px var(--sh-amber-glow);
}

.bg-purple { background-color: var(--sh-purple) !important; }
.text-purple { color: var(--sh-purple) !important; }
.bg-amber { background-color: var(--sh-amber) !important; }
.text-amber { color: var(--sh-amber) !important; }

/* Large checkable "switch" button — replaces plain <input type=checkbox> for on/off
   settings across onboarding/settings forms so the whole row is a tappable target,
   consistent with the pill-button pattern already used for multi-select options. */
.sh-toggle-switch {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    width: 100%;
    padding: 0.9rem 1.1rem;
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid var(--sh-gray-800);
    border-radius: 10px;
    color: rgba(255, 255, 255, 0.75);
    font-weight: 600;
    text-align: left;
    transition: border-color 140ms ease, background-color 140ms ease, color 140ms ease;
}

.sh-toggle-switch:hover { border-color: rgba(255, 255, 255, 0.28); }

.sh-toggle-switch.active {
    background: var(--sh-gold-glow);
    border-color: var(--sh-gold);
    color: var(--sh-white);
}

.sh-toggle-switch-indicator {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    flex-shrink: 0;
    border-radius: 50%;
    border: 2px solid rgba(255, 255, 255, 0.25);
    color: transparent;
    transition: all 140ms ease;
}

.sh-toggle-switch.active .sh-toggle-switch-indicator {
    background: var(--sh-gold);
    border-color: var(--sh-gold);
    color: var(--sh-black);
}

.card-header {
    background-color: var(--sh-gray-800) !important;
    border-bottom: 1px solid var(--sh-gray-700) !important;
    padding: 1.25rem !important;
}

/* Global Contrast Fixes */
.card-title {
    color: var(--sh-white) !important;
    text-shadow: 0 2px 4px rgba(0,0,0,0.8) !important;
    font-weight: 600 !important;
}

.card-text {
    color: rgba(255,255,255,0.9) !important;
    text-shadow: 0 1px 2px rgba(0,0,0,0.5) !important;
}

.text-muted {
    color: rgba(255,255,255,0.7) !important;
    text-shadow: 0 1px 2px rgba(0,0,0,0.5) !important;
}

/* Unified Status Pills */
.status-pill {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 16px;
    border-radius: 100px;
    font-size: 0.7rem;
    font-weight: 800;
    letter-spacing: 0.05em;
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.08);
    text-transform: uppercase;
    white-space: nowrap;
}

/* La pastille réduite à son point : même couleur, même bordure, plus de mot. Le point garde sa
   taille — c'est lui l'information — et la boîte se referme dessus. */
.status-pill--dot {
    gap: 0;
    padding: 4px;
    justify-content: center;
}

.status-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    flex-shrink: 0;
}

/* Six tons, six significations. Rien d'autre.

   Vingt règles vivaient ici, une par valeur d'énumération, avec douze teintes prises au catalogue
   Bootstrap. Après un premier dégraissage il en restait cinq, et un défaut de fond : le même cyan
   disait « acompte débité » et « paiement total débité ». Or c'est la distinction qui compte pour
   celui qui attend son argent.

   Le bleu dit qu'une partie est payée, le vert que tout l'est. Ils ne se ressemblent pas. Le
   violet, lui, ne sert qu'à ce qui bouge en ce moment — une session en cours, un remboursement en
   chemin. Le ton vient de StatusVocabulary ; la palette est celle de l'application. */

.status-pill.tone-success { color: var(--sh-green); border-color: rgba(74, 222, 128, 0.25); }
.status-pill.tone-success .status-dot { background: var(--sh-green); box-shadow: 0 0 10px var(--sh-green); }

.status-pill.tone-warning { color: var(--sh-amber); border-color: var(--sh-amber-glow); }
.status-pill.tone-warning .status-dot { background: var(--sh-amber); box-shadow: 0 0 10px var(--sh-amber); }

.status-pill.tone-danger { color: #ff8b8b; border-color: rgba(255, 71, 71, 0.28); }
.status-pill.tone-danger .status-dot { background: #ff4747; box-shadow: 0 0 10px #ff4747; }

.status-pill.tone-info { color: var(--sh-blue); border-color: rgba(77, 171, 247, 0.28); }
.status-pill.tone-info .status-dot { background: var(--sh-blue); box-shadow: 0 0 10px var(--sh-blue); }

/* La séance tourne : le rouge d'un enregistrement, et le point qui bat avec lui. C'est le seul
   ton animé — ailleurs, un statut ne bouge pas. */
.status-pill.tone-rec { color: #ff8b8b; border-color: rgba(255, 71, 71, 0.32); }
.status-pill.tone-rec .status-dot {
    background: #ff4747;
    box-shadow: 0 0 10px #ff4747;
    animation: status-rec-pulse 2s ease-in-out infinite;
}

@keyframes status-rec-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
    .status-pill.tone-rec .status-dot { animation: none; }
}

.status-pill.tone-purple { color: #c88ee0; border-color: rgba(155, 89, 182, 0.32); }
.status-pill.tone-purple .status-dot { background: var(--sh-purple); box-shadow: 0 0 10px var(--sh-purple); }

.status-pill.tone-neutral { color: rgba(255, 255, 255, 0.55); border-color: rgba(255, 255, 255, 0.14); }
.status-pill.tone-neutral .status-dot { background: rgba(255, 255, 255, 0.45); }

.btn-outline-elite {
    color: var(--sh-gold) !important;
    border: 1px solid var(--sh-gold) !important;
    background: rgba(240, 180, 0, 0.05) !important;
    text-shadow: 0 1px 2px rgba(0,0,0,0.5) !important;
    font-weight: 700 !important;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    transition: all 0.3s ease;
}

.btn-outline-elite:hover {
    background: var(--sh-gold) !important;
    color: var(--sh-black) !important;
    text-shadow: none !important;
    border-color: var(--sh-gold) !important;
    transform: translateY(-2px);
    box-shadow: 0 4px 15px var(--sh-gold-glow);
}

.btn-gold {
    background: linear-gradient(135deg, var(--sh-gold) 0%, var(--sh-gold-deep) 100%) !important;
    color: var(--sh-black) !important;
    border: none !important;
    font-weight: 800 !important;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    text-shadow: none !important;
    box-shadow: var(--sh-elev-2-shadow);
    transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

.btn-gold:hover {
    background: linear-gradient(135deg, #ffd54f 0%, var(--sh-gold) 100%) !important;
    transform: translateY(-2px) scale(1.02);
    box-shadow: 0 8px 25px var(--sh-gold-glow);
    color: var(--sh-black) !important;
}

.btn-gold:focus, .btn-gold.focus {
    box-shadow: 0 0 0 0.2rem rgba(240, 180, 0, 0.25) !important;
}

.form-check-input:checked {
    background-color: var(--sh-gold) !important;
    border-color: var(--sh-gold) !important;
}

.nav-link {
    color: rgba(255,255,255,0.7) !important;
    font-weight: 500;
    transition: all 0.3s ease;
    padding: 0.5rem 1rem !important;
    border-radius: 8px;
}

.nav-link:hover {
    color: var(--sh-gold) !important;
    background: rgba(240, 180, 0, 0.05) !important;
}

.nav-link.active {
    color: var(--sh-gold) !important;
    background: rgba(240, 180, 0, 0.1) !important;
    font-weight: 700;
}

/* Fix for small text on badges */
.badge {
    font-weight: 600 !important;
    text-shadow: 0 1px 2px rgba(0,0,0,0.3) !important;
}

/* Better contrast for form controls */
.form-control {
    background-color: var(--sh-gray-800) !important;
    border-color: var(--sh-gray-700) !important;
    color: var(--sh-white) !important;
}

.form-control:focus {
    background-color: var(--sh-gray-950) !important;
    border-color: var(--sh-gold) !important;
    color: var(--sh-white) !important;
    box-shadow: 0 0 0 0.2rem rgba(240, 180, 0, 0.25) !important;
}

/* Elite Buttons */
.btn-gold {
    background-color: var(--sh-gold) !important;
    color: #000 !important;
    font-weight: 700 !important;
    border-radius: 8px !important;
    padding: 0.75rem 1.5rem !important;
    border: none !important;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.btn-gold:hover {
    transform: scale(1.02);
    box-shadow: 0 0 15px var(--sh-gold-glow);
}

.btn-gold:disabled {
    opacity: 0.65 !important;
    cursor: not-allowed !important;
    transform: none !important;
    box-shadow: none !important;
}

.btn-amber {
    background-color: var(--sh-amber) !important;
    color: #000 !important;
    font-weight: 700 !important;
    border-radius: 8px !important;
    padding: 0.75rem 1.5rem !important;
    border: none !important;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.btn-amber:hover {
    transform: scale(1.02);
    box-shadow: 0 0 15px var(--sh-amber-glow);
}

.btn-outline-elite {
    border: 1px solid var(--sh-gray-700) !important;
    color: var(--sh-white) !important;
    border-radius: 8px !important;
    font-weight: 600;
}

.btn-outline-elite:hover {
    border-color: var(--sh-gold) !important;
    color: var(--sh-gold) !important;
    background: rgba(240, 180, 0, 0.05) !important;
}

/* Form Styling */
.form-control {
    background-color: var(--sh-gray-950) !important;
    border: 1px solid var(--sh-gray-800) !important;
    color: var(--sh-white) !important;
    border-radius: 8px !important;
    padding: 0.8rem 1rem !important;
}

.form-control:focus {
    border-color: var(--sh-amber) !important;
    box-shadow: 0 0 0 2px var(--sh-amber-glow) !important;
}

.form-range::-webkit-slider-thumb {
    background-color: var(--sh-gold) !important;
}

.form-range::-moz-range-thumb {
    background-color: var(--sh-gold) !important;
    border: none !important;
}

/* Animations Helpers */
.hover-lift {
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.hover-lift:hover {
    transform: translateY(-4px);
}

.text-gold {
    color: var(--sh-gold) !important;
}

.bg-gold {
    background-color: var(--sh-gold) !important;
    color: var(--sh-black) !important;
}

.border-gold {
    border-color: var(--sh-gold) !important;
}

.sh-onboarding-shell {
    background: linear-gradient(180deg, rgba(15, 15, 15, 0.95) 0%, rgba(5, 5, 5, 0.95) 100%);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 14px;
    padding: 1.25rem;
}

.sh-onboarding-progress {
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    background: rgba(10, 10, 10, 0.85);
    padding: 0.9rem 1rem;
}

.sh-onboarding-progress .progress {
    height: 6px !important;
    background: var(--sh-gray-800) !important;
    border-radius: 999px;
}

.sh-onboarding-progress .progress-bar {
    background: linear-gradient(90deg, var(--sh-gold) 0%, var(--sh-amber) 100%) !important;
}

.sh-step-pill {
    border: 1px solid rgba(240, 180, 0, 0.35);
    color: var(--sh-gold);
    background: rgba(240, 180, 0, 0.08);
    border-radius: 999px;
    padding: 0.2rem 0.65rem;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.sh-required-note {
    color: rgba(255, 255, 255, 0.72);
    font-size: 0.8rem;
}

.sh-flow-steps {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.75rem;
    margin-bottom: 1rem;
}

.sh-flow-step {
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.02);
    color: rgba(255, 255, 255, 0.65);
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 0.65rem 0.8rem;
    text-align: center;
}

.sh-flow-step.active {
    border-color: rgba(240, 180, 0, 0.55);
    background: rgba(240, 180, 0, 0.1);
    color: var(--sh-gold);
}

.sh-flow-step.complete {
    border-color: rgba(40, 167, 69, 0.45);
    background: rgba(40, 167, 69, 0.1);
    color: #5cd38a;
}

@media (max-width: 768px) {
    /* « max() » et non une somme : en portrait les encoches latérales valent zéro et le
       rembourrage reste celui qu'on a choisi ; en paysage, c'est l'encoche qui commande, sans
       s'ajouter à lui. */
    .content {
        padding-block: 0 !important;
        padding-left: max(1rem, env(safe-area-inset-left, 0px)) !important;
        padding-right: max(1rem, env(safe-area-inset-right, 0px)) !important;
    }

    .sh-onboarding-shell {
        padding: 0.8rem;
    }

    .sh-flow-steps {
        grid-template-columns: 1fr;
    }
}

/* Custom Spinner */
.sh-spinner-elite {
    width: 44px;
    height: 44px;
    border: 3px solid rgba(255, 255, 255, 0.05);
    border-top: 3px solid var(--sh-gold);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

.help-text i {
    color: var(--sh-gold);
}

@keyframes pulse-gold {
    0% { outline-color: rgba(240, 180, 0, 0.5); }
    50% { outline-color: rgba(240, 180, 0, 1); }
    100% { outline-color: rgba(240, 180, 0, 0.5); }
}

/* Initial Loader */
.initial-loader {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    background-color: #050505;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: var(--sh-z-critical);
}

.loader-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.loader-text {
    margin-top: 1.5rem;
    font-weight: 800;
    letter-spacing: 0.35em;
    font-size: 0.9rem;
    animation: pulse-text 1.5s ease-in-out infinite;
    text-align: center;
}

.loader-text .sh-brand-studio,
.loader-text .sh-brand-hub {
    letter-spacing: 0.35em;
}

@keyframes pulse-text {
    0%, 100% { opacity: 0.4; transform: scale(0.98); }
    50% { opacity: 1; transform: scale(1); }
}

.reservation-room-card.selected {
    border-color: rgba(240, 180, 0, 0.55);
    background: rgba(240, 180, 0, 0.1);
}

/* Auth — instant login/register switch (no full-page loader) */
.auth-page .auth-card-shell {
    background: linear-gradient(135deg, var(--sh-gray-900) 0%, var(--sh-black) 100%) !important;
    border: 1px solid var(--sh-gray-800) !important;
    transform-origin: top center;
}

.auth-card-shell--leaving {
    opacity: 0.82;
    transform: translateY(-5px);
    transition: opacity 110ms ease, transform 110ms ease;
}

.auth-card-shell--morphing {
    transition:
        height 400ms cubic-bezier(0.22, 1, 0.36, 1),
        opacity 220ms ease,
        transform 400ms cubic-bezier(0.22, 1, 0.36, 1);
    will-change: height, opacity, transform;
}

.auth-card-header {
    background: transparent !important;
    border-bottom: 1px solid var(--sh-gray-800) !important;
}

.auth-mode-tabs {
    display: flex;
    gap: 0.5rem;
    padding: 0.25rem;
    background: var(--sh-gray-950);
    border-radius: 10px;
    border: 1px solid var(--sh-gray-800);
}

.auth-mode-tab {
    flex: 1;
    border: none;
    background: transparent;
    color: var(--sh-muted);
    font-weight: 700;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 0.65rem 1rem;
    border-radius: 8px;
    transition: color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}

.auth-mode-tab.active {
    color: var(--sh-black);
    background: var(--sh-gold);
    box-shadow: 0 0 16px var(--sh-gold-glow);
}

.auth-mode-tab:not(.active):hover {
    color: var(--sh-white);
}

.auth-panel {
    animation: authPanelIn 0.22s ease-out;
}

@keyframes authPanelIn {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .auth-card-shell--leaving,
    .auth-card-shell--morphing,
    .auth-panel {
        animation: none !important;
        transition: none !important;
    }
}

.sh-money-gold {
    color: var(--sh-gold) !important;
    font-variant-numeric: tabular-nums;
}

/* /studios/my — sober owner studio selector */
.studios-my-loading {
    padding: 4rem 0;
    text-align: center;
    color: rgba(255, 255, 255, 0.55);
}

.studios-my-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 1rem;
    margin: 1.5rem 0 1rem;
    padding-bottom: 1.25rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.studios-my-label {
    color: var(--sh-gold);
    font-size: 0.76rem;
    font-weight: 800;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    margin-bottom: 0.35rem;
}

.studios-my-header h1 {
    color: var(--sh-white);
    font-size: clamp(2rem, 4vw, 3rem);
    font-weight: 850;
    letter-spacing: -0.045em;
    margin: 0;
}

.studios-my-header p {
    color: rgba(255, 255, 255, 0.58);
    margin: 0.35rem 0 0;
}

.studios-my-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 0.6rem;
}

.studios-my-note,
.studios-my-plan {
    margin-bottom: 1rem;
}

.studios-my-plan {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.65rem 1rem;
    padding: 0.85rem 1rem;
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.025);
    color: rgba(255, 255, 255, 0.62);
    font-size: 0.9rem;
}

.studios-my-plan strong {
    color: var(--sh-white);
}

.studios-my-plan .btn-link {
    color: var(--sh-gold);
    text-decoration: none;
    font-weight: 700;
}

.studios-my-list {
    display: grid;
    gap: 0.75rem;
}

.studios-my-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    padding: 1rem;
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 14px;
    background: rgba(12, 12, 12, 0.72);
}

.studios-my-row h2 {
    color: var(--sh-white);
    font-size: 1.05rem;
    font-weight: 800;
    margin: 0 0 0.35rem;
}

.studios-my-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 0.85rem;
    color: rgba(255, 255, 255, 0.56);
    font-size: 0.88rem;
}

.studios-my-empty {
    padding: 2.5rem 1rem;
    text-align: center;
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 14px;
    background: rgba(12, 12, 12, 0.72);
}

.studios-my-empty h2 {
    color: var(--sh-white);
    font-size: 1.35rem;
    font-weight: 850;
    margin-bottom: 0.5rem;
}

.studios-my-empty p {
    color: rgba(255, 255, 255, 0.58);
    max-width: 560px;
    margin: 0 auto 1.25rem;
}

@media (max-width: 768px) {
    .studios-my-header,
    .studios-my-row {
        align-items: stretch;
        flex-direction: column;
    }

    .studios-my-actions,
    .studios-my-actions .btn,
    .studios-my-row .btn {
        width: 100%;
    }
}

.sh-money-glow,
.sh-money-highlight {
    text-shadow: 0 0 14px rgba(217, 166, 83, 0.35);
    animation: shMoneyGlow 1.4s ease-out 1;
}

@keyframes shMoneyGlow {
    0% { text-shadow: 0 0 0 rgba(217, 166, 83, 0); transform: scale(1); }
    35% { text-shadow: 0 0 18px rgba(217, 166, 83, 0.55); transform: scale(1.015); }
    100% { text-shadow: 0 0 10px rgba(217, 166, 83, 0.25); transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
    .sh-money-glow,
    .sh-money-highlight {
        animation: none;
        text-shadow: none;
    }
}

/* ── Champ téléphone : indicatif + numéro ──────────────────────────────────────
   Une seule définition, partagée par l'inscription et les réglages studio. Les deux
   portaient chacune leur copie, et elles avaient divergé : celle du studio n'avait
   aucune règle de largeur, si bien que le champ numéro était écrasé par le sélecteur
   d'indicatif dans une colonne étroite.

   Le sélecteur se dimensionne sur son contenu (voir CountryDropdown.razor.css) et le
   numéro prend tout le reste. Le min-width est ce qui empêche l'écrasement : sans lui,
   flex réduit un champ de saisie jusqu'à le rendre inutilisable. */
.sh-phone-field {
    display: flex;
    flex-wrap: nowrap;
    align-items: stretch;
}

.sh-phone-field > .form-control {
    flex: 1 1 auto;
    min-width: 8rem;
    /* Soudé au sélecteur, qui porte l'arrondi gauche. */
    border-radius: 0 0.5rem 0.5rem 0 !important;
}

/* Sous 576px les deux champs s'empilent : côte à côte, le numéro passerait
   sous le seuil de lisibilité. */
@media (max-width: 576px) {
    .sh-phone-field {
        flex-direction: column;
        gap: 0.75rem;
    }

    .sh-phone-field > .form-control {
        width: 100%;
        border-radius: 0.5rem !important;
    }
}

/* ── Utilitaires remontés depuis les pages ─────────────────────────────────
   Ces deux règles étaient recopiées à l'identique dans plusieurs <style> en
   ligne : .fw-800 dans sept pages, .engineer-space-page--embedded dans les
   quatre onglets de l'espace ingénieur. Un <style> en ligne étant global, la
   règle n'existait que si la page qui la portait était affichée — un composant
   partagé perdait donc la graisse 800 selon l'écran d'où on l'ouvrait. */

.fw-800 { font-weight: 800; }

/* Largeur des onglets de l'espace ingénieur quand ils sont rendus dans le
   shell de l'espace de travail plutôt qu'en page pleine. */
.engineer-space-page--embedded {
    width: 100%;
    max-width: 1280px;
    margin: 0 auto;
    padding: 0.25rem 0 0;
}

/* ── Classes posées un peu partout mais définies nulle part ────────────────
   .btn-outline-gold est employé dans dix fichiers — barre d'actions du panneau
   studio, récapitulatifs ingénieur, réglages de profil, confirmation d'email —
   et n'existait que dans le <style> en ligne d'AddRoom. Partout ailleurs le
   bouton retombait sur le .btn nu de Bootstrap, sans bordure ni couleur.
   .elite-day-card, définie par l'accueil ingénieur, est posée par ses
   récapitulatifs, qui vivent sur un autre onglet : la carte y était plate. */

.btn-outline-gold {
    color: var(--sh-gold);
    border-color: var(--sh-gold);
}

.btn-outline-gold:hover {
    background-color: var(--sh-gold);
    color: black;
}

.elite-day-card {
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.03) 0%, rgba(0, 0, 0, 0.2) 100%);
}

/* Aplats de gris, recopiés en dur dans deux profils publics et l'écran de
   paiement — dont un #0a0a0a qui ne correspondait à aucun jeton. */
.bg-gray-700 { background-color: var(--sh-gray-700) !important; }
.bg-gray-800 { background-color: var(--sh-gray-800) !important; }
.bg-gray-900 { background-color: var(--sh-gray-900) !important; }

/* ── Habillage sombre des contrôles de formulaire ──────────────────────────
   .form-select est posée dans douze fichiers — onboarding, disponibilités,
   réservation, réglages studio — mais n'était habillée que dans les <style> en
   ligne de Register et CreateStudio. Ailleurs, le sélecteur restait au blanc
   par défaut de Bootstrap sur fond noir, et sa liste déroulante avec. */

.form-select {
    background-color: var(--sh-gray-950) !important;
    border: 1px solid var(--sh-gray-800) !important;
    color: var(--sh-white) !important;
}

.form-select option {
    background-color: var(--sh-gray-900) !important;
    color: var(--sh-white) !important;
}

.form-control:focus, .form-select:focus {
    border-color: var(--sh-gold) !important;
    box-shadow: 0 0 0 0.25rem rgba(255, 204, 0, 0.15) !important;
}

/* Utilitaires posés dans plusieurs écrans, définis dans un seul jusqu'ici. */
.border-dashed { border-style: dashed !important; }
.cursor-pointer { cursor: pointer; }

/* Onglet actif du sélecteur liste/calendrier de l'espace ingénieur : même
   traitement que le survol, déjà global. */
.btn-outline-elite.active {
    color: white;
    background: rgba(255, 255, 255, 0.1);
    border-color: rgba(255, 255, 255, 0.2);
}

/* ── Carte de choix de rôle ────────────────────────────────────────────────
   .role-card est posée par le choix de rôle et par les réglages de profil, mais
   chacun en écrivait sa propre version dans un <style> en ligne : bordure verte
   d'un côté, dorée de l'autre, pour le même état sélectionné. Le vert est
   conservé — le doré sert déjà au survol, et garder les deux rendait
   « survolé » et « choisi » indiscernables. */

.role-card {
    cursor: pointer;
    transition: all 0.3s ease;
}

.role-card:hover {
    border-color: var(--sh-gold) !important;
    transform: translateY(-5px);
    box-shadow: 0 10px 30px rgba(255, 204, 0, 0.2);
}

.role-card.selected {
    border-color: #198754 !important;
    background: rgba(25, 135, 84, 0.1) !important;
    box-shadow: 0 0 30px rgba(25, 135, 84, 0.3);
}

/* ---- Actions métier ------------------------------------------------------
   Un seul vocabulaire de boutons pour tout /app : accepter, refuser, démarrer,
   clôturer, encaisser, annuler.

   Ces règles vivaient dans la feuille scopée du détail de réservation, où elles
   étaient nées. Les panneaux, eux, employaient les boutons Bootstrap — btn-success,
   btn-outline-danger, btn-outline-elite — si bien que le même geste changeait
   d'apparence selon qu'on l'accomplissait depuis le détail ou depuis le panneau
   rapide. Remontées ici, elles s'appliquent partout ; une feuille scopée n'aurait
   jamais pu servir un autre composant.

   Deux tons seulement : ce qui fait avancer la session, ce qui l'arrête. Le reste
   est neutre. Trois couleurs de plus n'ajouteraient aucune information. */

.sh-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.9rem;
}

/* En colonne, quand les actions occupent le pied d'un panneau plutôt qu'une ligne. */
.sh-actions--stacked {
    flex-direction: column;
    flex-wrap: nowrap;
}

.sh-action {
    display: inline-flex;
    text-decoration: none;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
    padding: 0.5rem 1rem;
    border-radius: var(--sh-radius-aero-sm);
    border: 1px solid var(--sh-glass-border);
    background: var(--sh-glass-bg-raised);
    color: rgba(255, 255, 255, 0.85);
    font-size: 0.84rem;
    font-weight: 700;
    box-shadow: var(--sh-glass-specular);
    transition: transform var(--sh-duration-aero) var(--sh-ease-liquid),
                background var(--sh-duration-aero);
}

.sh-action:active { transform: translateY(1px); }

/* Pendant qu'une action tourne, les boutons se ferment — l'écran, lui, reste lisible. */
.sh-action:disabled {
    opacity: 0.45;
    transform: none;
    cursor: progress;
}

.sh-action--go {
    border-color: var(--sh-accent-edge);
    background: var(--sh-accent-soft);
    color: var(--sh-accent);
}

.sh-action--stop {
    border-color: rgba(255, 71, 71, 0.32);
    background: rgba(255, 71, 71, 0.1);
    color: #ff8b8b;
}

/* La pastille qui nomme un espace, partout où une ligne peut venir de plusieurs à la fois.

   Qui est ingénieur chez un studio et artiste ailleurs recevait « Séance confirmée » sans savoir
   laquelle de ses deux vies était concernée. Le mot le disait déjà, en gris, à côté de l'heure —
   du même gris que l'heure elle-même, donc lu en dernier ou pas du tout. La couleur le dit avant
   le mot, et c'est celle de l'espace, la même que porte le sélecteur de la barre du haut. */
.sh-space {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.05rem 0.45rem;
    border: 1px solid transparent;
    border-radius: 999px;
    font-size: 0.66rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
}

.sh-space > i { font-size: 0.9em; }

.sh-space--owner {
    color: var(--sh-space-owner);
    background: var(--sh-space-owner-soft);
    border-color: var(--sh-space-owner-edge);
}

/* ── Où suis-je ────────────────────────────────────────────────────────────────────────────
   La coquille d'un espace remet l'accent, et tout ce qu'elle contient l'hérite. C'est le seul
   endroit qui nomme une couleur d'espace : le reste de l'application écrit « --sh-accent ».

   Le fond suit la même règle. Les trois espaces partageaient exactement le même noir : rien,
   à part le mot en haut de la page, ne disait lequel on regardait — et le mot part au défilement.
   Un voile d'à peine cinq centièmes, tombant du haut, se lit sans se voir : on ne saurait pas
   dire qu'il est là, on saurait dire qu'on a changé d'espace. */
.page:has(.app-space-shell--owner) { --sh-accent: var(--sh-space-owner); --sh-accent-soft: var(--sh-space-owner-soft); --sh-accent-edge: var(--sh-space-owner-edge); --sh-accent-ground: var(--sh-space-owner-ground); }
.page:has(.app-space-shell--engineer) { --sh-accent: var(--sh-space-engineer); --sh-accent-soft: var(--sh-space-engineer-soft); --sh-accent-edge: var(--sh-space-engineer-edge); --sh-accent-ground: var(--sh-space-engineer-ground); }
.page:has(.app-space-shell--artist) { --sh-accent: var(--sh-space-artist); --sh-accent-soft: var(--sh-space-artist-soft); --sh-accent-edge: var(--sh-space-artist-edge); --sh-accent-ground: var(--sh-space-artist-ground); }

.app-space-shell--owner,
.app-space-shell--engineer,
.app-space-shell--artist {
    /* Le voile ne suit pas le défilement : il appartient à l'espace, pas à la page. */
    background-image: radial-gradient(140% 420px at 50% 0%, var(--sh-accent-ground), transparent 70%);
    background-repeat: no-repeat;
}

/* Dans un espace, la barre du haut et l'espace se touchent, et c'est la barre qui porte le trait
   de couleur.

   Il vivait sur la coquille, un rang plus bas : vingt-quatre pixels de fond séparaient donc la
   barre de son propre trait, et le trait s'en allait au défilement pendant que la barre restait.
   Une ligne de séparation qui ne sépare rien de contigu est pire qu'aucune ligne — elle se lit
   comme un défaut d'assemblage, et c'est exactement ce qu'elle était. */
.page:has(.app-space-shell) > .sh-site-header {
    margin-bottom: 0;
    border-bottom: 1px solid var(--sh-accent-edge);
}

.sh-space--engineer {
    color: var(--sh-space-engineer);
    background: var(--sh-space-engineer-soft);
    border-color: var(--sh-space-engineer-edge);
}

.sh-space--artist {
    color: var(--sh-space-artist);
    background: var(--sh-space-artist-soft);
    border-color: var(--sh-space-artist-edge);
}

/* Les faits d'une ligne de file : quand, combien, jusqu'à quand.

   Globale et non isolée : la même ligne existe dans trois espaces, et l'isolation CSS attache
   la classe au fichier qui écrit le balisage — trois copies de la même règle, libres de diverger
   au premier ajustement. C'est le pendant de .sh-action, qui l'est déjà pour les mêmes raisons.

   Un fait est une étiquette et une valeur, sur une ligne, séparés par un point médian implicite
   (l'espacement). L'espace de l'ingénieur les posait en pastilles à deux tons, empilées : sept
   pastilles hautes de 40 px pour quatre informations, et sur un téléphone la ligne « à traiter »
   occupait un écran entier avant qu'on ait pu lire le montant. La règle est celle de la file :
   ce qui décide du geste tient sur la ligne, tout le reste vit dans l'aperçu, à un clic. */
.sh-fact {
    display: inline-flex;
    align-items: baseline;
    gap: 0.35rem;
    color: rgba(255, 255, 255, 0.75);
    font-size: 0.78rem;
    line-height: 1.4;
    font-variant-numeric: tabular-nums;
}

.sh-fact > i {
    align-self: center;
    color: rgba(255, 255, 255, 0.35);
    font-size: 0.85em;
}

/* L'étiquette ne se lit qu'en second : c'est la valeur qu'on vient chercher. */
.sh-fact-label {
    color: rgba(255, 255, 255, 0.38);
    font-size: 0.72rem;
}

/* L'argent porte l'ambre, comme partout ailleurs. */
.sh-fact--money { color: var(--sh-amber); font-weight: 750; }
.sh-fact--money > i { color: var(--sh-amber); }

/* Une échéance qui court, et celle qui a expiré. */
.sh-fact--urgent { color: #f0c34f; }
.sh-fact--urgent > i { color: #f0c34f; }
.sh-fact--late { color: #ef8585; }
.sh-fact--late > i { color: #ef8585; }

/* Régler. Le seul geste qui sort de l'argent de la poche de celui qui clique.

   Il portait l'aqua de « --go », la même que « Accepter », « Ouvrir », « Désigner » : rien ne le
   distinguait d'un geste de navigation, alors que c'est le seul de l'écran qui débite une carte.
   L'or est réservé à l'argent dans cette charte — c'est précisément le cas ici. */
.sh-action--pay {
    border-color: var(--sh-gold);
    background: var(--sh-gold);
    color: #17120a;
    font-weight: 800;
    box-shadow: var(--sh-glass-specular), 0 6px 18px var(--sh-gold-glow);
}

.sh-action--pay:hover,
.sh-action--pay:focus-visible { background: var(--sh-gold-deep); border-color: var(--sh-gold-deep); }

/* Attente d'un tiers : ni avancer ni arrêter, on patiente. */
.sh-action--wait {
    border-color: rgba(240, 180, 0, 0.32);
    background: rgba(240, 180, 0, 0.1);
    color: #f0c34f;
}

/* ── Le doigt ────────────────────────────────────────────────────────────────

   Le mobile est la plateforme de vente principale, et rien n'y était dimensionné pour un doigt :
   les boutons d'action faisaient 36 px de haut, l'interrupteur 30, plusieurs pastilles 32. Le
   seuil confortable est 44 px — en dessous, on vise et on rate, ce qui se paie en abandons sur
   un tunnel d'achat.

   Posé globalement plutôt que dans chaque feuille scopée : la règle est la même partout, et une
   quinzaine de copies auraient divergé à la première retouche. */

@media (max-width: 700px) {
    .sh-action,
    .btn,
    .role-workspace-link,
    .nav-link,
    .dropdown-item {
        min-height: 44px;
    }

    /* Les boutons qui n'ont qu'une icône doivent aussi être larges de 44 px : un carré de
       36 px se rate par le côté autant que par le haut. */
    .sh-sidepanel-close,
    .btn-close,
    .navbar-toggler {
        min-width: 44px;
        min-height: 44px;
    }

    /* L'interrupteur garde ses proportions — c'est une piste, pas un bouton — mais gagne une
       zone de frappe autour de lui. */
    .sht { padding: 0.4rem 0; }
}

/* ── L'encoche et la barre d'accueil ─────────────────────────────────────────

   Tout ce qui se colle en bas d'un iPhone passe sous la barre d'accueil : le volet de
   réservation, la barre REC, le pied du panneau. Une seule règle le disait dans toute
   l'application, sur un seul écran. */

.sh-safe-bottom {
    padding-bottom: calc(var(--sh-safe-bottom-pad, 1rem) + env(safe-area-inset-bottom));
}

@supports (padding: env(safe-area-inset-bottom)) {
    .selection-panel.visible {
        margin-bottom: env(safe-area-inset-bottom);
    }
}

/* En ligne, quand les actions coiffent une page plutôt qu'une colonne étroite.

   Les mêmes boutons, empilés, s'étiraient d'un bord à l'autre de l'écran — une ligne entière
   pour trois mots. Ici ils prennent la largeur de leur libellé et se replient s'il en manque. */
.sh-actions--inline {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
}

.sh-actions--inline .sh-action {
    flex: 0 0 auto;
    width: auto;
    min-width: 0;
}

/* La phrase qui explique un bouton inerte passe à la ligne, seule : intercalée entre deux
   boutons elle les séparerait sans rien y gagner. */
.sh-actions--inline .sp-line {
    flex: 1 0 100%;
    margin: 0;
}


/* ── Le vocabulaire monétaire du tunnel de paiement ──────────────────────────

   Deux écrans se suivent — le récapitulatif puis la confirmation — et chacun disait les mêmes
   montants à sa façon : « Montant du dépôt à payer » ici, « Acompte à payer » là, deux cartes
   dorées de formes différentes, et le reste dû mentionné sur l'un seulement.

   Remontées en partagé pour que le second écran ne réapprenne pas à lire au moment où l'argent
   part. */

   Or quand un solde suivra, vert quand c'est tout : la couleur doit dire si l'engagement est
   terminé. Le bloc était or dans les deux cas, et un paiement intégral ressemblait donc à un
   acompte de plus. */
.pay-now {
    margin-top: 1rem;
    padding: 0.9rem 1rem;
    text-align: center;
    background: rgba(240, 180, 0, 0.07);
    border: 1px solid rgba(240, 180, 0, 0.3);
    border-radius: 12px;
}

.pay-now h3 {
    margin: 0;
    color: var(--sh-gold);
    font-weight: 800;
}

.pay-now-label {
    color: rgba(255, 255, 255, 0.55);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

.pay-now--full {
    background: rgba(103, 207, 145, 0.08);
    border-color: rgba(103, 207, 145, 0.35);
}

.pay-now--full h3 { color: #67cf91; }

/* Ce qui restera dû après ce paiement. Ambre : ce n'est pas une alerte, c'est un engagement à
   venir — et il doit se voir avant de payer, pas le jour de la séance. */
.pay-rest {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    margin-top: 0.6rem;
    padding: 0.65rem 1rem;
    color: var(--sh-amber);
    background: rgba(212, 165, 116, 0.07);
    border: 1px solid var(--sh-amber-glow);
    border-radius: 10px;
    font-size: 0.82rem;
    font-weight: 650;
}

.pay-rest strong {
    font-size: 1rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
}

.pay-rest--settled {
    justify-content: flex-start;
    color: #67cf91;
    background: rgba(103, 207, 145, 0.07);
    border-color: rgba(103, 207, 145, 0.28);
}

/* Le renvoi entre le profil public d'un rôle et les paramètres du compte. Deux écrans portaient
   le même titre, on cherchait son mot de passe et on trouvait un tarif horaire. */
.profile-boundary {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 1.25rem 0 0;
    padding: 0.7rem 0.9rem;
    color: rgba(255, 255, 255, 0.5);
    background: rgba(255, 255, 255, 0.02);
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: 12px;
    font-size: 0.8rem;
}

.profile-boundary i { color: var(--sh-gold); }
.profile-boundary a { color: var(--sh-gold); }


/* Le décompte posé à droite d'un titre de section.

   Il s'écrivait « badge bg-warning text-dark » ici, « badge bg-secondary » là, « badge bg-gold »
   ailleurs : trois couleurs pour la même idée — combien d'éléments dans cette section. La couleur
   ne portait aucun sens, elle variait selon qui avait écrit l'écran. */
.section-count {
    padding: 0.1rem 0.55rem;
    color: rgba(255, 255, 255, 0.7);
    background: rgba(255, 255, 255, 0.08);
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 750;
    font-variant-numeric: tabular-nums;
}
/* Le détail technique d'un plantage : lisible pour qui le recopiera, effacé pour les autres. */
.crash-detail {
    max-width: 600px;
    margin: 0 auto;
    padding: 0.75rem 1rem;
    border-radius: var(--sh-radius-aero-sm);
    background: rgba(0, 0, 0, 0.5);
    color: rgba(255, 139, 139, 0.85);
    font-size: 0.8rem;
    word-break: break-word;
}

/* Pendant qu'un panneau de détail est ouvert, la liste derrière lui ne répond plus au clic :
   sans cela, on sélectionne une autre réservation à travers le voile. La règle vivait en double,
   dans le tableau de bord du studio et dans les réservations de l'artiste. */
.dashboard-wrapper.sidepanel-open .dashboard-main-content { pointer-events: none; }

/* Un espace de travail occupe toute la largeur : le rembourrage du gabarit, taillé pour des
   pages de contenu, couperait la barre latérale. La règle vise le gabarit depuis l'extérieur,
   elle ne peut donc pas vivre dans la feuille scopée de l'espace. */
.content:has(.app-space-shell) { max-width: none; padding-inline: 0 !important; }

/* ── L'argent ────────────────────────────────────────────────────────────────

   Trois montants, trois rôles, trois poids. Ce qui reste dû domine ; le total l'accompagne ; ce
   qui a été réglé s'efface sans disparaître. Ces classes sont globales parce qu'elles servent
   aussi bien dans une cellule de tableau que dans une fiche. */

.amounts {
    display: inline-flex;
    align-items: baseline;
    gap: 0.45rem;
    white-space: nowrap;
}

.amounts--stacked {
    flex-direction: column;
    align-items: flex-end;
    gap: 0.1rem;
}

/* Ce qui reste à payer : la seule information qu'on cherche vraiment. */
.amount-due {
    color: var(--sh-gold);
    font-size: 1.05rem;
    font-weight: 800;
}

.amount-total {
    color: rgba(255, 255, 255, 0.5);
    font-size: 0.78rem;
    font-weight: 600;
}

/* Plus rien à payer : le total grossit, mais reste blanc — c'est un total de séance, donc un
   brut, et un brut ne devient pas net parce que son solde est réglé. L'état « soldé » se lit
   déjà dans la pastille de paiement et dans le solde barré ci-dessous ; le vert est réservé à
   ce qui reste au studio une fois la commission et les frais déduits (voir SessionRecap). */
.amount-total--paid {
    color: #fff;
    font-size: 1.05rem;
    font-weight: 800;
}

/* Un solde qui a existé, puis a été réglé. */
.amount-cleared {
    color: rgba(255, 255, 255, 0.32);
    font-size: 0.78rem;
    font-weight: 600;
    text-decoration-thickness: 1px;
}

/* Une étiquette n'est pas un statut. Les équipements d'une salle empruntaient la pastille de
   statut, et donc son vocabulaire de couleurs : un micro n'a pas d'état. */
.tag {
    display: inline-flex;
    align-items: center;
    padding: 3px 10px;
    border-radius: 100px;
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid var(--sh-glass-border);
    color: rgba(255, 255, 255, 0.6);
    font-size: 0.72rem;
    font-weight: 600;
    white-space: nowrap;
}

/* Une pastille de genre ou d'équipement (complément de .tag ci-dessus) et la liste des membres
   d'une équipe : la fiche publique d'un studio et la page publique d'une salle doivent dessiner
   l'une et l'autre de façon identique. L'isolation CSS de Blazor scope chaque feuille
   « .razor.css » à son seul composant — deux composants ne peuvent donc jamais partager une
   règle en la posant chacun dans sa propre feuille, quoi qu'en dise un commentaire qui l'affirme.
   Cette feuille globale, elle, n'est isolée par rien : c'est ici, et nulle part dans un fichier
   « .razor.css », que ce genre de règle partagée doit vivre. */
.psp-tag {
    font-size: 0.8rem;
    padding: 5px 12px;
}

.psp-crew {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.5rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.psp-crew__member {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.psp-crew__member > i {
    color: var(--sh-gold, #d4af37);
}

/* La surface qui referme une couche temporaire au clic à côté.
   
   L'échappement et le changement de page passent par OverlayCoordinator ; le clic extérieur, lui,
   demande une surface à cliquer. La barre du haut en avait une, scopée chez elle ; les menus des
   autres écrans n'en avaient aucune et restaient ouverts. */
.sh-dismiss {
    position: fixed;
    inset: 0;
    z-index: var(--sh-z-dropdown);
    background: transparent;
}

/* ── L'explication d'un outil ─────────────────────────────────────────────────────────────────

   Cinquante-quatre « title="…" » disaient à quoi servent les boutons de l'application. Le
   navigateur les affiche après une seconde, dans sa propre police, sur un fond système qui ne
   ressemble à rien d'autre à l'écran — et jamais au doigt, où rien ne survole. L'explication
   existait donc, et ne se lisait qu'à la souris, tard, ailleurs.

   La bulle est au cran 3 : elle flotte au-dessus de ce qu'elle explique, sans le couvrir. Sa
   position est calculée en JavaScript (« placeTooltip ») parce qu'elle dépend de la hauteur du
   texte une fois retourné à la ligne — une mesure qu'aucune feuille de style n'a. */
.sh-tooltip {
    position: fixed;
    top: 0;
    left: 0;
    z-index: var(--sh-z-popover);
    max-width: min(280px, calc(100vw - 2rem));
    padding: 0.45rem 0.6rem;
    border-radius: 10px;
    background: var(--sh-elev-3-bg);
    border: 1px solid var(--sh-elev-3-border);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), var(--sh-elev-3-shadow);
    color: var(--sh-white, #fff);
    font-size: 0.78rem;
    line-height: 1.35;
    pointer-events: none;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;

    /* Invisible tant qu'elle n'est pas mesurée : sans cela, elle paraît un instant au coin
       supérieur gauche, là où elle est rendue avant d'être posée. */
    opacity: 0;
    transition: opacity 90ms ease;
}

.sh-tooltip.is-placed { opacity: 1; }

.sh-tooltip-title {
    font-size: 0.68rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--sh-accent);
}

/* La flèche vise le déclencheur, même quand la bulle a été ramenée dans l'écran et n'est donc
   plus centrée sur lui : « --sh-tooltip-arrow » est posée à la mesure. */
.sh-tooltip::after {
    content: "";
    position: absolute;
    left: var(--sh-tooltip-arrow, 50%);
    width: 8px;
    height: 8px;
    margin-left: -4px;
    background: var(--sh-elev-3-bg);
    border: 1px solid var(--sh-elev-3-border);
    transform: rotate(45deg);
}

.sh-tooltip--top::after {
    bottom: -5px;
    border-top: 0;
    border-left: 0;
}

.sh-tooltip--bottom::after {
    top: -5px;
    border-bottom: 0;
    border-right: 0;
}

/* Le déclencheur n'a pas d'allure propre : il enveloppe ce qui existait déjà. */
.sh-hint {
    display: inline-flex;
    align-items: center;
}

/* Et quand il ne doit même pas exister pour la mise en page : l'enfant redevient l'élément
   direct de la grille ou du flex qui le contient. */
.sh-hint--bare { display: contents; }

/* Le point d'aide, lui, se voit — mais discrètement : il accompagne un titre, il ne le concurrence
   pas. Il prend l'accent de l'espace une fois ouvert, comme tout ce qui dit « c'est ceci ». */
.sh-help-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--sh-gray-400, #9a9a9a);
    font-size: 0.85rem;
    line-height: 1;
    cursor: help;
    transition: color 120ms ease, background 120ms ease;
}

.sh-help-dot:hover,
.sh-help-dot:focus-visible,
.sh-help-dot.is-open {
    color: var(--sh-accent);
    background: var(--sh-accent-soft);
}

@media (prefers-reduced-motion: reduce) {
    .sh-tooltip { transition: none; }
}

/* ── Les raccourcis d'un espace ───────────────────────────────────────────────────────────────

   Quatre destinations en tête de vue d'ensemble. Le propriétaire les avait, dans sa feuille à
   lui ; l'ingénieur et l'artiste ouvraient sur des chiffres, qui se contemplent et ne mènent
   nulle part. Le rang est ici, global, parce que les trois espaces l'emploient — et l'icône prend
   l'accent de l'espace, seule différence entre eux. */
.sh-shortcuts {
    display: flex;
    align-items: stretch;
    gap: 0.5rem;
    margin-bottom: 0.9rem;
}

.sh-shortcuts-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
    gap: 0.5rem;
    flex: 1;
}

.sh-shortcut {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.65rem 0.85rem;
    color: #fff;
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 12px;
    font-size: 0.82rem;
    font-weight: 650;
    text-align: left;
    transition: background 160ms ease, border-color 160ms ease;
}

.sh-shortcut > i {
    color: var(--sh-accent);
    font-size: 1rem;
}

.sh-shortcut:hover,
.sh-shortcut:focus-visible {
    background: rgba(255, 255, 255, 0.06);
    border-color: var(--sh-accent-edge);
}

/* L'en-tête sombre à liseré or d'une carte de formulaire pleine page — copié en style inline
   dans quatre écrans (inscription par rôle, confirmation de courriel, création de salle, de
   studio) avant d'avoir sa classe. */
.sh-card-header-gold {
    background: linear-gradient(135deg, var(--sh-gray-900) 0%, var(--sh-black) 100%) !important;
    border-bottom: 1px solid var(--sh-gold) !important;
}

/* La modale « session expirée » passe devant tout le reste, y compris un autre voile déjà
   ouvert — un cran au-dessus de son propre fond. */
.sh-z-critical {
    z-index: var(--sh-z-critical);
}

.sh-z-critical-above {
    z-index: calc(var(--sh-z-critical) + 1);
}

/* ── Rien ne défile derrière un panneau ───────────────────────────────────────────────────────

   Le voile est fixe : il couvre la fenêtre, barre du haut comprise. Mais la page, elle, restait
   défilable dessous — et sur iOS, un élément fixe se décale visuellement pendant l'élan du
   défilement. D'où l'écran rapporté : le panneau ouvert, un coup de pouce, et la liste
   réapparaissait nette sous un voile parti trop haut. Le flou n'était pas en cause, la page
   qui bougeait derrière l'était.

   « :has » plutôt qu'une classe posée par le composant : neuf panneaux et modales ouvrent chacun
   le leur, et neuf endroits qui doivent penser à verrouiller finissent toujours par en oublier
   un. Ici, la présence du voile suffit — c'est la même condition qui fait le voile et le verrou. */
html:has(.sh-sidepanel-overlay),
html:has(.sh-modal-overlay),
html:has(.confirm-overlay),
html:has(.picker-overlay),
html:has(.pin-modal-overlay),
html:has(.invite-modal-overlay) {
    overflow: hidden;
}

body:has(.sh-sidepanel-overlay),
body:has(.sh-modal-overlay),
body:has(.confirm-overlay),
body:has(.picker-overlay),
body:has(.pin-modal-overlay),
body:has(.invite-modal-overlay) {
    overflow: hidden;
    overscroll-behavior: none;
}

/* Le consentement à figurer dans la recherche publique, dans un profil.

   Rendu par le profil artiste et par le profil ingénieur : la règle vit donc ici plutôt que
   recopiée dans deux feuilles de style propres à leur composant. Détaché des champs par un
   filet — ce n'est pas une information de la fiche mais une décision sur elle, et la ranger
   entre deux liens Spotify la ferait manquer. */
.profile-visibility {
    margin: 1.75rem 0 1.25rem;
    padding: 1rem 1.1rem;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 0.75rem;
    background: rgba(255, 255, 255, 0.03);
}

.profile-visibility-hint {
    margin: 0.6rem 0 0;
    font-size: 0.82rem;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.6);
}

/* ── La pastille d'une place dans l'équipe ────────────────────────────────────────────────
   Globale, comme .sh-space et .sh-action : la même pastille se lit dans la gestion d'équipe,
   dans les invitations en attente et dans la légende des rôles. L'isolation CSS de Blazor
   l'attacherait au fichier qui l'écrit, et trois copies de la même règle divergeraient au
   premier ajustement.

   La teinte vient de l'espace que la place ouvre — StudioRoleVocabulary le dit, et
   StudioRoleExtensions.ToAccountRole avant lui. Le propriétaire porte l'or de son espace,
   l'ingénieur l'aqua du sien. Elles empruntaient jusqu'ici les tons d'état, et une place
   pouvait s'afficher dans le rouge d'une erreur. */
.role-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.2rem 0.6rem;
    border: 1px solid transparent;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 800;
    letter-spacing: 0.03em;
    white-space: nowrap;
}

.role-pill > i { font-size: 0.95em; }

/* Le propriétaire : la couleur pleine. Il n'y en a qu'un, et c'est son studio. */
.role-pill--owner {
    color: #1a1400;
    background: var(--sh-space-owner);
    border-color: var(--sh-space-owner);
}

.role-pill--engineer {
    color: var(--sh-space-engineer);
    background: var(--sh-space-engineer-soft);
    border-color: var(--sh-space-engineer-edge);
}
