/* La feuille de style des deux back offices — celui de l'ÉDITEUR (/admin) et celui du CLIENT
   (/account). UNE seule, servie à la racine et publique comme les deux portes qu'elle habille.
   ⚠️ Elle a failli être copiée en deux exemplaires : deux feuilles qui se ressemblent dérivent, et la
   divergence ne se voit que sur la page qu'on regarde le moins. */
/* The management plane's stylesheet, shared by the door and the console.
   The ramp is the editor's own (`web/src/app/globals.css`) and the waiting page's, so this reads as the
   same product rather than as a tool bolted on beside it. Day and night both, because the front is
   consulted at 07:10 and at 22:00 and neither is the odd one out. */
:root {
  color-scheme: dark;
  --bg: #0f0f12; --chrome: #141418; --rule: #26262c; --rule-2: #22222a;
  --panel: #16161c; --panel-rule: #2e2e38; --field: #1e1e25; --field-rule: #33333c;
  --fg-hi: #f4f4f8; --fg: #e7e7ea; --fg-2: #c6c6d0; --fg-4: #8a8a93; --fg-5: #6f6f79; --fg-6: #55555f;
  --plate-white: #f4f4f8; --door-a: #17171c; --door-b: #131317;
  --accent: #2b6cff; --accent-hi: #4680ff; --focus: #6f9bff;
  --ok: #6ee7a0; --warn: #ffcf6a; --bad: #ff8a8a; --shadow: #0009;
}
:root[data-theme="light"] {
  color-scheme: light;
  --bg: #ececed; --chrome: #fbfbfc; --rule: #dcdce1; --rule-2: #ebebef;
  --panel: #ffffff; --panel-rule: #d9d9df; --field: #f5f5f7; --field-rule: #cfcfd7;
  --fg-hi: #000; --fg: #17171b; --fg-2: #3d3d47; --fg-4: #71717c; --fg-5: #8a8a95; --fg-6: #a6a6b0;
  --plate-white: #d6d6dd; --door-a: #e4e4e9; --door-b: #eeeef1;
  --ok: #1a8f52; --warn: #9a6a00; --bad: #c0332b; --shadow: #00000026;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
html { background: var(--bg); }
body { font: 13px/1.5 ui-sans-serif, system-ui, -apple-system, sans-serif; color: var(--fg);
       background: var(--bg); }
button, input, textarea, select { font: inherit; color: inherit; }
a { color: var(--accent); }

/* --- the door ------------------------------------------------------------------------------------ */
body.door { display: flex; align-items: center; justify-content: center; padding: 24px;
            background: var(--bg) repeating-conic-gradient(var(--door-a) 0 25%, var(--door-b) 0 50%) 0/26px 26px; }
.plate { width: 100%; max-width: 340px; background: var(--chrome); border: 1px solid var(--rule);
         border-radius: 12px; padding: 28px; box-shadow: 0 24px 60px var(--shadow); }
/* Two plates of one word, out of register — the defect this product exists to prevent. The editor's
   door snaps them together as it opens; here they stay apart, because this is the back of house. */
.mark { position: relative; font-size: 30px; font-weight: 700; letter-spacing: .14em;
        text-transform: uppercase; line-height: 1; margin-right: -.14em; }
.mark span { display: block; }
.mark .ink { color: var(--fg); position: relative; }
.mark .white { position: absolute; inset: 0; color: var(--plate-white); transform: translate(2.5px, -1px); }
.regline { margin-top: 12px; font-family: ui-monospace, Menlo, monospace; font-size: 10px;
           letter-spacing: .09em; text-transform: uppercase; color: var(--fg-5); }
.field { display: block; margin-top: 22px; }
.field span { display: block; font-size: 11px; color: var(--fg-4); margin-bottom: 5px; }
.field input { width: 100%; padding: 9px 11px; background: var(--field); color: var(--fg);
               border: 1px solid var(--field-rule); border-radius: 7px; outline: none; }
.field input:focus { border-color: var(--accent); }
.err { margin-top: 9px; font-size: 12px; color: var(--bad); min-height: 18px; }
.go { margin-top: 6px; width: 100%; padding: 9px; border: 0; border-radius: 7px; font-weight: 600;
      background: var(--accent); color: #fff; cursor: pointer; }
.go:hover { background: var(--accent-hi); }

/* --- the console --------------------------------------------------------------------------------- */
.shell { display: flex; flex-direction: column; height: 100vh; height: 100dvh; }
.top { flex: none; height: 46px; display: flex; align-items: center; gap: 4px; padding: 0 12px;
       background: var(--chrome); border-bottom: 1px solid var(--rule); }
.brand { font-size: 13px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
         color: var(--fg-4); padding-right: 10px; }
.tab { padding: 6px 12px; border: 0; background: transparent; color: var(--fg-4); border-radius: 7px;
       cursor: pointer; }
.tab:hover { background: var(--rule-2); color: var(--fg-hi); }
.tab[aria-selected="true"] { background: var(--accent); color: #fff; font-weight: 600; }
.gap { margin-left: auto; }
.quiet { border: 1px solid var(--field-rule); background: transparent; color: var(--fg-4);
         padding: 5px 10px; border-radius: 7px; cursor: pointer; }
.quiet:hover { background: var(--rule-2); color: var(--fg-hi); }
.page { flex: 1; min-height: 0; display: none; }
.page.on { display: flex; }

/* tickets: a list, and the one being looked at */
.list { width: 340px; flex: none; border-right: 1px solid var(--rule); display: flex;
        flex-direction: column; background: var(--chrome); }
.filters { flex: none; padding: 10px; border-bottom: 1px solid var(--rule); display: flex;
           flex-wrap: wrap; gap: 6px; }
.filters input { flex: 1 1 100%; padding: 6px 9px; background: var(--field); border: 1px solid var(--field-rule);
                 border-radius: 6px; outline: none; }
.chip { padding: 4px 9px; border: 1px solid var(--field-rule); background: transparent; color: var(--fg-4);
        border-radius: 999px; font-size: 11px; cursor: pointer; }
.chip[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: #fff; }
.rows { flex: 1; overflow: auto; }
.row { display: block; width: 100%; text-align: left; padding: 10px 12px; border: 0;
       border-bottom: 1px solid var(--rule-2); background: transparent; color: var(--fg-2); cursor: pointer; }
.row:hover { background: var(--rule-2); }
.row.on { background: var(--panel); color: var(--fg-hi); box-shadow: inset 3px 0 0 var(--accent); }
.row b { display: block; font-weight: 500; color: inherit; overflow: hidden; text-overflow: ellipsis;
         white-space: nowrap; }
.row i { display: block; margin-top: 3px; font-style: normal; font-size: 11px; color: var(--fg-5);
         font-variant-numeric: tabular-nums; }
.detail { flex: 1; min-width: 0; overflow: auto; padding: 18px 20px 40px; }
.empty { color: var(--fg-5); padding: 24px; }

h2 { font-size: 15px; font-weight: 600; }
h3 { font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
     color: var(--fg-5); margin: 20px 0 8px; }
.said { background: var(--panel); border: 1px solid var(--panel-rule); border-radius: 9px;
        padding: 12px 14px; white-space: pre-wrap; }
.said + .said { margin-top: 8px; }
.said em { display: block; font-style: normal; font-size: 11px; color: var(--fg-5); margin-bottom: 4px; }
.facts { display: grid; grid-template-columns: max-content 1fr; gap: 4px 16px; font-variant-numeric: tabular-nums; }
.facts dt { color: var(--fg-5); }
.facts dd { color: var(--fg-2); overflow-wrap: anywhere; }
/* A report made on code that is no longer running is not a new defect until proven otherwise — half of
   what looks like one is a report from before the fix, and the four chain fixes of 2026-09-01 all
   shipped in one go. It is the row that decides whether to go looking at all. */
.facts .stale { color: var(--warn); font-weight: 400; }
.state { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 11px;
         border: 1px solid var(--field-rule); color: var(--fg-4); }
.state.new { color: var(--warn); border-color: var(--warn); }
.state.understood { color: var(--accent-hi); border-color: var(--accent-hi); }
.state.fixed { color: var(--ok); border-color: var(--ok); }
.state.not_a_bug { color: var(--fg-5); }
.acts { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.acts input { flex: 1; min-width: 140px; padding: 6px 9px; background: var(--field);
              border: 1px solid var(--field-rule); border-radius: 6px; outline: none; }
.shots { display: flex; flex-wrap: wrap; gap: 12px; }
.shot { width: 210px; background: var(--panel); border: 1px solid var(--panel-rule); border-radius: 9px;
        padding: 8px; }
.shot img { display: block; width: 100%; height: 150px; object-fit: contain;
            background: repeating-conic-gradient(var(--door-a) 0 25%, var(--door-b) 0 50%) 0/14px 14px; }
.shot .cap { display: flex; align-items: center; gap: 6px; margin-top: 6px; font-size: 11px;
             color: var(--fg-5); font-variant-numeric: tabular-nums; }
.shot .cap button { margin-left: auto; border: 0; background: transparent; color: var(--bad);
                    cursor: pointer; font-size: 11px; padding: 2px 4px; }
.shot.gone { opacity: .55; }
.shot.gone .ph { height: 150px; display: flex; align-items: center; justify-content: center;
                 color: var(--fg-6); font-size: 11px; text-align: center; padding: 0 10px;
                 border: 1px dashed var(--field-rule); border-radius: 6px; }
details { margin-top: 8px; }
summary { cursor: pointer; color: var(--fg-4); }
pre { margin-top: 8px; padding: 12px; background: var(--panel); border: 1px solid var(--panel-rule);
      border-radius: 9px; overflow: auto; max-height: 340px;
      font: 11px/1.5 ui-monospace, Menlo, monospace; color: var(--fg-2); }
.events { list-style: none; font-variant-numeric: tabular-nums; }
.events li { padding: 4px 0; border-bottom: 1px solid var(--rule-2); color: var(--fg-4); font-size: 12px; }
.events b { color: var(--fg-2); font-weight: 500; }

/* the numbers */
.stats { flex: 1; overflow: auto; padding: 18px 20px 40px; }
.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; }
.tile { background: var(--panel); border: 1px solid var(--panel-rule); border-radius: 11px;
        padding: 14px 16px 12px; display: flex; flex-direction: column; }
.tile h4 { font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
           color: var(--fg-5); }
/* ⚠️ PROPORTIONAL figures, not tabular. Tabular gives every digit the width of a zero, which makes a
   standalone number like 121 look loose at display size; tabular belongs in columns that must align —
   the `.lines` and the table twins below. Same sans as everything else: a display face on a hero
   figure reads as decoration. */
.big { margin-top: 8px; font-size: 30px; font-weight: 600; line-height: 1.1; }
.tile .lines { margin-top: 10px; display: grid; grid-template-columns: 1fr max-content; gap: 3px 12px;
               font-variant-numeric: tabular-nums; }
.tile .lines span:nth-child(odd) { color: var(--fg-4); overflow: hidden; text-overflow: ellipsis;
                                   white-space: nowrap; }
.tile .lines span:nth-child(even) { color: var(--fg-2); text-align: right; }
/* ⚠️ Every tile names its SOURCE and its freshness. A chart makes every number look authoritative;
   this line is what keeps a stale one from being believed (ROADMAP §10b). */
.src { margin-top: auto; padding-top: 12px; font-size: 10px; color: var(--fg-6); overflow-wrap: anywhere; }
.dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--fg-6);
       margin-right: 6px; vertical-align: 1px; }
.dot.ok { background: var(--ok); } .dot.warn { background: var(--warn); } .dot.bad { background: var(--bad); }
.note { margin: 16px 0 0; font-size: 12px; color: var(--fg-5); max-width: 62ch; line-height: 1.55; }
/* Une ALERTE n'est pas une note plus grasse : la note explique comment lire la carte, l'alerte dit
   qu'il faut agir. Elles doivent se distinguer d'un coup d'œil, sinon elles se confondent en une
   semaine et l'alerte cesse d'en être une. */
.note.alert { color: var(--bad); font-weight: 600; border-left: 2px solid var(--bad); padding-left: 10px; }

/* --- usage: the charts -----------------------------------------------------------------------------
   Every chart here is ONE series, so there is no legend and no categorical palette: the title names
   what is plotted and a single accent carries it. Text wears text tokens; only the marks are coloured.
   Grid and axes are hairline and solid — a dashed grid reads as a threshold when it is just a grid. */
.filterbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 16px; }
.filterbar select { padding: 5px 9px; background: var(--field); border: 1px solid var(--field-rule);
                    border-radius: 7px; outline: none; }
.filterbar .hint { color: var(--fg-5); font-size: 11px; margin-left: auto; text-align: right; }

.wide2 { grid-column: span 2; }
@media (max-width: 780px) { .wide2 { grid-column: span 1; } }

/* Columns over time. The container is sized to include the x-axis band — a fixed plot height that
   excludes the labels is how a card ends up with its own tiny scrollbar. */
.cols { display: flex; align-items: flex-end; gap: 2px; height: 116px; margin-top: 14px;
        border-bottom: 1px solid var(--rule); padding-bottom: 0; }
.cols .slot { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; justify-content: flex-end;
              height: 100%; position: relative; }
/* ≤24px thick, 4px rounded at the data end, square at the baseline, growing from one baseline */
.cols .bar { width: 100%; max-width: 24px; margin: 0 auto; background: var(--accent);
             border-radius: 4px 4px 0 0; min-height: 0; }
.cols .slot.zero .bar { min-height: 1px; background: var(--rule); }
.colx { display: flex; gap: 2px; margin-top: 6px; font-size: 10px; color: var(--fg-6);
        font-variant-numeric: tabular-nums; }
/* ⚠️ NOT `overflow: hidden`. At ninety columns a slot is eleven pixels wide, and a date clipped to its
   slot came out as the single character "0" under every sixth column — a label cropped by its own
   container, which is worse than no label. Only about six slots carry text; the rest are empty, so a
   date is allowed to spill across its silent neighbours and stay centred on the column it names. */
.colx span { flex: 1 1 0; min-width: 0; text-align: center; white-space: nowrap; overflow: visible; }

/* Ranked horizontal bars: magnitude against a label. Value at the tip, outside the bar, so a short
   bar never clips its own number. */
.hbars { margin-top: 12px; display: grid; grid-template-columns: minmax(90px, max-content) 1fr max-content;
         align-items: center; gap: 6px 10px; }
.hbars .k { color: var(--fg-4); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* ⚠️ `display: block` on BOTH, and the fill is the one that matters. A <span> is inline, and width and
   height do nothing to an inline box — the track only escaped it by being a grid item (grid blockifies
   its children), so every bar rendered as an empty track with a 0x0 fill inside it. Nothing failed:
   the markup was right, the colour was right, the width was right, and the chart was blank. Measured,
   not guessed — `getBoundingClientRect()` on the fill answered 0x0 with `display: inline`. */
.hbars .track { display: block; height: 10px; background: var(--rule-2); border-radius: 4px;
                overflow: hidden; }
.hbars .fill { display: block; height: 100%; background: var(--accent); border-radius: 4px; }
.hbars .v { color: var(--fg-2); font-variant-numeric: tabular-nums; }
/* the histogram's bars are the SAME mark; only the order differs (buckets, never size) */
.hbars.hist .k { color: var(--fg-5); }

/* The table twin. Every value is reachable without hovering anything — a tooltip enhances, it never
   gates. `<details>` because the numbers are the fallback, not the headline. */
.tabletwin { margin-top: 12px; }
.tabletwin table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.tabletwin th, .tabletwin td { text-align: left; padding: 3px 8px 3px 0; border-bottom: 1px solid var(--rule-2);
                               font-weight: 400; }
.tabletwin th { color: var(--fg-5); font-size: 11px; }
.tabletwin td:last-child, .tabletwin th:last-child { text-align: right; }

/* La ligne des signalements sous l'axe des jours. ⚠️ Ce n'est pas une seconde série TRACÉE : deux
   échelles (0–3 contre 10–35) superposées sur un axe rendent le rouge invisible, et sur deux axes
   inventent une corrélation absente des données. Elle partage l'axe des jours et rien d'autre. */
.colmark { display: flex; gap: 2px; margin-top: 3px; font-size: 10px; line-height: 1.2;
           font-variant-numeric: tabular-nums; }
.colmark span { flex: 1 1 0; min-width: 0; text-align: center; overflow: visible; white-space: nowrap; }
/* Le rouge est une couleur de STATUT, donc il ne voyage jamais seul : le nombre EST son étiquette, et
   la légende de la carte dit ce qu'il compte. */
.colmark span.on { color: var(--bad); font-weight: 600; }

/* Le camembert. Les parts se séparent par un écart de 2 px dans la couleur du FOND — jamais par un
   contour, qui serait de l'encre en plus qui n'est pas de la donnée. */
.pie { display: flex; align-items: center; gap: 18px; margin-top: 14px; flex-wrap: wrap; }
.pie svg { width: 140px; height: 140px; flex: none; }
.pie .slice { stroke: var(--panel); stroke-width: 2; }
.pielegend { flex: 1; min-width: 150px; display: grid; grid-template-columns: 1fr max-content max-content;
             gap: 4px 10px; align-items: center; font-variant-numeric: tabular-nums; }
/* Le texte porte les jetons de TEXTE, jamais la couleur de la donnée : une teinte claire est illisible
   en lettres sur le fond. L'identité vient de la pastille posée à côté. */
.pielegend .key { display: flex; align-items: center; gap: 7px; color: var(--fg-4);
                  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pielegend .key i { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.pielegend .v { color: var(--fg-2); text-align: right; }
.pielegend .pc { color: var(--fg-5); text-align: right; }

/* La courbe d'une distribution. Trait fin, remplissage en voile, grille en filet plein — jamais en
   pointillés, qui se lisent comme un seuil alors que ce n'est qu'une ligne de base.
   ⚠️ Le SVG est étiré à la largeur de la carte : d'où `non-scaling-stroke` sur le trait, et tout ce qui
   doit garder sa taille (texte, sommet, axe) posé en HTML par-dessus. */
.curve { margin-top: 12px; }
.curveplot { position: relative; height: 100px; }
.curveplot svg { width: 100%; height: 100%; display: block; }
.curve .line { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round;
               stroke-linecap: round; vector-effect: non-scaling-stroke; }
/* un voile, jamais un aplat saturé : la donnée est la ligne, la surface ne fait que la poser */
.curve .fill { fill: var(--accent); opacity: .12; stroke: none; }
.curve .grid { stroke: var(--rule); stroke-width: 1; vector-effect: non-scaling-stroke; }
/* le sommet porte un anneau de la couleur du FOND, pour rester lisible là où il croise le trait */
.curve .dot { position: absolute; width: 9px; height: 9px; border-radius: 50%;
              background: var(--accent); box-shadow: 0 0 0 2px var(--panel);
              transform: translate(-50%, -50%); }
.curve .peak { position: absolute; transform: translate(-50%, -180%); font-size: 11px; font-weight: 600;
               color: var(--fg-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.curve .hit { position: absolute; top: 0; bottom: 0; }
.curvex { position: relative; height: 14px; margin-top: 4px; }
.curvex span { position: absolute; transform: translateX(-50%); font-size: 10px; color: var(--fg-6);
               font-variant-numeric: tabular-nums; white-space: nowrap; }

/* La barre de l'instant, en tête des chiffres. Des scalaires, donc des lectures — pas des graphiques :
   huit teintes pour raconter un nombre est la façon la plus courante de rater ce qu'on voulait dire. */
.livebar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px; margin-bottom: 16px;
           padding: 11px 14px; background: var(--panel); border: 1px solid var(--panel-rule);
           border-radius: 11px; font-variant-numeric: tabular-nums; }
.livebar .lit { display: flex; align-items: center; gap: 7px; color: var(--fg-2); }
.livebar .lit em { font-style: normal; font-size: 11px; letter-spacing: .04em; text-transform: uppercase;
                   color: var(--fg-5); }
.livebar .lit b { font-weight: 600; }
.livebar .head { font-weight: 600; color: var(--fg); }
.livebar .age { margin-left: auto; font-size: 11px; color: var(--fg-6); }
/* la jauge : le remplissage porte l'état, la piste est un cran plus clair du MÊME dégradé, pour que
   l'état se lise sur toute la barre et pas seulement sur sa partie pleine */
.livebar .meter { width: 64px; height: 6px; border-radius: 3px; background: var(--rule-2);
                  overflow: hidden; }
.livebar .meter span { display: block; height: 100%; background: var(--accent); border-radius: 3px; }

/* --- le back office du CLIENT ---------------------------------------------------------------------
   Même vocabulaire visuel que celui de l'éditeur, à dessein : c'est le même produit, et un client qui
   reconnaît la maison n'a pas l'impression d'être passé ailleurs. */
.atelier { font-size: 13px; color: var(--fg-2); padding: 0 12px;
           border-left: 1px solid var(--rule); margin-left: 4px; }

/* --- les comptes ------------------------------------------------------------------------------- */
/* L'état d'un abonnement se lit d'abord à sa couleur, comme celui d'un signalement : mêmes pastilles,
   même grammaire. ⚠️ Les deux jeux d'états sont DISJOINTS et le restent — un `.state.new` n'est pas un
   `.state.active`, et partager une classe parce que la couleur convient est la façon dont deux
   vocabulaires finissent par se contredire. */
.state.active { color: var(--ok); border-color: var(--ok); }
.state.trial { color: var(--accent-hi); border-color: var(--accent-hi); }
.state.suspended { color: var(--warn); border-color: var(--warn); }
.state.ended { color: var(--fg-5); }

.form { display: grid; grid-template-columns: max-content 1fr; gap: 8px 14px; align-items: center;
        max-width: 520px; }
.form label { color: var(--fg-5); }
.form input, .form select { width: 100%; padding: 6px 9px; background: var(--field);
        border: 1px solid var(--field-rule); border-radius: 6px; color: inherit; outline: none;
        font: inherit; }
.form input:focus, .form select:focus { border-color: var(--accent); }
/* ⚠️ Un champ qu'on ne peut pas changer doit AVOIR L'AIR de ne pas pouvoir l'être. Le nom court de
   l'atelier est figé après la création — il nomme les signalements et les compteurs déjà écrits — et
   sans ce style il se présentait exactement comme les autres. */
.form input:disabled { color: var(--fg-5); background: transparent; border-style: dashed;
                       cursor: not-allowed; }
.form .wide { grid-column: 1 / -1; }

/* Le mot de passe tiré, montré UNE fois. Encadré comme un avertissement parce que c'en est un : il
   n'existe nulle part ailleurs, et fermer cette page le perd. */
.pw { margin-top: 14px; padding: 12px 14px; background: var(--panel); border: 1px solid var(--warn);
      border-radius: 9px; max-width: 520px; }
.pw code { display: block; margin-top: 6px; font: 14px/1.6 ui-monospace, Menlo, monospace;
           color: var(--fg-hi); overflow-wrap: anywhere; user-select: all; }
