  @font-face { font-family: 'TO-Poppins'; src: url('/fonts/Poppins-Bold.ttf'); font-weight: 700; }
  @font-face { font-family: 'TO-Anton'; src: url('/fonts/Anton-Regular.ttf'); }
  @font-face { font-family: 'TO-Pacifico'; src: url('/fonts/Pacifico-Regular.ttf'); }
  @font-face { font-family: 'TO-SpaceMono'; src: url('/fonts/SpaceMono-Bold.ttf'); font-weight: 700; }
  @font-face { font-family: 'TO-AbrilFatface'; src: url('/fonts/AbrilFatface-Regular.ttf'); }

  /* Éditeur de texte incrusté façon Instagram — zone éditable directement sur l'image */
  #text-overlay-drag:empty::before { content: attr(data-placeholder); opacity: 0.85; text-shadow: 0 1px 3px rgba(0,0,0,0.6); pointer-events: none; }
  #text-overlay-dragwrap { touch-action: none; }
  .to-preview-icon {
    width: 30px; height: 30px; border-radius: 50%; border: 1px solid rgba(var(--text-rgb),0.25);
    background: rgba(0,0,0,0.55); color: #fff; display: flex; align-items: center; justify-content: center;
    cursor: pointer; backdrop-filter: blur(4px); font-weight: 700; font-size: 13px; padding: 0;
    transition: opacity 0.15s;
  }
  .to-align-btn.active { background: var(--accent); border-color: var(--accent); color: #1a1a1a; }
  .to-swatch {
    width: 24px; height: 24px; border-radius: 50%; border: 2px solid rgba(var(--text-rgb),0.2);
    cursor: pointer; padding: 0; display: flex; align-items: center; justify-content: center; overflow: hidden;
  }
  .to-swatch-custom { background: conic-gradient(red, yellow, lime, cyan, blue, magenta, red); position: relative; }
  .to-swatch-custom input[type="color"] {
    position: absolute; inset: -4px; width: 32px; height: 32px; border: none; padding: 0; cursor: pointer; opacity: 0;
  }
  .to-swatch-none {
    background: rgba(var(--text-rgb),0.08); color: rgba(var(--text-rgb),0.6); font-size: 11px; font-weight: 700;
  }
  /* Le popover partage la classe générique "hidden" utilisée ailleurs, mais celle-ci n'est
     définie qu'en combinaison avec d'autres classes (.modal-overlay.hidden, etc.) — sans cette
     règle propre, class="hidden" seul ne masque rien et le popover reste toujours affiché. */
  #text-overlay-popover.hidden { display: none; }
  #text-overlay-popover { max-width: calc(100% - 12px); }
  #text-overlay-popover-slider { min-width: 0; }
  /* Slider vertical (taille de police) façon Instagram — piste en coin (large en haut = grand
     texte, pointe en bas = petit texte) + curseur rond, construit à la main (drag document-level)
     plutôt qu'un <input type=range> stylé, pour un rendu fiable sur tous les navigateurs. */
  #text-overlay-size-track { touch-action: none; cursor: pointer; }
  /* Poignées d'étirement du cadre de texte (coins) */
  .to-resize-handle {
    position: absolute; width: 12px; height: 12px; background: var(--accent);
    border: 2px solid #0d1a18; border-radius: 3px; z-index: 4; touch-action: none;
  }

  * { box-sizing: border-box; margin: 0; padding: 0; }

  /* Ascenseurs — fins, discrets, accent cyan du thème plutôt que le rendu
     système par défaut (gris, tranche mal avec le fond dark/glass). Piste
     transparente : reste cohérent quel que soit le fond derrière (card
     glass, écran plein, modale...). */
  * { scrollbar-width: thin; scrollbar-color: rgba(var(--accent-rgb),0.4) transparent; }
  ::-webkit-scrollbar { width: 8px; height: 8px; }
  ::-webkit-scrollbar-track { background: transparent; }
  ::-webkit-scrollbar-thumb {
    background-color: rgba(var(--accent-rgb),0.35);
    border-radius: var(--radius-full);
    border: 2px solid transparent;
    background-clip: padding-box;
  }
  ::-webkit-scrollbar-thumb:hover { background-color: rgba(var(--accent-rgb),0.6); }

  html { overflow-x: hidden; width: 100%; overscroll-behavior: none; }
  /* Pas de overflow-x sur body : avec html qui a déjà overflow-x:hidden, en remettre un sur body
     (display:flex de surcroît) fait de body un second conteneur de scroll indépendant de html —
     Chrome devient alors incohérent sur qui doit répondre à la molette (le scroll programmatique
     et au clavier continuent de fonctionner, seule la molette est cassée). html:overflow-x:hidden
     suffit déjà à empêcher tout scroll horizontal de la page. */
  body {
    font-family: var(--font-body), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: var(--bg);
    color: var(--text);
    width: 100%;
    min-height: 100vh;
    overscroll-behavior: none;
    display: flex;
    justify-content: center;
  }
  #main-app {
    width: 480px;
    max-width: 100vw;
    /* var(--bg), pas var(--bg-elevated) : ce dernier sert aussi de fond aux surfaces VRAIMENT
       élevées (modales, lightbox, texte de bouton sur accent) — le réutiliser ici pour le fond de
       page aplatissait tout à la même teinte que les cards (var(--bg-card)), qui du coup ne se
       détachaient plus. */
    background-color: var(--bg);
    min-height: 100vh;
    flex-shrink: 0;
  }
  /* position:fixed (pas juste overflow:hidden) car overflow:hidden seul ne bloque pas
     le scroll-through vers le fond sur Safari iOS. */
  body.modal-open { position: fixed; overflow: hidden; width: 100%; }
  @media (min-width: 700px) {
    #main-app { width: 680px; }
  }

  /* Header */
  .header {
    background: var(--bg);
    padding: 14px 20px;
    display: flex; align-items: center; justify-content: space-between;
    border-bottom: 1px solid rgba(var(--accent-border-rgb),0.2);
    position: sticky; top: 0; z-index: 10;
  }
  .header-logo { font-family: var(--font-display); font-size: 20px; font-weight: 700; color: var(--text); letter-spacing: 0.05em; }
  .header-date { font-size: 12px; color: rgba(var(--text-rgb),0.5); }
  .header-app-logo { height: 32px; width: 32px; object-fit: contain; }
  /* Stats dans le header — desktop seulement pour l'instant (voir layout-desktop.css) ;
     pas de place dans le header compact mobile, .brief-bar/#network-stats-cards y restent
     simplement invisibles (elles n'apparaissent plus ailleurs sur mobile non plus). */
  .header-stats { display: none; }
  /* Icônes réseaux dans le header — même chose, desktop seulement (voir layout-desktop.css). */
  .header-networks { display: none; }
  /* Identité (prénom/organisation) au-dessus du bouton Compte — desktop seulement, voir
     layout-desktop.css. Sans ça elle s'affiche à tort dans la bottom-nav mobile. */
  .sidebar-identity { display: none; }

  /* Bottom nav */
  .tabs {
    display: flex;
    background: rgba(var(--bg-elevated-rgb),0.97);
    border-top: 1px solid rgba(var(--accent-border-rgb),0.12);
    box-shadow: 0 -4px 16px rgba(0,0,0,0.25);
    position: fixed; bottom: 0; z-index: 99;
    left: 50%; transform: translateX(-50%);
    width: 480px; max-width: 100vw;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    padding-bottom: max(16px, calc(env(safe-area-inset-bottom) + 10px));
    /* Marge latérale : sans elle, les onglets aux deux bouts touchent le bord exact de
       l'écran et un tap dessus peut être intercepté par le geste système de swipe-retour
       (iOS Safari / Android Chrome) au lieu d'atteindre la page — cf. le tab Compte qui
       ne répondait plus sur mobile étroit une fois passé à 7 onglets. */
    padding-left: 10px; padding-right: 10px;
  }
  @media (min-width: 700px) {
    .tabs { width: 680px; }
  }
  /* Numéro de version sous "Compte" — seulement en sidebar desktop (voir
     layout-desktop.css) ; sur la bottom-nav mobile ça n'a pas sa place. */
  .sidebar-version { display: none; }
  .tab {
    flex: 1; padding: 14px 2px; text-align: center;
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    min-width: 0;
  }
  .tab-icon-wrap {
    position: relative;
    width: 42px; height: 42px;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
  }
  .tab-icon-halo {
    position: absolute; inset: 0;
    border-radius: 50%;
    background: rgba(var(--accent-rgb),0.16);
    opacity: 0; transform: scale(0.6);
    transition: opacity 0.25s ease, transform 0.25s ease;
  }
  .tab-icon {
    width: 18px; height: 18px;
    color: rgba(var(--text-rgb),0.35);
    position: relative; z-index: 1;
    transition: transform 0.2s, filter 0.2s;
  }
  .tab.active .tab-icon-halo {
    opacity: 1; transform: scale(1);
  }
  .tab.active .tab-icon {
    color: var(--accent);
    transform: scale(1);
    filter: drop-shadow(0 0 6px rgba(var(--accent-rgb),0.5));
  }
  .tab-icon.pop {
    animation: tabBlob 0.5s cubic-bezier(.22,.9,.32,1);
  }
  /* Libellé texte des tabs — inutile en bottom-nav mobile (icônes seules), révélé
     uniquement par la sidebar desktop (static/css/layout-desktop.css). */
  .tab-label { display: none; }
  @keyframes tabBlob {
    0%   { transform: scale(1); }
    30%  { transform: scale(1.75, 1.25); }
    55%  { transform: scale(1.25, 1.45); }
    78%  { transform: scale(1.45, 1.3); }
    100% { transform: scale(1); }
  }
  /* Paysage : la barre reste fixe et visible (pas de repli/point — abandonné après plusieurs
     essais, toujours un délai perçu et des conflits avec le geste système "retour à l'accueil"),
     mais compactée au minimum pour redonner un maximum de hauteur à la timeline du Reel
     Workshop, qui a justement intérêt à être éditée en paysage. Placé après les règles de base
     ci-dessus : à spécificité égale (.tab-icon simple), la règle la plus tardive dans la
     cascade l'emporte, donc ce bloc doit venir après pour effectivement réduire les tailles. */
  @media (orientation: landscape) {
    .tabs { padding-bottom: max(4px, env(safe-area-inset-bottom)); }
    .tab { padding: 4px 4px; }
    .tab-icon-wrap { width: 34px; height: 34px; }
    .tab-icon { width: 16px; height: 16px; }
  }

  /* Screens */
  .screen { display: none; }
  .screen.active { display: block; padding-bottom: 108px; }

  /* Section */
  .section { padding: 16px 16px 8px; }
  .section-title {
    font-family: var(--font-display);
    font-size: 11px; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.08em; color: rgba(var(--text-rgb),0.4);
    margin-bottom: 10px;
  }

  /* Brief bar */
  .brief-bar {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 16px;
    background: rgba(var(--accent-rgb),0.06);
    border-bottom: 1px solid rgba(var(--accent-rgb),0.1);
    font-size: 11px;
  }
  .brief-stat { text-align: center; flex: 1; }
  .brief-stat-val { font-size: 18px; font-weight: 700; color: var(--accent); }
  .brief-stat-lbl { color: rgba(var(--text-rgb),0.4); margin-top: 2px; }

  /* Alert */
  .alert {
    margin: 10px 16px 0; padding: 10px 14px; border-radius: 8px;
    font-size: 12px; font-weight: 600; line-height: 1.4;
  }
  .alert-danger { background: rgba(220,80,80,0.15); border: 1px solid rgba(220,80,80,0.3); color: #e08080; }
  .alert-warning { background: rgba(var(--accent-rgb),0.12); border: 1px solid rgba(var(--accent-rgb),0.3); color: var(--accent); }
  .alert-success { background: rgba(80,200,120,0.1); border: 1px solid rgba(80,200,120,0.25); color: #80e090; }

  /* Cards */
  .card {
    background: var(--bg-card);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-xl); padding: 14px; margin-bottom: 10px;
    box-shadow: var(--shadow-card);
  }
  /* Publiée ou programmée : la card reste affichée (ne disparaît pas de "Aujourd'hui"), juste
     passée en vert pour signaler que c'est fait — même vert que .alert-success/badge "✓ Publié". */
  .card.card-done { background: rgba(80,200,120,0.12); border-color: rgba(80,200,120,0.4); }
  .card.card-programme { background: rgba(242,165,76,0.18); border-color: rgba(242,165,76,0.4); }
  .card.card-late { border-color: rgba(232,90,67,0.4); background: rgba(232,90,67,0.06); }
  .card-meta { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; flex-wrap: wrap; }
  .badge {
    font-size: 10px; font-weight: 700; padding: 2px 8px; border-radius: var(--radius-full);
    text-transform: uppercase; letter-spacing: 0.05em;
  }
  .badge-instagram { background: rgba(200,100,200,0.2); color: #e0a0e0; }
  .badge-tiktok { background: rgba(255,80,120,0.2); color: #ff90a0; }
  .badge-facebook { background: rgba(100,130,255,0.2); color: #a0b0ff; }
  .badge-format { background: rgba(var(--accent-rgb),0.15); color: var(--accent); }
  .badge-late { background: rgba(232,90,67,0.18); color: #e85a43; }
  /* Deux états, deux couleurs : ambre pour « ce post part bientôt », vert pour « il est en
     ligne ». La card de la tâche suit la même couleur que sa pastille (.card-programme /
     .card-done, .week-task-wrap.programme / .done) — avant, les deux états partageaient la même
     card verte et seule la pastille les distinguait. */
  .badge-programme { background: rgba(242,165,76,0.20); color: var(--status-orange); }
  .badge-fait { background: rgba(80,200,120,0.28); color: var(--status-green); }
  .net-badge { display: inline-flex; flex-shrink: 0; }
  .network-stat-card { padding: 12px 14px; }
  .network-stat-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
  .network-stat-label { font-size: 13px; font-weight: 700; color: var(--text); }
  .network-stat-row { display: flex; gap: 14px; flex-wrap: wrap; }
  .network-stat-item { flex: 1; min-width: 70px; text-align: center; }
  .network-stat-val { font-size: 16px; font-weight: 700; color: var(--accent); }
  .network-stat-lbl { font-size: 10px; color: rgba(var(--text-rgb),0.45); margin-top: 2px; text-transform: uppercase; letter-spacing: .04em; }
  .health-score-global { display: flex; align-items: baseline; gap: 4px; margin-bottom: 14px; }
  .health-score-global-num { font-size: 32px; font-weight: 700; color: var(--accent); line-height: 1; }
  .health-score-global-lbl { font-size: 13px; color: rgba(var(--text-rgb),0.45); }
  .health-axis { margin-bottom: 12px; }
  .health-axis-head { display: flex; justify-content: space-between; margin-bottom: 4px; }
  .health-axis-label { font-size: 12px; font-weight: 600; color: var(--text); }
  .health-axis-val { font-size: 12px; font-weight: 700; color: rgba(var(--text-rgb),0.6); }
  .health-axis-bar { position: relative; height: 8px; border-radius: 4px; overflow: hidden; background: rgba(var(--accent-rgb),0.12); }
  .health-axis-fill { height: 100%; background: var(--accent); transition: width 0.3s ease; }
  .health-axis-note { font-size: 11px; color: rgba(var(--text-rgb),0.4); margin-top: 4px; }
  .health-score-interpretation { font-size: 12px; color: rgba(var(--text-rgb),0.7); line-height: 1.5; margin-top: 8px; padding-top: 10px; border-top: 1px solid rgba(var(--text-rgb),0.08); }
  /* Destinations enregistrees (ecran Compte). Une pastille signifie « c'est en base » : c'est
     le seul retour visuel qui distingue une destination stockee de ce qu'on est en train de
     taper dans le formulaire juste en dessous. */
  .dest-liste { display: flex; flex-direction: column; gap: 6px; }
  .dest-pastille {
    display: flex; align-items: center; gap: 8px;
    background: rgba(var(--accent-rgb),0.1); border: 1px solid rgba(var(--accent-rgb),0.3);
    border-radius: 20px; padding: 6px 8px 6px 12px; font-size: 12px; color: var(--text);
  }
  .dest-pastille-corps { flex: 1; min-width: 0; }
  .dest-pastille-nom { font-weight: 600; }
  .dest-pastille-url {
    display: block; font-size: 10px; color: rgba(var(--text-rgb),0.45);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .dest-pastille-retirer {
    flex-shrink: 0; width: 22px; height: 22px; border-radius: 50%; border: none; cursor: pointer;
    background: rgba(var(--text-rgb),0.08); color: rgba(var(--text-rgb),0.6); font-size: 11px;
    display: flex; align-items: center; justify-content: center; padding: 0;
  }
  .dest-pastille-retirer:hover { background: rgba(232,90,67,0.18); color: #e85a43; }
  .hashtag-list { display: flex; flex-wrap: wrap; gap: 8px; }
  .hashtag-pill {
    display: inline-flex; align-items: center; gap: 6px;
    background: rgba(var(--accent-rgb),0.1); border: 1px solid rgba(var(--accent-rgb),0.3);
    border-radius: 20px; padding: 5px 12px; font-size: 12px; color: var(--text);
  }
  .hashtag-pill-score { font-weight: 700; color: var(--accent); }
  #network-stats-cards { display: flex; gap: 10px; }
  .network-stat-mini {
    flex: 1; padding: 12px 10px; display: flex; flex-direction: column; align-items: center;
    gap: 4px; text-align: center;
  }
  .network-stat-mini-val { font-size: 18px; font-weight: 700; color: var(--accent); }
  .network-stat-mini-lbl { font-size: 10px; color: rgba(var(--text-rgb),0.45); text-transform: uppercase; letter-spacing: .04em; }
  #stats-network-select { display: flex; gap: 12px; margin-bottom: 14px; }
  .stats-network-icon {
    border-radius: 10px; cursor: pointer; filter: grayscale(1) opacity(0.4);
    transition: filter 0.25s ease, transform 0.15s ease;
  }
  .stats-network-icon:hover { transform: scale(1.05); }
  .stats-network-icon.active { filter: none; opacity: 1; }
  .stats-chart-wrap { margin-top: 6px; }
  .stats-chart-svg { width: 100%; height: 90px; display: block; }
  .stats-chart-note { font-size: 11px; color: rgba(var(--text-rgb),0.4); margin-top: 4px; }
  .stats-empty-note { font-size: 12px; color: rgba(var(--text-rgb),0.5); line-height: 1.5; padding: 8px 0; }
  .strategy-chat-toggle {
    background: rgba(var(--accent-rgb),0.08); border: 1px solid rgba(var(--accent-rgb),0.3);
    border-radius: 10px; width: 100%; text-align: center;
    font-size: 13px; font-weight: 600; color: rgba(var(--accent-rgb),0.75); cursor: pointer;
    padding: 11px 16px; margin-top: 8px; transition: background 0.2s, color 0.2s, border-color 0.2s;
  }
  .strategy-chat-toggle:hover {
    background: rgba(var(--accent-rgb),0.15); color: var(--accent); border-color: rgba(var(--accent-rgb),0.55);
  }
  .network-card {
    display: flex; flex-direction: column; gap: 10px;
    padding: 14px; border-radius: var(--radius-xl); margin-bottom: 10px;
    border: 1px solid var(--border-subtle); background: rgba(var(--text-rgb),0.02);
    transition: border-color 0.3s ease, background 0.3s ease;
    box-shadow: var(--shadow-card);
  }
  .network-card.connected { border-color: rgba(var(--accent-rgb),0.35); background: rgba(var(--accent-rgb),0.05); }
  .network-card-head { display: flex; align-items: center; gap: 12px; cursor: pointer; }
  .network-card.disabled .network-card-head { cursor: default; }
  .network-card-head .si-svg {
    width: 40px; height: 40px; border-radius: 10px; flex-shrink: 0; display: block;
    filter: grayscale(1) opacity(0.35); transition: filter 0.35s ease, opacity 0.35s ease;
  }
  .network-card.connected .network-card-head .si-svg { filter: none; opacity: 1; }
  .network-card-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  .network-card-name { font-size: 14px; font-weight: 600; color: var(--text); }
  .network-card-status { font-size: 12px; color: rgba(var(--text-rgb),0.5); }
  /* Mention inerte a la place d'un bouton indisponible (ex. Pages LinkedIn en cours de
     validation). Volontairement sans bordure ni fond cliquable : rien ici ne doit inviter au
     clic, contrairement a .btn-full-soft qu'elle remplace. */
  .network-card-note {
    font-size: 12px; line-height: 1.45; color: rgba(var(--text-rgb),0.55);
    padding: 8px 10px; margin-bottom: 6px; border-radius: 8px;
    background: rgba(var(--text-rgb),0.04);
  }
  .card-time { font-size: 11px; color: rgba(var(--text-rgb),0.4); margin-left: auto; }
  .card-title { font-size: 13px; font-weight: 600; color: var(--text); margin-bottom: 4px; }
  .card-desc {
    font-size: 12px; color: rgba(var(--text-rgb),0.7); line-height: 1.5;
    margin-bottom: 8px; max-height: 60px; overflow: hidden; cursor: pointer;
  }
  .card-desc.expanded { max-height: none; }
  .card-action {
    font-size: 11px; color: rgba(var(--text-rgb),0.5);
    background: rgba(var(--text-rgb),0.04);
    border-radius: 6px; padding: 6px 8px; margin-bottom: 8px; line-height: 1.4;
  }
  .card-actions { display: flex; gap: 6px; flex-wrap: wrap; }

  /* Buttons */
  .btn {
    font-size: 11px; font-weight: 600; padding: 6px 12px;
    border-radius: 6px; border: none; cursor: pointer; transition: all 0.15s;
  }
  .btn-primary { background: var(--accent); color: var(--bg-elevated); }
  .btn-primary:hover { filter: brightness(1.15); }
  .btn-ghost {
    background: rgba(var(--text-rgb),0.03); color: rgba(var(--text-rgb),0.7);
    border: 1px solid var(--border-subtle);
  }
  .btn-ghost:hover { background: rgba(var(--text-rgb),0.14); }
  .btn-posted { background: rgba(80,200,120,0.15); color: #80e090; border: 1px solid rgba(80,200,120,0.2); }
  .btn-danger { background: rgba(220,80,80,0.1); color: #e08080; border: 1px solid rgba(220,80,80,0.2); }
  .btn:disabled { opacity: 0.4; cursor: not-allowed; }

  /* CTA magenta glow (identité landing) — border transparent (pas none) exprès : plusieurs
     boutons secondaires (ex. auth-toggle, disconnect-btn) réutilisent .btn-full avec un
     style="background:...; border-color:..." inline pour un rendu "ghost" coloré ; sans
     border-width ici, ce border-color inline n'aurait aucun effet. */
  .btn-full {
    width: 100%; padding: 12px; border-radius: var(--radius-lg);
    font-size: 13px; font-weight: 700; cursor: pointer;
    border: 1px solid transparent; transition: all 0.2s;
    background: var(--accent-magenta); color: #fff;
    box-shadow: 0 0 30px -6px rgba(217,4,170,0.45);
    margin-top: 8px;
  }
  .btn-full:hover { background: var(--accent-magenta-soft); box-shadow: 0 0 40px -4px rgba(217,4,170,0.7); }
  .btn-full:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; }

  /* Variante rose pâle (--accent, même teinte que .btn-primary) pour les actions courantes
     hors onboarding/login — le magenta vif de .btn-full ci-dessus reste réservé aux CTA
     d'identité landing (connexion, onboarding). */
  .btn-full-soft { background: var(--accent); color: var(--bg-elevated); box-shadow: none; }
  .btn-full-soft:hover { filter: brightness(1.15); box-shadow: none; }

  /* Variante "ghost" des boutons secondaires de l'écran de connexion. Elle remplace le
     style="background:transparent; border-color:..." inline qui traînait sur ces boutons :
     celui-ci laissait hériter le `color:#fff` de .btn-full, donc du blanc sur blanc — invisible
     en thème clair. La couleur suit désormais l'accent (rose pâle en sombre, indigo en clair). */
  .btn-full-ghost {
    background: transparent; color: var(--accent);
    border-color: rgba(var(--accent-rgb),0.3); box-shadow: none;
  }
  .btn-full-ghost:hover {
    background: rgba(var(--accent-rgb),0.08);
    border-color: rgba(var(--accent-rgb),0.5); box-shadow: none;
  }

  /* Champ mot de passe avec bouton oeil. Le wrapper doit lui-même s'étirer : .form-group est en
     flex, et les .form-text tirent leur pleine largeur du fait d'être des éléments flex directs —
     encapsulé, l'input retombe sinon sur sa largeur intrinsèque (~227px au lieu de 308px), d'où
     le width:100% explicite. padding-right pour que le texte ne passe jamais sous l'icône. */
  .password-field { position: relative; flex: 1; min-width: 0; }
  .password-field .form-text { width: 100%; padding-right: 42px; }
  .password-toggle {
    position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
    width: 32px; height: 32px; padding: 0;
    display: flex; align-items: center; justify-content: center;
    background: none; border: 0; cursor: pointer;
    color: rgba(var(--text-rgb),0.45); border-radius: 6px;
  }
  .password-toggle:hover { color: var(--accent); background: rgba(var(--text-rgb),0.06); }
  .password-toggle svg { width: 18px; height: 18px; }

  /* Semaine — sections par jour, vraies cards */
  .week-day-section { margin-bottom: 4px; border-radius: 8px; padding: 0 4px; transition: background 0.15s; }
  .week-day-section.drop-target { background: rgba(var(--accent-rgb),0.1); }
  .week-day-header { font-size: 12px; font-weight: 700; color: var(--accent); padding: 10px 4px 4px; text-transform: capitalize; }
  .week-day-empty { font-size: 11px; color: rgba(var(--text-rgb),0.25); padding: 4px 4px 12px; }
  /* -webkit-user-select/-touch-callout dès le départ (pas seulement sur .dragging, posée trop
     tard par le JS) — sur mobile l'appui long arme la sélection/callout natif avant même que le
     seuil de déplacement du drag ne soit atteint. */
  /* La bordure/fond de la card vit sur .week-task-wrap (pas .week-task-summary) : au clic, le
     détail (.week-task-full) apparaît DANS cette même boîte plutôt que dans une 2e card
     séparée en dessous — une seule card qui grandit, pas deux qui s'empilent. */
  .week-task-wrap {
    position: relative; padding-left: 26px; margin-bottom: 10px;
    background: rgba(var(--text-rgb),0.03); border: 1px solid rgba(var(--text-rgb),0.12); border-radius: 10px;
    overflow: hidden;
    -webkit-touch-callout: none; -webkit-user-select: none; user-select: none;
  }
  .week-task-wrap.late { background: rgba(232,90,67,0.06); border-color: rgba(232,90,67,0.3); }
  .week-task-wrap.done { background: rgba(80,200,120,0.1); border-color: rgba(80,200,120,0.35); }
  .week-task-wrap.programme { background: rgba(242,165,76,0.15); border-color: rgba(242,165,76,0.35); }
  .week-task-wrap.dragging, .week-pinnable.dragging { opacity: 0.5; position: relative; z-index: 10; }
  .week-drag-handle {
    position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 22px; height: 42px;
    display: flex; align-items: center; justify-content: center; border-radius: 6px;
    background: rgba(0,0,0,0.2); color: rgba(var(--text-rgb),0.4); font-size: 15px;
    cursor: grab; touch-action: none; -webkit-touch-callout: none; user-select: none;
  }
  .week-task-summary { cursor: pointer; padding: 10px 12px; }
  .week-summary-top { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
  .week-caret { font-size: 10px; color: rgba(var(--text-rgb),0.4); flex-shrink: 0; }
  .week-task-wrap.late .week-caret { color: rgba(232,90,67,0.6); }
  .week-summary-time { font-size: 11px; color: rgba(var(--text-rgb),0.5); margin-left: auto; flex-shrink: 0; }
  .week-summary-title {
    font-size: 12px; color: var(--text); margin-top: 4px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* Détail déplié — apparaît dans la même card que le résumé (celle-ci "grandit"), pas de
     titre/badges dupliqués (déjà affichés dans .week-task-summary juste au-dessus), et le
     .card de renderTaskCard est neutralisé (pas de 2e bordure imbriquée). */
  .week-task-full { padding: 12px 24px 20px 24px; transform-origin: top center; animation: weekFullReveal 0.22s cubic-bezier(0.16,1,0.3,1) both; }
  .week-task-full.hidden { display: none; }
  .week-task-full .card { background: transparent; border: none; padding: 0; margin: 0; }
  .week-task-full .card-meta, .week-task-full .card-title { display: none; }
  /* Boîte visible (fond + padding propre), même traitement que .card-action juste en dessous —
     pour que le texte de la description ait clairement de l'air autour de lui, pas seulement un
     espacement invisible au niveau du conteneur parent. */
  .week-task-full .card-desc {
    background: rgba(var(--text-rgb),0.04);
    border-radius: 8px;
    padding: 10px 12px;
  }
  @keyframes weekFullReveal { from { opacity: 0; transform: scaleY(0.92); } to { opacity: 1; transform: scaleY(1); } }

  /* Suppression via une icône poubelle fixe (pas de swipe) : voir .week-task-delete plus bas.
     week-task-wrap-deletable (pin+poubelle, posts en retard et idées épinglées) élargit le
     padding pour laisser la place aux 2 icônes sans chevaucher le badge/l'heure de
     .week-summary-top. */
  .week-task-wrap-deletable { padding-right: 58px; }
  .week-task-wrap-deletable .week-pin-btn { right: 34px; }
  .week-task-delete {
    position: absolute; top: 8px; right: 8px; z-index: 2;
    width: 22px; height: 22px; border-radius: 6px; border: none;
    background: rgba(220,80,80,0.12); color: #e08080;
    display: flex; align-items: center; justify-content: center; cursor: pointer;
  }
  .week-task-delete:hover { background: rgba(220,80,80,0.22); }

  /* Épingler (Idées bonus + Posts en retard) — icône fixe, en haut à droite de la card.
     .week-pinnable enrobe le rendu générique de renderTaskCard() pour les idées NON épinglées
     (pas de bordure propre, juste un repère de positionnement pour le bouton) ; une fois
     épinglée, une idée passe par .week-task-wrap comme un post en retard (même apparence
     compressée, même zone de drag englobée dans la bordure de la card — voir _weekTaskCard).
     Épingler/désépingler/réordonner ré-affiche les panneaux "Épinglés" depuis les données (voir
     _weekRenderPinnedPanels() dans week.js — une même card peut vivre à deux endroits en même
     temps, Semaine + accueil) ; .week-pinned-card rejoue une entrée en glissade + rebond à
     chaque rendu plutôt qu'un vrai FLIP depuis la position d'origine. */
  .week-pinnable { position: relative; }
  .week-pinnable .card { padding-right: 40px; }
  .week-pin-btn {
    position: absolute; top: 8px; right: 8px; z-index: 2;
    width: 22px; height: 22px; border-radius: 6px; border: none;
    background: rgba(var(--accent-rgb),0.12); color: var(--accent);
    display: flex; align-items: center; justify-content: center; cursor: pointer;
  }
  .week-pin-btn:hover { background: rgba(var(--accent-rgb),0.22); }
  .week-pin-btn.pinned { background: var(--accent); color: var(--bg-elevated); }
  .week-pinned-card.week-task-wrap { border-color: rgba(var(--accent-rgb),0.35); }
  .week-pinned-card { animation: weekPinSlideIn 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) both; }
  @keyframes weekPinSlideIn {
    from { opacity: 0; transform: translateX(24px) scale(0.96); }
    to { opacity: 1; transform: translateX(0) scale(1); }
  }

  /* Réordonnancement dans la pile "Épinglés" — poignée générée par le template quand
     opts.pinned (voir _weekTaskCard dans week.js), donc elle n'existe nulle part ailleurs, pas
     besoin de condition supplémentaire pour la cacher hors panneau. .week-task-wrap réserve
     déjà 26px à gauche (padding-left), que ce soit pour .week-drag-handle (planning normal) ou
     .week-pin-drag-handle (épinglé) — les deux sont mutuellement exclusifs (voir _weekTaskCard). */
  .week-pin-drag-handle {
    position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 22px; height: 42px;
    display: flex; align-items: center; justify-content: center; border-radius: 6px;
    background: rgba(0,0,0,0.2); color: rgba(var(--text-rgb),0.4); font-size: 15px;
    cursor: grab; touch-action: none; -webkit-touch-callout: none; user-select: none; z-index: 3;
  }

  /* Empty */
  .empty { text-align: center; padding: 32px 20px; color: rgba(var(--text-rgb),0.3); font-size: 13px; line-height: 1.6; }

  /* Toast */
  .toast {
    position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%);
    background: var(--bg-card); border: 1px solid rgba(var(--accent-border-rgb),0.3);
    color: var(--text); font-size: 12px; padding: 10px 18px;
    border-radius: 20px; opacity: 0; transition: opacity 0.3s;
    pointer-events: none; white-space: nowrap; z-index: 400;
  }
  .toast.show { opacity: 1; }

  /* Loader — GIF animé en boucle (static/img/loader/loader-icon.gif, 24 frames, exporté
     d'Adobe Animate) — même fichier derrière .loader, .app-overlay-ring, .ig-loading-ring et
     .pub-spin (voir plus bas) pour un seul et même loader partout. Le GIF boucle tout seul,
     aucune rotation CSS à ajouter par-dessus (contrairement à l'ancien loader-icon.png, une
     image statique unique qu'il fallait faire tourner via @keyframes spin). */
  .loader {
    display: inline-block; width: 14px; height: 14px;
    background: url('/static/img/loader/loader-icon.gif') center/contain no-repeat;
    vertical-align: middle; margin-right: 6px;
  }

  /* Grande version du loader — plein milieu d'une card pendant que ses données chargent (voir
     #history-list/#stats-body/#stats-grid), plutôt que la petite puce inline utilisée dans les
     bulles de chat/boutons (.loader ci-dessus). */
  .loader-big {
    display: block; width: 144px; height: 144px;
    background: url('/static/img/loader/loader-icon.gif') center/contain no-repeat;
  }
  .card-loading {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    min-height: 180px;
    gap: 12px; padding: 40px 16px; text-align: center;
    color: rgba(var(--text-rgb),0.5); font-size: 12px;
  }

  /* Chat (Atelier + Onboarding) */
  .chat-container {
    display: flex; flex-direction: column; height: calc(100vh - 150px);
    min-height: 0; overflow: hidden;
  }
  .chat-messages {
    flex: 1; overflow-y: auto; padding: 16px; min-height: 0;
    display: flex; flex-direction: column; gap: 10px;
  }
  .chat-bubble {
    max-width: 85%; padding: 10px 14px;
    border-radius: 12px; font-size: 13px; line-height: 1.5;
  }
  .chat-alex {
    background: var(--bg-card); border: 1px solid rgba(var(--accent-border-rgb),0.2);
    align-self: flex-start; border-bottom-left-radius: 4px;
  }
  .chat-alex .chat-name { display: flex; align-items: center; gap: 5px; font-size: 10px; font-weight: 700; color: var(--accent); margin-bottom: 4px; }
  .chat-avatar { width: 44px; height: 44px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
  .chat-user {
    background: rgba(var(--accent-rgb),0.15); color: var(--text);
    align-self: flex-end; border-bottom-right-radius: 4px;
  }
  .chat-input-bar {
    display: flex; gap: 8px; padding: 12px 16px;
    background: var(--bg); border-top: 1px solid rgba(var(--accent-border-rgb),0.15);
  }
  .chat-input {
    flex: 1; background: var(--surface-alt); border: 1px solid var(--border-subtle);
    color: var(--text); padding: 10px 14px; border-radius: var(--radius-lg);
    font-size: 16px; outline: none; resize: none;
    font-family: inherit; transition: border-color 0.15s;
  }
  .chat-input:focus { border-color: var(--accent-cyan); }
  .chat-input::placeholder { color: rgba(var(--text-rgb),0.3); }
  .chat-send {
    background: var(--accent-pink-muted); color: var(--bg-elevated); border: none;
    width: 40px; height: 40px; border-radius: 8px;
    font-size: 16px; cursor: pointer; font-weight: 700;
  }

  /* Onboarding overlay */
  .onboarding-overlay {
    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    background: var(--bg-elevated); z-index: 150;
    display: flex; flex-direction: column; align-items: center;
  }
  .onboarding-overlay.hidden { display: none; }
  .onboarding-header {
    padding: 20px; text-align: center;
    border-bottom: 1px solid rgba(var(--accent-border-rgb),0.15);
    width: 100%; max-width: 480px;
  }
  .onboarding-header h1 { font-family: var(--font-display); font-size: 18px; color: var(--accent); font-weight: 700; }
  .onboarding-header p { font-size: 12px; color: rgba(var(--text-rgb),0.5); margin-top: 4px; }
  .onboarding-step { font-size: 10px; color: rgba(var(--text-rgb),0.3); margin-top: 6px; }

  /* Sector grid */
  .sector-grid {
    display: grid; grid-template-columns: 1fr 1fr;
    gap: 8px; padding: 16px;
  }
  .sector-btn {
    background: var(--bg-card); border: 1px solid var(--border-subtle);
    color: var(--text); padding: 14px 10px; border-radius: var(--radius-xl);
    font-size: 12px; font-weight: 600; cursor: pointer;
    text-align: center; transition: all 0.2s;
  }
  .sector-btn:hover { border-color: var(--accent); background: rgba(var(--accent-rgb),0.1); }
  .sector-btn.selected { border-color: var(--accent); background: rgba(var(--accent-rgb),0.15); color: var(--accent); }

  /* Choix du parcours d'onboarding, et boutons de reseau de l'ecran 0b. Deux cartes pleine
     largeur et non la grille 2 colonnes des secteurs : ce choix oriente tout le reste de
     l'onboarding, il doit se lire, pas se survoler. */
  .parcours-grid { display: flex; flex-direction: column; gap: 10px; }
  .parcours-btn {
    display: flex; flex-direction: column; gap: 5px; text-align: left;
    background: var(--bg-card); border: 1px solid var(--border-subtle);
    color: var(--text); padding: 16px; border-radius: var(--radius-xl);
    cursor: pointer; font-family: inherit; transition: all 0.2s; width: 100%;
  }
  .parcours-btn:hover { border-color: var(--accent); background: rgba(var(--accent-rgb),0.1); }
  .parcours-btn-titre { font-size: 14px; font-weight: 700; }
  .parcours-btn-desc { font-size: 12px; line-height: 1.45; color: rgba(var(--text-rgb),0.6); }

  /* Onboarding form */
  .onboarding-form { padding: 16px; display: flex; flex-direction: column; gap: 14px; overflow-y: auto; flex: 1; min-height: 0; width: 100%; max-width: 480px; padding-bottom: calc(16px + env(safe-area-inset-bottom));}
  .form-group { display: flex; flex-direction: column; gap: 4px; }
  .form-label { font-size: 12px; font-weight: 600; color: rgba(var(--text-rgb),0.8); }
  .form-select, .form-text {
    background: var(--surface-alt); border: 1px solid var(--border-subtle);
    color: var(--text); padding: 10px 12px; border-radius: var(--radius-lg);
    font-size: 13px; font-family: inherit; outline: none; transition: border-color 0.15s;
  }
  .form-select:focus, .form-text:focus { border-color: var(--accent-cyan); }
  .form-select option { background: var(--surface-alt); }

  /* Strategy cards */
  .strategy-card {
    background: var(--bg-card); border: 1px solid var(--border-subtle);
    border-radius: var(--radius-xl); padding: 14px; margin-bottom: 10px; cursor: pointer;
    transition: all 0.2s;
    box-shadow: var(--shadow-card);
  }
  .strategy-card:hover { border-color: rgba(var(--accent-rgb),0.4); }
  .strategy-card.selected { border-color: var(--accent); background: rgba(var(--accent-rgb),0.08); }
  .strategy-card h3 { font-family: var(--font-display); font-size: 14px; color: var(--accent); margin-bottom: 6px; }
  .strategy-card p { font-size: 12px; color: rgba(var(--text-rgb),0.7); line-height: 1.4; margin-bottom: 6px; }
  .strategy-card .mix { font-size: 11px; color: rgba(var(--text-rgb),0.5); }
  .strategy-examples {
    margin-top: 8px; font-size: 11px; color: rgba(var(--text-rgb),0.6);
    max-height: 0; overflow: hidden; transition: max-height 0.3s;
  }
  .strategy-card.selected .strategy-examples { max-height: 200px; }
  /* Résumé lecture seule (écran Compte, cf. renderStrategySummary) — pas de sélection possible */
  .strategy-card-readonly { cursor: default; }
  .strategy-card-readonly:hover { border-color: var(--accent); }

  /* Historique */
  .pub-card {
    background: var(--bg-card); border: 1px solid rgba(var(--accent-border-rgb),0.1);
    border-radius: 8px; padding: 12px; margin-bottom: 8px;
    box-shadow: var(--shadow-card);
  }
  .pub-card-processing { opacity: 0.55; }

  /* overflow-x/y séparés plutôt que le raccourci "overflow: hidden" : un overflow:hidden ici
     piège le scroll à la molette sur desktop (Chrome ne le fait pas remonter à la page quand le
     curseur est au-dessus d'un ancêtre non scrollable en overflow:hidden). overflow-y:auto garde
     le même clipping visuel tout en laissant la molette remonter normalement à la page. */
  /* filter: drop-shadow (pas box-shadow) : ce wrapper a overflow-x/y sur lui-même pour le
     swipe-to-delete ci-dessus — un box-shadow serait clippé par son propre overflow, un
     drop-shadow non (cf. --shadow-card-filter, theme.css). Le .pub-card à l'intérieur garde
     quand même son box-shadow pour le cas où il est rendu SANS ce wrapper (item "processing",
     non supprimable, voir _histCardHtml) — box-shadow qui, ici, ne rend simplement rien de plus
     puisqu'il serait clippé, sans conflit visuel avec le drop-shadow du wrapper. */
  /* flex-shrink:0 est nécessaire : dans une liste flex-column bornée en hauteur avec
     overflow-y:auto (.history-month-list, history-desktop.css), un enfant flex qui a lui-même
     un overflow autre que visible voit sa taille mini automatique ramenée à 0 par la spec
     Flexbox — sans ce flex-shrink:0, dès qu'il y a trop de publications pour la hauteur
     disponible, les cards se compressent toutes au lieu de laisser la liste défiler. */
  .hist-swipe { position: relative; overflow-x: hidden; overflow-y: auto; flex-shrink: 0; border-radius: 8px; margin-bottom: 8px; filter: var(--shadow-card-filter); }
  .hist-swipe .pub-card { margin-bottom: 0; position: relative; z-index: 1; transition: transform 0.2s ease; touch-action: pan-y; }
  .hist-swipe.open .pub-card { transform: translateX(-84px); }
  .hist-swipe-delete {
    position: absolute; top: 0; right: 0; bottom: 0; width: 84px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
    background: #c0392b; color: #fff; font-size: 10.5px; font-weight: 600;
    border: none; cursor: pointer; padding: 0;
  }
  .pub-card-delete-btn {
    flex-shrink: 0; width: 26px; height: 26px; border-radius: 6px; border: none; padding: 0;
    display: flex; align-items: center; justify-content: center; cursor: pointer;
    background: transparent; color: rgba(var(--text-rgb),0.35); transition: background 0.15s, color 0.15s;
  }
  .pub-card-delete-btn:hover { background: rgba(220,80,80,0.12); color: #e08080; }
  .pub-date { font-size: 10px; color: rgba(var(--text-rgb),0.4); }
  .pub-caption {
    font-size: 12px; color: rgba(var(--text-rgb),0.7); margin-top: 4px; line-height: 1.4;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }

  /* Stars */
  .stars { display: flex; gap: 2px; margin-top: 6px; }
  .star {
    font-size: 16px; cursor: pointer; color: rgba(var(--text-rgb),0.2);
    transition: color 0.15s;
  }
  .star.filled { color: var(--accent); }

  /* Config */
  .config-group { margin-bottom: 16px; }
  .config-label { font-size: 11px; font-weight: 700; color: rgba(var(--text-rgb),0.5); text-transform: uppercase; margin-bottom: 6px; }
  .config-input {
    width: 100%; background: var(--surface-alt); border: 1px solid var(--border-subtle);
    color: var(--text); padding: 10px 12px; border-radius: var(--radius-lg);
    font-size: 13px; font-family: inherit; outline: none; transition: border-color 0.15s;
  }
  .config-input:focus { border-color: var(--accent-cyan); }

  .scroll-y { overflow-y: auto; }

  /* Modal caption */
  .modal-overlay {
    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    background: rgba(0,0,0,0.7); z-index: 150;
    display: flex; align-items: center; justify-content: center;
  }
  .modal-overlay.hidden { display: none; }
  /* La discussion avec Alex s'ouvre depuis une card de tâche — et sur le dashboard desktop
     cette card vit déjà dans une modale (#dash-task-modal, calendrier éditorial). Les deux
     partagent .modal-overlay, donc à z-index égal c'est l'ordre du DOM qui tranche :
     #task-chat-modal est écrit AVANT, il passait dessous. On le monte d'un cran plutôt que de
     fermer le détail de la tâche — refermer la discussion doit ramener la tâche, pas le
     dashboard nu (le composeur, lui, REMPLACE le détail : voir openCaptionModal). */
  #task-chat-modal { z-index: 160; }
  /* Vue agrandie d'une photo du post (clic sur une case de la grille Facebook, une vignette, ou la
     diapo principale Instagram) — les vignettes/cases sont trop petites pour vraiment voir le
     média avant publication. */
  .media-lightbox { position:fixed; inset:0; background:rgba(0,0,0,0.92); z-index:300; display:flex; align-items:center; justify-content:center; cursor:zoom-out; }
  .media-lightbox.hidden { display:none; }
  .media-lightbox img,.media-lightbox video { max-width:92vw; max-height:92vh; object-fit:contain; }
  .modal {
    background: var(--glass-bg); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-xl); width: 390px; max-height: 80vh; max-height: 80dvh;
    display: flex; flex-direction: column; overflow: hidden;
  }
  /* Éditeur de texte incrusté en plein écran (façon Instagram/TikTok/Focato) : le média occupe
     toute la hauteur disponible, les réglages de police/couleur restent groupés en bas, toujours
     visibles sans scroll — plutôt qu'une modale centrée classique de taille fixe. */
  #text-overlay-modal.modal-overlay { padding: 0; }
  /* Même largeur que #main-app (colonne centrée façon app mobile) — pas toute la fenêtre,
     sinon la modale déborde largement de la largeur réelle de l'app sur desktop. */
  #text-overlay-modal .modal {
    width: 480px; max-width: 100vw; height: 100dvh; max-height: 100dvh;
    border-radius: 0; background: #000;
    /* .modal porte un backdrop-filter, invisible ici (le fond est noir opaque) mais lourd de
       consequences : un backdrop-filter fait de l'element le BLOC CONTENEUR de ses descendants
       en position:fixed. Le popover des reglages de texte est fixed et vit dans cette modale :
       ses coordonnees, calculees en reperes ecran, etaient donc interpretees en reperes modale.
       Sur mobile la modale part de 0,0 et l'erreur ne se voyait pas ; sur PC elle est centree,
       et le popover partait de la moitie de la marge vers la droite — hors ecran, ou rogne par
       l'overflow:hidden de la modale. */
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
  @media (min-width: 700px) {
    #text-overlay-modal .modal { width: 680px; }
  }
  #text-overlay-modal .modal-header {
    justify-content: flex-start; background: transparent; border-bottom: none;
    padding: calc(10px + env(safe-area-inset-top)) 16px 10px;
  }
  /* Cet éditeur reste toujours sur fond noir (#000 ci-dessus), même en thème clair — comme un
     éditeur photo/vidéo (Instagram, CapCut...). Le titre/la croix de fermeture doivent donc
     rester clairs en dur plutôt que suivre var(--accent)/var(--text-rgb), qui foncent en
     thème clair et deviendraient illisibles sur ce fond toujours sombre. */
  #text-overlay-modal .modal-header h3 { flex: 1; text-align: center; color: #f8fafc; }
  #text-overlay-modal .modal-close { color: rgba(248,250,252,0.6); }
  #text-overlay-modal .modal-body { padding: 0; display: flex; flex-direction: column; overflow: hidden; }
  #text-overlay-preview { flex: 1; min-height: 0; }
  #logo-overlay-preview { flex: 1; min-height: 0; }
  .to-bottom-panel {
    flex-shrink: 0; display: flex; flex-direction: column; gap: 12px;
    padding: 14px 16px calc(6px + env(safe-area-inset-bottom)); background: #000;
  }
  .to-font-row {
    display: flex; gap: 10px; overflow-x: auto; padding-bottom: 2px; scrollbar-width: none;
  }
  .to-font-row::-webkit-scrollbar { display: none; }
  .to-font-chip {
    flex-shrink: 0; padding: 10px 18px; border-radius: 22px; font-size: 15px;
    /* Couleurs fixes (pas var(--text-rgb)/var(--text)) : ce chip vit sur .to-bottom-panel,
       fond noir en dur quel que soit le thème — voir la note plus haut sur #text-overlay-modal. */
    border: 1.5px solid rgba(248,250,252,0.25); background: rgba(255,255,255,0.06);
    color: #f8fafc; cursor: pointer; white-space: nowrap; transition: all 0.15s;
  }
  .to-font-chip.active { border-color: var(--accent); color: var(--accent); background: rgba(var(--accent-rgb),0.14); }
  .to-controls-row { display: flex; align-items: center; justify-content: space-between; }
  .to-align-group, .to-style-group { display: flex; gap: 8px; }
  /* Repères d'alignement (centre horizontal/vertical) affichés pendant le glisser-déposer d'un
     texte incrusté ou d'une mention — s'accrochent visuellement quand on approche le centre. */
  .snap-guide { position:absolute; background:var(--accent); z-index:4; pointer-events:none; opacity:0; transition:opacity 0.1s; }
  .snap-guide.show { opacity:0.9; }
  .snap-guide-v { top:0; bottom:0; left:50%; width:1px; transform:translateX(-50%); }
  .snap-guide-h { left:0; right:0; top:50%; height:1px; transform:translateY(-50%); }
  .modal-header {
    display: flex; justify-content: space-between; align-items: center;
    padding: 14px 16px; border-bottom: 1px solid rgba(var(--accent-border-rgb),0.15);
    flex-shrink: 0;
  }
  .modal-header h3 { font-family: var(--font-display); font-size: 14px; color: var(--accent); }
  .modal-close {
    background: none; border: none; color: rgba(var(--text-rgb),0.5);
    font-size: 18px; cursor: pointer;
  }
  .modal-body {
    padding: 16px; overflow-y: auto; flex: 1;
  }
  .caption-block {
    background: var(--bg-card); border: 1px solid rgba(var(--accent-border-rgb),0.1);
    border-radius: 8px; padding: 12px; margin-bottom: 10px;
    font-size: 12px; color: rgba(var(--text-rgb),0.85);
    line-height: 1.6; white-space: pre-wrap; cursor: pointer;
    position: relative;
  }
  .caption-block:hover { border-color: rgba(var(--accent-rgb),0.3); }
  .caption-block .copy-hint {
    position: absolute; top: 6px; right: 8px;
    font-size: 10px; color: rgba(var(--text-rgb),0.3);
  }
  .caption-label {
    font-size: 10px; font-weight: 700; text-transform: uppercase;
    color: rgba(var(--text-rgb),0.4); margin-bottom: 6px; letter-spacing: 0.05em;
  }
  .modal-footer {
    padding: 10px 16px calc(14px + env(safe-area-inset-bottom));
    border-top: 1px solid rgba(var(--accent-border-rgb),0.15);
    display: flex; flex-direction: column; gap: 10px; flex-shrink: 0;
  }
  .network-btn {
    flex: 1; padding: 8px; border-radius: 6px; border: none;
    font-size: 11px; font-weight: 600; cursor: pointer; transition: all 0.15s;
  }
  .network-btn.active { outline: 2px solid var(--accent); }
  .btn-ig-net { background: rgba(200,100,200,0.15); color: #e0a0e0; }
  .btn-tt-net { background: rgba(255,80,120,0.15); color: #ff90a0; }
  .btn-fb-net { background: rgba(100,130,255,0.15); color: #a0b0ff; }
  /* ── IG Preview Card ──────────────────────────────────────────────────── */
  .ig-preview-card { background:#000; border-radius:6px; overflow:hidden; border:1px solid rgba(255,255,255,0.1); margin-bottom:10px; }
  .ig-card-header { display:flex; align-items:center; gap:9px; padding:10px 12px; background:#000; }
  .ig-avatar-ring { width:32px; height:32px; border-radius:50%; padding:2px; background:linear-gradient(135deg,#f09433,#e6683c,#dc2743,#cc2366,#bc1888); flex-shrink:0; }
  .ig-avatar-inner { width:100%; height:100%; border-radius:50%; background:#222; display:flex; align-items:center; justify-content:center; font-size:13px; font-weight:700; color:#fff; border:1.5px solid #000; }
  .ig-username-row { font-size:12px; font-weight:700; color:#fff; font-family:-apple-system,BlinkMacSystemFont,sans-serif; }
  .ig-image-area { width:100%; height:270px; position:relative; background:#111; overflow:hidden; cursor:pointer; display:flex; align-items:center; justify-content:center; touch-action:auto; user-select:none; -webkit-user-select:none; }
  .ig-image-area.format-story,.ig-image-area.format-reel { height:320px; }
  .ig-image-area.drag-over::after { content:''; position:absolute; inset:0; border:2px solid rgba(var(--accent-rgb),0.6); pointer-events:none; border-radius:0; }
  .ig-image-area #pub-preview-img { width:100%; height:100%; object-fit:cover; }
  .ig-image-area.format-story #pub-preview-img,.ig-image-area.format-reel #pub-preview-img { object-fit:contain; width:auto; max-width:100%; }
  .ig-drop-hint { text-align:center; pointer-events:none; }
  .ig-actions-row { display:flex; justify-content:space-between; align-items:center; padding:8px 12px 4px; background:#000; }
  .ig-actions-left { display:flex; gap:14px; }
  .ig-caption-area { padding:2px 12px 12px; background:#000; font-size:12.5px; color:rgba(255,255,255,0.85); line-height:1.5; font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; word-break:break-word; }
  .ig-caption-handle { font-weight:700; color:#fff; margin-right:4px; }
  .ig-caption-more { color:rgba(255,255,255,0.4); cursor:pointer; font-size:12px; margin-left:2px; }
  #ig-caption-text { display:block; white-space:pre-wrap; }
  .pub-story-sticker-row {
    display:flex; align-items:center; gap:8px; padding:8px 12px 12px; background:#000;
    color:rgba(255,255,255,0.55); font-size:11px; line-height:1.4; cursor:pointer;
  }
  .pub-story-sticker-row input[type=checkbox] { width:14px; height:14px; flex-shrink:0; accent-color:var(--accent); cursor:pointer; }
  .ig-loading-block { padding:16px 12px 18px; background:#000; display:flex; flex-direction:column; align-items:center; gap:10px; }
  .ig-loading-ring { width:38px; height:38px; }
  .ig-loading-label { font-size:11px; color:rgba(255,255,255,0.3); letter-spacing:.04em; }

  .video-play-btn {
    display:none; position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
    width:52px; height:52px; border-radius:50%; z-index:5;
    background:rgba(0,0,0,0.55); border:2px solid rgba(255,255,255,0.85);
    align-items:center; justify-content:center; cursor:pointer; padding:0;
  }
  .video-play-btn.show { display:flex; }
  .video-play-btn svg { margin-left:3px; }

  .video-scrub-bar { position:absolute; left:0; right:0; bottom:0; height:24px; display:none; align-items:center; padding:0 10px; z-index:6; touch-action:none; cursor:pointer; }
  .video-scrub-bar.show { display:flex; }
  .video-scrub-track { position:relative; width:100%; height:3px; background:rgba(255,255,255,0.3); border-radius:2px; }
  .video-scrub-fill { position:absolute; top:0; left:0; height:100%; width:0%; background:#fff; border-radius:2px; }
  .video-scrub-thumb { position:absolute; top:50%; left:0%; width:10px; height:10px; border-radius:50%; background:#fff; transform:translate(-50%,-50%); box-shadow:0 0 3px rgba(0,0,0,0.5); }
  .video-scrub-bar.dragging .video-scrub-track { height:5px; }

  .pub-preview-carousel { margin-bottom:6px; cursor:grab; touch-action:pan-y; user-select:none; -webkit-user-select:none; }
  .pub-preview-page { width:100%; }
  .pub-preview-dots { display:flex; justify-content:center; gap:6px; margin-bottom:10px; }
  .pub-preview-dot { width:6px; height:6px; border-radius:50%; background:rgba(255,255,255,0.18); transition:background .15s; }
  .pub-preview-dot.active { background:var(--accent); }
  .pub-network-tabs { display:none; justify-content:center; gap:10px; margin-bottom:8px; }
  .pub-network-tab {
    padding:0; border-radius:9px; border:2px solid transparent; cursor:pointer;
    background:none; opacity:0.45; transition:opacity .15s, border-color .15s;
  }
  .pub-network-tab.active { opacity:1; border-color:var(--accent); }

  .fb-preview-card { background:#0e1a2b; border-radius:6px; overflow:hidden; border:1px solid rgba(255,255,255,0.1); }
  .fb-card-header { display:flex; align-items:center; gap:9px; padding:10px 12px; }
  .fb-avatar { width:32px; height:32px; border-radius:50%; background:#1877F2; display:flex; align-items:center; justify-content:center; font-size:14px; font-weight:700; color:#fff; flex-shrink:0; }
  .fb-username-row { font-size:12px; font-weight:700; color:#fff; }
  .fb-caption-area { padding:0 12px 10px; font-size:12.5px; color:rgba(255,255,255,0.85); line-height:1.5; word-break:break-word; }
  #fb-caption-text { display:block; white-space:pre-wrap; }
  .fb-loading-block { padding:16px 12px 18px; display:flex; flex-direction:column; align-items:center; gap:10px; }
  /* 270px comme .ig-image-area (pas 250px) : la pile d'icônes complète (fond uni + recadrer/
     retoucher/musique/...) a besoin de la même hauteur qu'Instagram pour ne pas se chevaucher —
     voir .pub-solidbg-btn (top:44) vs .pub-crop-btn (bottom:162), qui se touchaient à 250px. */
  .fb-image-area { width:100%; height:270px; background:#111; position:relative; overflow:hidden; display:flex; align-items:center; justify-content:center; }
  .fb-image-area img,.fb-image-area video { width:100%; height:100%; object-fit:cover; }
  .fb-empty-hint { text-align:center; color:rgba(255,255,255,0.25); font-size:11px; padding:0 20px; }
  /* Grille multi-photos Facebook : reflète le VRAI rendu d'un post multi-photos (attached_media),
     pas juste la diapo active — 2/3/4 cases, +N sur la dernière si plus de 4 photos. */
  .fb-media-grid { position:absolute; inset:0; display:grid; gap:2px; }
  .fb-media-grid.fb-grid-2 { grid-template-columns: 1fr 1fr; }
  .fb-media-grid.fb-grid-3 { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
  .fb-media-grid.fb-grid-3 .fb-grid-cell:first-child { grid-row: 1 / 3; }
  .fb-media-grid.fb-grid-4 { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
  .fb-grid-cell { position:relative; overflow:hidden; cursor:pointer; }
  .fb-grid-cell img,.fb-grid-cell video { width:100%; height:100%; object-fit:cover; display:block; }
  .fb-grid-cell.active { outline:2px solid var(--accent); outline-offset:-2px; }
  .fb-grid-more { position:absolute; inset:0; background:rgba(0,0,0,0.55); color:#fff; display:flex; align-items:center; justify-content:center; font-size:22px; font-weight:700; }
  .fb-actions-row { display:flex; justify-content:space-around; padding:9px 4px; border-top:1px solid rgba(255,255,255,0.08); font-size:12px; color:rgba(255,255,255,0.6); }
  .fb-actions-row span { display:flex; align-items:center; gap:5px; }

  /* YouTube réutilise toute la structure .fb-* (carte, header, zone légende, zone média) et se
     contente d'en surcharger la couleur — sinon l'aperçu YouTube s'affichait en bleu Facebook
     (#0e1a2b + avatar #1877F2). Mêmes couleurs EN DUR que le reste des aperçus, pour la raison
     expliquée plus bas (cf. .pub-format-select) : ces cartes imitent l'UI native du réseau et ne
     suivent pas le thème clair/sombre de l'app.
     Le fond est le rouge YouTube ramené à la luminosité du fond Facebook (~11 %), pas un rouge vif :
     à côté d'une vidéo il doit rester un fond, pas un aplat qui capte l'œil. */
  .yt-preview-card { background:#2c0c0c; }
  .yt-avatar { background:#cc0000; }

  .tt-preview-card { background:#000; border-radius:6px; overflow:hidden; border:1px solid rgba(255,255,255,0.1); position:relative; }
  .tt-image-area { width:100%; height:400px; background:#111; position:relative; overflow:hidden; display:flex; align-items:center; justify-content:center; }
  /* Contrairement à Facebook/LinkedIn (légende dans une zone à part sous l'image), la légende
     TikTok est incrustée EN OVERLAY sur l'image elle-même — le spinner doit donc recouvrir toute
     la zone plutôt que remplacer une zone de texte séparée. */
  .tt-loading-block { position:absolute; inset:0; z-index:7; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:10px; background:rgba(0,0,0,0.55); }
  .tt-image-area img,.tt-image-area video { width:100%; height:100%; object-fit:cover; }
  .tt-empty-hint { text-align:center; color:rgba(255,255,255,0.25); font-size:11px; padding:0 20px; }
  .tt-overlay-bottom { position:absolute; left:0; right:56px; bottom:0; padding:12px; background:linear-gradient(transparent,rgba(0,0,0,0.75)); }
  .tt-username { font-size:13px; font-weight:700; color:#fff; margin-bottom:4px; }
  #tt-caption-text { display:block; font-size:12px; color:#fff; line-height:1.4; word-break:break-word; white-space:pre-wrap; }
  .tt-overlay-icons { position:absolute; right:8px; bottom:16px; display:flex; flex-direction:column; align-items:center; gap:18px; }

  /* Options TikTok — panneau impose par les Content Sharing Guidelines (voir index.html).
     Hors de .tt-image-area : ce sont des reglages, pas une incrustation sur le media. */
  .tt-options-panel { display:none; flex-direction:column; gap:9px; margin-top:8px; padding:11px 13px; background:var(--surface-alt); border:1px solid var(--border-subtle); border-radius:var(--radius-lg); }
  .tt-options-panel.show { display:flex; }
  .tt-opt-head { display:flex; align-items:center; gap:7px; font-size:12px; color:rgba(var(--text-rgb),0.7); }
  .tt-opt-title { font-weight:700; letter-spacing:.03em; }
  .tt-opt-account { margin-left:auto; color:rgba(var(--text-rgb),0.5); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .tt-opt-account strong { color:rgba(var(--text-rgb),0.85); font-weight:600; }
  .tt-opt-row { display:flex; align-items:center; gap:9px; }
  .tt-opt-checks { gap:14px; flex-wrap:wrap; }
  .tt-opt-lbl { flex-shrink:0; font-size:12px; color:rgba(var(--text-rgb),0.55); }
  .tt-opt-select { flex:1; min-width:0; background:var(--bg-card); color:var(--text); border:1px solid var(--border-subtle); border-radius:8px; padding:7px 8px; font-size:12px; font-family:inherit; }
  .tt-opt-check { display:flex; align-items:center; gap:5px; cursor:pointer; font-size:12px; color:rgba(var(--text-rgb),0.85); }
  .tt-opt-check input { width:15px; height:15px; accent-color:var(--accent); }
  /* Interaction interdite par le compte : grisee ET non cochable, pas seulement ignoree. */
  .tt-opt-check.disabled { opacity:.35; cursor:default; }
  .tt-opt-sep { border-top:1px solid var(--border-subtle); padding-top:8px; }
  .tt-opt-commercial { display:none; align-items:center; gap:16px; flex-wrap:wrap; margin-top:7px; padding-left:21px; }
  .tt-opt-commercial.show { display:flex; }
  .tt-opt-commercial-lbl { display:none; width:100%; font-size:11px; color:var(--accent); }
  .tt-opt-commercial-lbl.show { display:block; }
  .tt-opt-commercial-lbl.warn { color:#e0a060; }
  /* Avertissement d'audit : visible seulement tant que le client n'est pas audite. */
  .tt-opt-warning { display:none; font-size:11px; line-height:1.45; color:#e0a060; background:rgba(224,160,96,0.10); border:1px solid rgba(224,160,96,0.25); border-radius:8px; padding:7px 9px; }
  .tt-opt-warning.show { display:block; }
  .tt-opt-legal { font-size:11px; color:rgba(var(--text-rgb),0.55); line-height:1.45; }
  .tt-opt-legal a { color:var(--accent); }
  .tt-opt-legal.warn { color:#e0a060; }
  .tt-opt-delay { font-size:11px; color:rgba(var(--text-rgb),0.4); line-height:1.4; }

  .app-overlay {
    position:fixed; inset:0; z-index:500; display:none;
    flex-direction:column; align-items:center; justify-content:center; gap:16px;
    background:rgba(10,18,16,0.88); backdrop-filter:blur(3px);
  }
  .app-overlay.active { display:flex; }
  .app-overlay-ring { width:52px; height:52px; }
  .app-overlay-label { font-size:13px; color:var(--text); font-weight:600; text-align:center; padding:0 30px; }

  /* Connexion d'un réseau social (network-connect.js) — bloque l'écran du clic jusqu'à la
     confirmation du statut serveur. z-index au-dessus de tout le reste, bannière de mise à
     jour (998) comprise : tant que la connexion n'est pas tranchée, rien d'autre n'est
     cliquable, et aucune sortie n'est offerte avant un état certain (succès ou échec). */
  .netconnect-overlay {
    position:fixed; inset:0; z-index:1200; display:none;
    align-items:center; justify-content:center; padding:24px;
    background:rgba(10,18,16,0.92); backdrop-filter:blur(4px);
  }
  .netconnect-overlay.active { display:flex; }
  .netconnect-box {
    width:100%; max-width:330px; padding:26px 22px; text-align:center;
    display:flex; flex-direction:column; align-items:center; gap:13px;
    background:var(--glass-bg); backdrop-filter:blur(16px); -webkit-backdrop-filter:blur(16px);
    border:1px solid var(--border-subtle); border-radius:var(--radius-xl);
  }
  .netconnect-logo svg { box-shadow:0 4px 18px rgba(0,0,0,0.35); }
  .netconnect-ring { width:44px; height:44px; }
  .netconnect-badge {
    width:44px; height:44px; border-radius:50%; font-size:22px; font-weight:700;
    display:flex; align-items:center; justify-content:center;
  }
  .netconnect-badge.success { background:rgba(128,224,144,0.14); color:#80e090; border:1px solid rgba(128,224,144,0.35); }
  .netconnect-badge.error { background:rgba(220,80,80,0.12); color:#e08080; border:1px solid rgba(220,80,80,0.3); }
  .netconnect-title { font-size:15px; font-weight:700; color:var(--text); }
  .netconnect-msg { font-size:12.5px; line-height:1.5; color:rgba(var(--text-rgb),0.65); }
  .netconnect-msg:empty { display:none; }
  .netconnect-actions { display:flex; gap:8px; width:100%; margin-top:2px; }
  .netconnect-actions .btn { flex:1; padding:11px 0; font-size:12px; }
  /* Liste de choix de l'overlay (Pages Facebook). Défilante : un compte Meta peut porter
     beaucoup de Pages, et la boîte ne doit pas déborder de l'écran sur mobile. */
  .netconnect-choices { display:flex; flex-direction:column; gap:6px; width:100%; margin-top:2px; max-height:46vh; overflow-y:auto; }
  .netconnect-choice { display:flex; flex-direction:column; align-items:flex-start; gap:2px; width:100%; padding:11px 13px; background:var(--bg2); border:1px solid rgba(var(--text-rgb),0.12); border-radius:10px; cursor:pointer; text-align:left; font-family:inherit; }
  .netconnect-choice:hover:not(.disabled) { border-color:var(--accent); background:rgba(var(--accent-rgb),0.08); }
  .netconnect-choice.disabled { opacity:0.45; cursor:not-allowed; }
  .netconnect-choice-nom { font-size:13px; font-weight:600; color:var(--text); }
  .netconnect-choice-note { font-size:11px; color:rgba(var(--text-rgb),0.55); }
  .pub-remove-btn { position:absolute; top:8px; left:8px; background:rgba(0,0,0,0.6); border:none; color:#fff; border-radius:50%; width:26px; height:26px; cursor:pointer; font-size:15px; display:flex; align-items:center; justify-content:center; line-height:1; }
  .pub-add-btn { position:absolute; top:8px; right:8px; background:rgba(0,0,0,0.55); border:none; color:#fff; border-radius:50%; width:28px; height:28px; cursor:pointer; font-size:20px; display:flex; align-items:center; justify-content:center; line-height:1; backdrop-filter:blur(4px); }
  .pub-slide-counter { position:absolute; bottom:10px; left:50%; transform:translateX(-50%); background:rgba(0,0,0,0.55); color:#fff; font-size:11px; font-weight:600; border-radius:10px; padding:3px 9px; backdrop-filter:blur(4px); pointer-events:none; white-space:nowrap; }
  .pub-icon-btn { position:absolute; right:8px; width:30px; height:30px; background:rgba(0,0,0,0.55); border:none; color:#fff; border-radius:50%; cursor:pointer; align-items:center; justify-content:center; backdrop-filter:blur(4px); font-weight:700; font-size:13px; }
  /* Carré (pas rond comme les autres icônes) pour bien le distinguer, posé juste sous le "+" —
     hors de la pile d'icônes du bas (qui suit le format post/story) pour ne jamais en déborder,
     et hors de la zone qui déclenche l'input file au clic (source du bug "ouvre le browser"
     quand le lien vivait dans le message vide de #ig-image-area). */
  .pub-solidbg-btn { position:absolute; top:44px; right:8px; border-radius:6px; }
  .pub-preview-reset-btn { bottom:238px; }
  .pub-cover-btn { bottom:200px; }
  .pub-crop-btn { bottom:162px; }
  .pub-text-btn { bottom:124px; }
  .pub-mention-btn { bottom:86px; }
  .fb-text-btn,.tt-text-btn { top:8px; right:8px; }
  .net-copy-overlays-btn { top:8px; right:46px; font-size:14px; }
  .pub-retouch-btn { bottom:48px; }
  .pub-music-btn { bottom:10px; }
  /* Le logo ouvre une SECONDE colonne, à gauche : la pile de droite est pleine (7 icônes de
     bottom:10 à bottom:238 pour une zone haute de 270px, cf. .ig-image-area), un 8e bouton y
     déborderait. Le coin haut-gauche est déjà pris par .pub-remove-btn, le bas-gauche est libre. */
  .pub-icon-btn-left { right:auto; left:8px; }
  .pub-logo-btn { bottom:10px; }
  /* Facebook a maintenant la même pile d'outils qu'Instagram (recadrer/musique/retouche/...) —
     réutilise ces mêmes réglages "bottom" plutôt que le coin top-right (qui collisionnerait avec
     les nouveaux fb-add-btn/fb-remove-img). TikTok, lui, garde sa position d'origine (pas encore
     étendu à la même boîte à outils), d'où ces overrides scopés par ID plutôt que sur .fb-text-btn. */
  #fb-text-btn { top:auto; bottom:86px; }
  #fb-copy-overlays-btn { top:auto; right:8px; bottom:124px; }
  .pub-ratio-warning {
    position:absolute; top:8px; left:50%; transform:translateX(-50%); z-index:5;
    background:rgba(230,80,80,0.85); border:none; color:#fff; font-size:11px; font-weight:600;
    padding:6px 10px; border-radius:8px; cursor:pointer; backdrop-filter:blur(4px);
    white-space:nowrap; max-width:90%; overflow:hidden; text-overflow:ellipsis;
  }
  /* Sur Instagram, le badge de ratio (pub-ratio-warning) partage la même position — décalé plus
     bas pour ne pas se superposer si les deux problèmes surviennent en même temps. */
  #pub-media-format-warning { top: 34px; }
  .pub-media-warning {
    position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); z-index:6;
    background:rgba(230,80,80,0.9); color:#fff; font-size:12.5px; font-weight:600;
    padding:12px 18px; border-radius:10px; backdrop-filter:blur(4px);
    max-width:85%; text-align:center; opacity:0; transition:opacity 0.3s; pointer-events:none;
  }
  .pub-media-warning.show { opacity:1; }
  .pub-text-edit-badge {
    position:absolute; width:26px; height:26px; border-radius:50%;
    background:rgba(0,0,0,0.55); border:none; color:#fff; font-size:12px;
    display:flex; align-items:center; justify-content:center; cursor:pointer;
    backdrop-filter:blur(4px); transform:translate(-50%,-50%); z-index:5; pointer-events:auto;
  }
  .pub-text-erase-badge {
    position:absolute; width:26px; height:26px; border-radius:50%;
    background:rgba(200,40,40,0.75); border:none; color:#fff; font-size:12px;
    display:flex; align-items:center; justify-content:center; cursor:pointer;
    backdrop-filter:blur(4px); transform:translate(-50%,-50%); z-index:5; pointer-events:auto;
  }
  .pub-mention-wrap { position:absolute; transform:translate(-50%,-50%); pointer-events:auto; }
  .pub-mention-pill {
    position:relative; background:rgba(0,0,0,0.65); color:#fff; border:none; border-radius:20px;
    padding:5px 12px; font-size:12px; font-weight:600; cursor:pointer; backdrop-filter:blur(4px);
    white-space:nowrap;
  }
  .pub-mention-pill-del {
    position:absolute; top:-8px; right:-8px; width:18px; height:18px; border-radius:50%;
    background:rgba(200,40,40,0.85); color:#fff; border:none; font-size:10px; cursor:pointer;
    display:flex; align-items:center; justify-content:center; line-height:1; padding:0;
  }
  .mention-suggestion-item {
    padding:8px 10px; font-size:13px; color:var(--text); cursor:pointer;
  }
  .mention-suggestion-item:hover, .mention-suggestion-item.active { background:rgba(var(--accent-rgb),0.15); }

  /* Music picker + waveform trim editor */
  .music-category { font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; color:rgba(var(--text-rgb),0.4); margin:14px 0 6px; }
  .music-category:first-child { margin-top:0; }
  .music-track-row { display:flex; align-items:center; gap:10px; padding:9px 10px; border-radius:8px; cursor:pointer; }
  .music-track-row:hover { background:rgba(var(--accent-rgb),0.08); }
  .music-track-title { font-size:13px; color:var(--text); flex:1; }
  .music-track-duration { font-size:11px; color:rgba(var(--text-rgb),0.4); }
  .music-track-play {
    flex-shrink:0; width:26px; height:26px; border-radius:50%; border:none;
    background:rgba(var(--accent-rgb),0.15); color:var(--accent); font-size:11px;
    display:flex; align-items:center; justify-content:center; cursor:pointer;
  }
  .music-track-play:hover { background:rgba(var(--accent-rgb),0.3); }
  .music-duration-picker { display:flex; gap:6px; margin-bottom:10px; }
  .music-duration-opt { flex:1; padding:6px; border:1px solid rgba(var(--accent-border-rgb),0.3); border-radius:6px; background:transparent; color:rgba(var(--text-rgb),0.6); cursor:pointer; font-size:12px; }
  .music-duration-opt.active { background:var(--accent); color:var(--bg-elevated); font-weight:700; border-color:var(--accent); }
  .waveform-wrap { position:relative; height:64px; overflow:hidden; background:#12201c; border-radius:8px; margin:0 8px; }
  #waveform-svg { position:absolute; top:0; height:64px; touch-action:none; cursor:grab; }
  #waveform-svg.dragging { cursor:grabbing; }
  .video-duration-window { position:absolute; top:0; bottom:0; left:50%; transform:translateX(-50%); border:2px solid var(--accent); background:rgba(var(--accent-rgb),0.10); pointer-events:none; border-radius:4px; }
  .pub-thumb-strip { display:flex; gap:6px; padding:8px 12px; background:#000; overflow-x:auto; }
  .pub-thumb { position:relative; flex-shrink:0; width:46px; height:46px; border-radius:6px; overflow:hidden; border:2px solid transparent; cursor:grab; touch-action:none; }
  .pub-thumb.active { border-color:var(--accent); }
  .pub-thumb.dragging { opacity:0.5; z-index:10; cursor:grabbing; }
  .pub-thumb img, .pub-thumb video { width:100%; height:100%; object-fit:cover; display:block; pointer-events:none; }
  /* Format select — un par page réseau (header ig/fb/li), indépendant par réseau. Facebook et
     LinkedIn n'ont que 2 <option> (pas de Story, rejetée par leur API — voir network-media
     compat côté serveur) donc pas de largeur fixe, on laisse le contenu piloter. */
  /* Couleurs EN DUR, pas les tokens de thème : l'aperçu imite l'UI sombre d'Instagram/Facebook/
     LinkedIn, donc .ig-preview-card & co restent en #000 dans les deux thèmes (le pseudo et
     l'heure juste à côté sont d'ailleurs en blanc en dur). Avec rgba(var(--text-rgb),...), le
     sélecteur virait au noir sur fond noir en thème clair — illisible. La liste déroulante
     ouverte est peinte par le navigateur avec les couleurs du <select>, d'où la règle option. */
  .pub-format-select {
    background:rgba(0,0,0,0.35); color:rgba(255,255,255,0.9); border:1px solid rgba(var(--accent-border-rgb),0.25);
    border-radius:999px; padding:4px 8px; font-size:10px; font-weight:700; letter-spacing:.04em;
    text-transform:uppercase; cursor:pointer; flex-shrink:0;
  }
  .pub-format-select option { background:#1c1c1e; color:#fff; text-transform:none; }
  .pub-format-select:focus { outline:none; border-color:var(--accent); }
  /* Pastilles type de contenu / format d'un post passé — remplace les 3 .pub-format-select (voir
     openHistoryItem dans history.js), même bordure de séparation que les anciens tabs. */
  .pub-task-badges { display:flex; align-items:center; gap:6px; flex-wrap:wrap; padding:10px 14px; border-bottom:1px solid rgba(var(--accent-border-rgb),0.12); }
  /* Network checkboxes */
  .pub-ia-row { display:flex; align-items:center; justify-content:center; gap:6px; font-size:11px; color:rgba(var(--text-rgb),0.55); cursor:pointer; user-select:none; }
  .pub-ia-row input[type=checkbox] { width:14px; height:14px; accent-color:var(--accent); cursor:pointer; }
  .pub-networks-row { display:flex; gap:18px; justify-content:center; }
  .pub-network-check { display:flex; align-items:center; gap:6px; font-size:11px; color:rgba(var(--text-rgb),0.55); cursor:pointer; user-select:none; }
  .pub-network-check input[type=checkbox] { width:14px; height:14px; accent-color:var(--accent); cursor:pointer; }
  /* Caption textarea */
  .caption-textarea { width:100%; background:var(--surface-alt); border:1px solid var(--border-subtle); border-radius:var(--radius-lg); padding:11px 12px; font-size:12px; color:rgba(var(--text-rgb),0.9); line-height:1.6; resize:vertical; font-family:inherit; box-sizing:border-box; margin-bottom:8px; }
  .caption-textarea:focus { outline:none; border-color:var(--accent-cyan); }
  .btn:disabled { opacity:0.38; cursor:not-allowed; pointer-events:none; }
  .btn-outline { background:transparent; color:var(--accent); border:1px solid rgba(var(--accent-rgb),0.5); }
  .btn-outline:hover { background:rgba(var(--accent-rgb),0.08); }
  .pub-actions { display:flex; gap:7px; position:relative; }
  .pub-actions .btn { flex:1; padding:11px 0; display:flex; align-items:center; justify-content:center; }
  .pub-actions .btn svg { width:18px; height:18px; flex-shrink:0; }
  .pub-actions .btn-instagram {
    flex:1.3; border:none; color:#fff;
    background:linear-gradient(45deg,#f09433 0%,#e6683c 25%,#dc2743 50%,#cc2366 75%,#bc1888 100%);
  }
  .schedule-picker { position:absolute; bottom:calc(100% + 8px); right:0; background:var(--bg-elevated); border:1px solid rgba(var(--accent-border-rgb),0.3); border-radius:10px; padding:14px; z-index:200; min-width:230px; box-shadow:0 8px 32px rgba(0,0,0,0.6); }
  .schedule-picker-title { font-size:11px; color:rgba(var(--text-rgb),0.4); letter-spacing:.06em; text-transform:uppercase; margin-bottom:10px; }
  .schedule-picker input[type="date"],.schedule-picker input[type="time"] { background:var(--surface-alt); border:1px solid rgba(var(--accent-border-rgb),0.25); border-radius:5px; color:var(--text); padding:7px 9px; font-size:13px; width:100%; box-sizing:border-box; margin-bottom:8px; }
  .schedule-picker-row { display:flex; gap:6px; margin-top:4px; }

  /* ── Espaces (multi-marques) ───────────────────────────────────────────── */
  /* Section "Vos espaces" de l'écran Compte : seul chemin d'accès sur mobile, où le switcheur
     de la sidebar desktop est masqué. */
  .config-hint { font-size:12px; color:rgba(var(--text-rgb),0.45); line-height:1.5; margin:-4px 0 12px; }
  /* Aperçu du logo client, carré et centré. Damier plutôt qu'un aplat : c'est le seul moyen de
     voir d'un coup d'oeil si le PNG a bien un fond transparent — un logo sur fond blanc posé sur
     une photo fait un timbre-poste, et l'utilisateur ne s'en apercevrait qu'après l'avoir
     incrusté. Fond blanc dans les deux thèmes : un logo se juge sur clair. */
  .cfg-logo-preview {
    position:relative; width:120px; aspect-ratio:1/1; margin:0 auto 8px;
    border-radius:var(--radius-lg); border:1px solid var(--border-subtle); overflow:hidden;
    display:flex; align-items:center; justify-content:center;
    background-color:#fff;
    background-image:
      linear-gradient(45deg, rgba(0,0,0,0.08) 25%, transparent 25%, transparent 75%, rgba(0,0,0,0.08) 75%),
      linear-gradient(45deg, rgba(0,0,0,0.08) 25%, transparent 25%, transparent 75%, rgba(0,0,0,0.08) 75%);
    background-size:16px 16px;
    background-position:0 0, 8px 8px;
  }
  .cfg-logo-preview img { max-width:80%; max-height:80%; object-fit:contain; }
  .cfg-logo-empty { font-size:11px; color:rgba(0,0,0,0.35); }
  .cfg-logo-hint { text-align:center; margin:0 0 8px; }
  /* Boutons étroits et centrés (pas de .btn-full) : le logo se règle en un clic, il n'a pas le
     poids d'un « Sauvegarder » pleine largeur. */
  .cfg-logo-actions { display:flex; justify-content:center; gap:8px; }
  .cfg-logo-actions .btn { padding:7px 14px; }
  /* Sous-bloc d'une card de reglages : separe visuellement deux sujets qui partagent la meme
     card parce qu'ils portent sur le meme objet (ici l'espace ouvert : sa zone, puis la liste
     des espaces). Le trait remplace la bordure de card qu'on vient de leur retirer. */
  /* Creneaux de la journee (voir static/js/creneaux.js). Les graphiques reutilisent
     .stats-chart-svg / .stats-chart-note, deja definis plus haut pour les courbes de
     croissance : meme grammaire visuelle, rien de nouveau a maintenir. */
  .creneaux-sous-titre { font-size:11px; font-weight:600; color:rgba(var(--text-rgb),0.55);
    margin:12px 0 4px; }
  .creneaux-picker { margin:6px 0 4px; }
  .creneaux-picker .stats-chart-svg { height:62px; }
  /* Pas de max-width ici : les graphiques de creneaux portent le leur EN LIGNE, calcule avec
     leur viewBox (voir largeurRendu dans creneaux.js). Le poser aussi en CSS creerait deux
     sources a garder d'accord — et un desaccord entre les deux est exactement ce qui deformait
     le dessin. */
  .creneaux-picker-note { font-size:10px; color:rgba(var(--text-rgb),0.45); text-align:center;
    margin-top:2px; }

  /* Semaines futures de l'horizon de planning (voir loadWeek, week.js). Repliees par defaut :
     depliees, quatre semaines font un mur de 28 sections dans lequel la tache du jour se perd.
     Le compteur de l'en-tete dit s'il y a quelque chose dedans sans avoir a ouvrir. */
  .week-bloc { margin-top:14px; border-top:1px solid rgba(var(--text-rgb),0.09); padding-top:10px; }
  .week-bloc-header { display:flex; align-items:center; gap:8px; cursor:pointer;
    font-size:12px; font-weight:600; color:rgba(var(--text-rgb),0.6); padding:4px 0; }
  .week-bloc-caret { font-size:10px; color:var(--accent); }
  .week-bloc-count { margin-left:auto; font-size:11px; font-weight:500;
    color:rgba(var(--text-rgb),0.4); }
  .week-bloc-body.hidden { display:none; }

  /* Conseil de reseau dans la card de connexion (voir renderConseilReseau). Teinte d'accent
     pour se distinguer du texte d'aide au-dessus, sans crier : c'est une suggestion, pas une
     alerte — la card ne doit pas donner l'impression qu'il manque quelque chose d'urgent. */
  .conseil-reseau { margin:10px 0 4px; padding:10px 12px; border-radius:10px;
    background:rgba(var(--accent-rgb),0.07); border:1px solid rgba(var(--accent-rgb),0.2); }
  .conseil-reseau-tete { font-size:12px; font-weight:600; color:var(--accent); }
  .conseil-reseau-txt { font-size:11.5px; color:rgba(var(--text-rgb),0.65); margin-top:3px;
    line-height:1.45; }
  .conseil-reseau-lien { margin-top:8px; font-size:11px; padding:5px 10px; }

  .config-sous-bloc { margin-top:16px; padding-top:14px; border-top:1px solid rgba(var(--text-rgb),0.09); }

  .espace-row {
    display:flex; align-items:center; gap:10px;
    padding:10px 12px; margin-bottom:8px;
    background:rgba(var(--text-rgb),0.04);
    border:1px solid rgba(var(--accent-border-rgb),0.14);
    border-radius:10px;
  }
  .espace-row.active { border-color:rgba(var(--accent-rgb),0.45); background:rgba(var(--accent-rgb),0.07); }
  .espace-row-main { flex:1; min-width:0; }
  .espace-row:not(.active) .espace-row-main { cursor:pointer; }
  .espace-row-nom { font-size:14px; font-weight:600; color:var(--text); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .espace-row-badge {
    font-size:10px; font-weight:600; text-transform:uppercase; letter-spacing:.05em;
    color:var(--accent); background:rgba(var(--accent-rgb),0.14);
    padding:1px 6px; border-radius:20px; vertical-align:middle; margin-left:4px;
  }
  .espace-row-sub { font-size:11px; color:rgba(var(--text-rgb),0.45); margin-top:2px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .espace-row-actions { display:flex; gap:4px; flex:0 0 auto; }
  .espace-row-btn {
    width:30px; height:30px; border-radius:7px; cursor:pointer;
    background:rgba(var(--text-rgb),0.06); border:1px solid rgba(var(--text-rgb),0.1);
    color:rgba(var(--text-rgb),0.6); font-size:13px; line-height:1;
    display:flex; align-items:center; justify-content:center;
  }
  .espace-row-btn:hover { background:rgba(var(--text-rgb),0.12); color:var(--text); }
  .espace-row-btn-danger:hover { background:rgba(220,80,80,0.14); color:#e08080; border-color:rgba(220,80,80,0.3); }

  /* Jauges d'usage (voir renderEspacesSection / quotas.py). Deux familles VOLONTAIREMENT
     distinctes, parce qu'elles ne disent pas la meme chose :
       .quota-item  — un plafond REEL et applique (espaces, reseaux, stockage) : une barre qui se
                      remplit, et la question a laquelle elle repond est « puis-je en ajouter un ? »
       .quota-rythme — un simple compteur (publications, echanges avec Alex) : PAS de barre, parce
                      qu'aucun plafond n'existe et qu'une jauge en inventerait un. */
  .quota-bloc { margin-bottom:12px; padding:10px 12px; border-radius:10px;
    background:rgba(var(--text-rgb),0.03); border:1px solid rgba(var(--accent-border-rgb),0.1); }
  .quota-bloc-titre { font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:.04em;
    color:rgba(var(--text-rgb),0.45); margin-bottom:8px; }
  .quota-item { margin-bottom:8px; }
  .quota-item:last-child { margin-bottom:0; }
  .quota-head { display:flex; justify-content:space-between; align-items:baseline; gap:8px; margin-bottom:3px; }
  .quota-label { font-size:11px; color:rgba(var(--text-rgb),0.6); }
  .quota-val { font-size:11px; font-weight:700; color:rgba(var(--text-rgb),0.75); flex:0 0 auto; }
  .quota-bar { position:relative; height:5px; border-radius:3px; overflow:hidden;
    background:rgba(var(--accent-rgb),0.12); }
  .quota-fill { height:100%; background:var(--accent); transition:width .3s ease; }
  .quota-fill.attention { background:#e0a060; }
  .quota-fill.alerte { background:#e08080; }
  /* Compteur sans plafond : les trois periodes sur une ligne, separees par des points medians
     — meme grammaire que .espace-row-sub, pour que ca se lise comme une precision et non comme
     une alerte. */
  .quota-rythme { font-size:11px; color:rgba(var(--text-rgb),0.45); margin-top:4px; }
  .quota-rythme strong { color:rgba(var(--text-rgb),0.7); font-weight:600; }
  .quota-espace { margin-top:8px; padding-top:8px; border-top:1px solid rgba(var(--text-rgb),0.07); }

  /* Sortie de secours de l'onboarding d'un espace neuf (voir renderOnboardingBack) — sans elle,
     créer un espace par erreur enfermerait le client hors de sa marque existante. */
  .onboarding-espace-back { margin-top:12px; display:flex; flex-wrap:wrap; gap:6px; justify-content:center; }
  .onboarding-espace-back.hidden { display:none; }
  .onboarding-espace-back-btn {
    background:rgba(var(--text-rgb),0.07); border:1px solid rgba(var(--text-rgb),0.12);
    color:rgba(var(--text-rgb),0.7); font-size:12px; font-family:inherit;
    padding:6px 12px; border-radius:20px; cursor:pointer;
  }
  .onboarding-espace-back-btn:hover { background:rgba(var(--text-rgb),0.13); color:var(--text); }

/* Icone d'information des cards de chiffres. Un « i » discret, et une infobulle ancree plutot
   qu'une modale : on consulte l'explication d'un oeil sans perdre l'ecran de vue. */
.stat-info {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; margin-left: 6px; vertical-align: middle;
  border-radius: 50%;
  border: 1px solid rgba(var(--accent-rgb), 0.45);
  background: rgba(var(--accent-rgb), 0.10);
  color: var(--accent);
  font-size: 10px; font-weight: 700; font-style: italic;
  cursor: pointer; flex-shrink: 0;
}
.stat-info:hover { background: rgba(var(--accent-rgb), 0.2); }
.stat-info-bulle {
  display: none;
  position: absolute; z-index: 40; top: 22px; left: 0; transform: none;
  width: 240px;
  background: var(--bg-card, #1b1b24);
  border: 1px solid rgba(var(--accent-rgb), 0.35);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 11.5px; line-height: 1.5; font-weight: 400; font-style: normal;
  color: rgba(var(--text-rgb), 0.85);
  text-align: left;
  box-shadow: 0 8px 24px rgba(0,0,0,0.35);
}
.stat-info.ouverte .stat-info-bulle { display: block; }
/* Pres du bord droit, l'infobulle se recale pour ne pas sortir de la card. */
.stat-info.bord-droit .stat-info-bulle { left: auto; right: 0; transform: none; }

/* Loader d'une seule card : les analyses n'arrivent pas ensemble (le score de sante passe par
   Claude, les abonnes arrivent tout de suite), chaque card attend donc la sienne. */
.stats-case-loader {
  display: flex; justify-content: center; align-items: center;
  /* min-height : la card garde sa place pendant le chargement, elle ne saute pas quand la
     donnee arrive. */
  min-height: 96px; padding: 12px 0;
}
/* Meme GIF que .loader / .loader-big — un seul loader dans toute l'app — mais a une taille
   intermediaire : 14px (la puce des bulles de chat) etait invisible dans une card, 144px
   ecraserait un cadran de chiffres. */
.stats-case-loader::after {
  content: ''; width: 56px; height: 56px;
  background: url('/static/img/loader/loader-icon.gif') center/contain no-repeat;
}


/* Bouton « rechercher a nouveau » des evenements — discret, aligne a droite de l'en-tete. */
.events-refresh {
  float: right; background: none; border: none; cursor: pointer;
  color: rgba(var(--text-rgb), 0.45); font-size: 15px; line-height: 1;
  padding: 0 2px; transition: color .15s;
}
.events-refresh:hover { color: var(--accent); }
.events-refresh:disabled { cursor: default; opacity: .5; }
.events-refresh.tourne { animation: events-refresh-spin .9s linear infinite; }
@keyframes events-refresh-spin { to { transform: rotate(360deg); } }
