/* ============================================================
   Split din app.css pe layer/audienta (audit 2026-08-06 SF, ADR 0023).
   Precedenta layerelor (ultimul castiga): vendor < app < kf (tokens..utilities).
   Ordinea @layer e declarata IDENTIC in capul fiecarui fisier -
   prima declaratie stabileste ordinea, repetarea e no-op.
   ATENTIE: ordinea <link>-urilor e CONTRACT de cascada (intra-layer
   castiga ultimul incarcat): tokens, scoreboard, components, admin,
   base-layout, kf-skin; pagina juratului: tokens, judge, base-layout.
   NU adauga/reordona <link>-uri fara audit de coliziuni (ADR 0023).
   admin.css - S11 ADMIN + S11b CONTEST EDIT (/cont/{id}/edit).
   (Flash toasts au fost mutate in base-layout.css - chrome partajat.)
   ============================================================ */
@layer vendor, app, tokens, base, layout, components, utilities;

@layer app {
/* === 11. ADMIN ============================================= */

.admin-grid {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: 0.75rem; align-items: start;
}
/* Dashboardul pe taburi folosește doar c3/c12 + o1..o3 (c6/o4/o5 șterse la auditul 2026-08-06). */
.admin-section--c3  { grid-column: span 3; }
.admin-section--c12 { grid-column: span 12; }
.admin-section--o1 { order: 1; }
.admin-section--o2 { order: 2; }
.admin-section--o3 { order: 3; }
@media (max-width: 992px) {
    .admin-section--c3, .admin-section--c12 { grid-column: 1 / -1; }
}
/* FOST `overflow: hidden`. Justificarea („taie colțurile la rază") murise: remapul global
   nelayered din tokens.css pune `--radius-lg: 0` pe ORICE pagină. Ce mai făcea regula era să
   ÎNGHITĂ tăcut orice depășea secțiunea, fără bară de scroll și fără nicio cale de a ajunge la
   conținut — mecanismul din spatele raportului „pe mobil lipsesc părți de informații" (tabelul de
   dansatori pierdea coloanele 5-8, cardul de sistem își pierdea butoanele de acțiune).
   Depășirea se rezolvă acum la SURSĂ (grila de sisteme cu `min()`, tabelele cu container propriu
   de derulare); dacă mai reapare vreodată, trebuie să se VADĂ, nu să dispară.
   ⚠️ `min-width: 0` e OBLIGATORIU odată cu ștergerea: secțiunea e item de grilă în `.admin-grid`,
   iar minimul automat al unui item de grilă e min-content. `overflow` îl ținea la 0 ca efect
   secundar; fără el, un copil lat ar lăți pista și ar da scroll orizontal pe TOATĂ pagina. */
.admin-section {
    border: 2px solid var(--border-strong);
    border-radius: var(--radius-lg);
    min-width: 0;
}
.admin-section__header {
    font-family: var(--font-display);
    font-size: var(--font-xs); font-weight: 900; text-transform: uppercase;
    letter-spacing: 0.1em; color: var(--fg1);
    padding: 0.4rem 0.6rem;
    background: var(--surface-inverse); color: var(--text-on-inverse);
    border-bottom: var(--border);
}
.admin-section__hint { font-size: var(--font-xs); font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--text-on-inverse); opacity: .72; margin-left: 0.4rem; }

/* `flex-wrap` + `min-width: 0`: un nume lung (stil de dans, format, rol) împingea clusterul de
   acțiuni în afara rândului, iar pe telefon butonul de ștergere ajungea în afara ecranului. Wrapul
   e progresiv — rândul se rupe DOAR când chiar nu încape, nu la un prag fix. */
.admin-item {
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: 0.35rem;
    padding: 0.3rem 0.6rem; font-size: var(--font-md);
    border-bottom: 1px solid var(--border-hair);
    background: var(--card);
}
.admin-item > * { min-width: 0; }

/* ── Rând de CONTOPIRE (dansatori, crew-uri): etichetă · sursă → țintă · buton ──────────────────
   Înainte cele două selecturi purtau `.w-in-md`, care la ≤640px devine `width: 100%` → fiecare
   lua un rând întreg, iar săgeata rămânea singură pe al ei: cinci rânduri pentru un formular de
   trei câmpuri (raport user).
   Cheia e că perechea sursă→țintă e UN bloc: săgeata nu înseamnă nimic ruptă de câmpurile pe care
   le leagă, deci wrapul se face ÎNTRE grupuri, nu prin mijlocul lor (regula „ce trebuie să stea
   împreună nu poate wrapa independent", UI_RULES „Aranjament FLUID").
   `flex: 1 1 6rem` pe selecturi, fără `width` fix: pe desktop rândul rămâne unul singur, pe telefon
   cele două selecturi împart un rând în loc să ia câte unul. */
.merge-form { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; width: 100%; padding: 0.25rem 0; }
.merge-form__pair { display: flex; align-items: center; gap: 0.35rem; flex: 1 1 16rem; min-width: 0; }
.merge-form__pair .form-select { flex: 1 1 6rem; min-width: 0; width: auto; }
.merge-form__arrow { flex: 0 0 auto; color: var(--fg3); }
.merge-form > .btn { flex: 0 0 auto; }

/* ── Rând de FILTRE (traduceri) — aceeași idee: butonul de acțiune se leagă de câmpul pe care îl
   acționează. Butonul „Filtrează" cădea singur pe rândul 2 fiindcă `flex-wrap` umple lacom: cele
   trei câmpuri încăpeau pe primul rând și îl împingeau pe el peste margine. Grupat cu căutarea,
   rândul se rupe ca „[limbă][status] / [caută][filtrează]", nu ca „…/[buton orfan]". */
.admin-filters { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.4rem; width: 100%; }
.admin-filters label { display: flex; flex-direction: column; min-width: 0; }
.admin-filters__sel { flex: 0 1 5rem; }
.admin-filters__go { display: flex; align-items: flex-end; gap: 0.4rem; flex: 1 1 14rem; min-width: 0; }
.admin-filters__go label { flex: 1 1 auto; }
.admin-filters__go .btn { flex: 0 0 auto; }
.admin-item:last-child { border-bottom: none; }
.admin-item:hover { background: var(--paper-2); }

/* Istoric colapsat într-o secțiune admin (ex. „ELO aplicat": ultimele 3 la vedere, restul aici).
   <details> nativ — zero JS; summary-ul arată ca un rând discret de acțiune. */
.admin-collapse__summary {
    cursor: pointer; list-style-position: inside;
    padding: 0.3rem 0.6rem; font-size: var(--font-sm); color: var(--text-muted);
    border-bottom: 1px solid var(--border-hair);
}
.admin-collapse__summary:hover { color: var(--text); background: var(--paper-2); }
.admin-collapse[open] > .admin-collapse__summary { border-bottom-style: dashed; }


.admin-sys-badge { font-size: var(--font-2xs); font-weight: 700; padding: 1px 6px; border-radius: var(--radius-sm); }
.admin-sys-badge--ok   { background: var(--success-soft); color: var(--success); }
.admin-sys-badge--warn { background: var(--warning-soft); color: var(--warning); }

.admin-skill-tag { display: inline-flex; align-items: center; gap: 3px; font-size: var(--font-xs); background: var(--paper-2); border: 1px solid var(--border-hair); border-radius: var(--radius-sm); padding: 1px 5px; color: var(--fg2); }
.admin-skill-tag__max { color: var(--fg4); font-family: var(--font-mono); }
.admin-skill-tag__del { color: var(--danger); cursor: pointer; background: none; border: none; padding: 0; line-height: 1; font-size: var(--font-xs); }
.admin-skill-tag__del:hover { color: var(--primary-strong); }
.admin-skill-tag--anchored { border-color: var(--success); }
.admin-skill-tag__anchor { color: var(--fg4); cursor: pointer; background: none; border: none; padding: 0; line-height: 1; font-size: var(--font-xs); }
.admin-skill-tag__anchor:hover { color: var(--primary-strong); }
.admin-skill-tag--anchored .admin-skill-tag__anchor { color: var(--success); }

/* Barem ancorat — panou editare per skill */
.anchor-panel { width: 100%; }
.anchor-form {
    width: 100%; margin-top: 0.2rem;
    border: 1px solid var(--border-hair); border-left: 3px solid var(--primary);
    border-radius: var(--radius-sm); background: var(--paper-2); padding: 0.5rem 0.6rem;
}
.anchor-form__title {
    font-family: var(--font-display);
    font-size: var(--font-xs); font-weight: 900; text-transform: uppercase;
    letter-spacing: .08em; color: var(--fg1);
}
.anchor-form__max { color: var(--fg4); font-family: var(--font-mono); }
.anchor-form__hint { font-size: var(--font-xs); color: var(--fg3); margin: 0.15rem 0 0.45rem; }
/* Rândul de ancoră = FLUID, nu fix: cele două câmpuri stau unul lângă altul cât e loc și pică pe
   rânduri singure sub ~14rem, fără niciun prag. `flex: 1 1 5rem` pe etichetă, NU `width: auto`:
   `flex-shrink: 0` (valoarea de dinainte) ar fi supraviețuit unei simple schimbări de `width`, iar
   `width: auto` pe un `<input>` cade pe atributul `size` (~20ch) — adică ar fi ieșit mai LAT. */
.anchor-row { display: flex; align-items: center; flex-wrap: wrap; gap: 0.35rem; margin-bottom: 0.25rem; }
.anchor-row__score { flex-shrink: 0; width: 1.3rem; text-align: center; font-family: var(--font-mono); font-weight: 700; font-size: var(--font-sm); color: var(--fg2); }
.anchor-row__label { flex: 1 1 5rem; width: auto; min-width: 0; }
.anchor-row__text { flex: 2 1 9rem; min-width: 0; }
.anchor-row--penalty .anchor-row__score { color: var(--danger); }

.admin-table { width: 100%; font-size: var(--font-md); border-collapse: collapse; }
.admin-table th {
    font-family: var(--font-display);
    font-size: var(--font-xs); font-weight: 900; text-transform: uppercase;
    letter-spacing: .1em; color: var(--text-on-inverse);
    padding: 0.3rem 0.6rem; border-bottom: 2px solid var(--border-strong); background: var(--surface-inverse);
}
.admin-table td { padding: 0.28rem 0.6rem; border-bottom: 1px solid var(--border-hair); vertical-align: middle; background: var(--card); }
.admin-table tr:last-child td { border-bottom: none; }
.admin-table tr:hover td { background: var(--paper-2); }
.admin-table .col-actions { width: 1%; white-space: nowrap; text-align: right; }

/* ── Tabelele dense de admin (dansatori, utilizatori) pe ecran îngust: SE STRÂNG ÎNTÂI, se trag
   lateral doar pentru rest (decizie user 2026-08-17). Card-reflow — rândul devine card cu etichete
   — a fost RESPINS explicit: adminul compară valori pe coloană când repară date în timpul unui
   eveniment, iar 30 de carduri a 8 câmpuri sunt de patru ori mai lungi de derulat.

   `@media` e legitim aici: e comutatorul de DENSITATE, nu o prăbușire de aranjament.

   ⚠️ `overflow-wrap: anywhere`, NU `word-break: break-word`: numai `anywhere` scade contribuția de
   MIN-CONTENT a celulei, adică singura care face tabelul mai îngust (`break-word` rupe textul la
   randare, dar lățimea minimă rămâne aceeași). Se pune pe `td`, nu pe `th`: un antet ar fi rupt în
   „Nume sce/nă".
   ⚠️ Podeaua e OBLIGATORIE alături: `anywhere` coboară min-content până la o literă, deci cu
   `width: 100%` pe layout automat tabelul ar încăpea MEREU și n-ar mai trage niciodată lateral —
   ar pulveriza coloanele la ~3 caractere. Podeaua stă pe COLOANĂ (`th`), nu pe tabel: regula reală
   e „nicio coloană sub ~3.5rem, altfel devine ilizibilă", iar totalul iese singur din numărul de
   coloane — utilizatori (5) încape la 360px, dansatori (8) trage puțin. O cifră pe tabel ar fi
   fost aceeași podea pentru amândouă, deci scroll inutil la cel cu 5 coloane.
   ⚠️ Modificator, nu `.admin-table` gol: `.trad-table` (traduceri) e `table-layout: fixed` cu
   coloane procentuale, deci are nevoie de alt tratament — vezi blocul ei de mai jos. ── */
@media (max-width: 640px) {
    .admin-table--drag { font-size: var(--font-sm); }
    .admin-table--drag th { min-width: 3.5rem; font-size: var(--font-2xs); letter-spacing: .04em; padding: .25rem .3rem; }
    .admin-table--drag td { padding: .25rem .3rem; overflow-wrap: anywhere; }
    .admin-table--drag .badge { font-size: var(--font-2xs); }
    /* Coloana de acțiuni rămâne `nowrap`: lăsate să se rupă, cele două butoane de 44px s-ar stivui
       și ar dubla înălțimea FIECĂRUI rând. Podeaua ei sunt oricum două ținte tactile alăturate. */
    .admin-table--drag .col-actions { padding-inline: .25rem; }
}

/* Grid traduceri (i18n Faza 2) — coloane fixe + textarea confortabil pt conținut */
.trad-table { table-layout: fixed; }
.trad-table td { vertical-align: top; }
.trad-col-ent { width: 20%; }
.trad-col-field { width: 13%; }
.trad-col-src { width: 26%; }
.trad-col-status { width: 6rem; }
.trad-table td .form-control { min-height: 2.6rem; resize: vertical; }
.trad-table td, .trad-table th { word-break: break-word; }
/* Antetul se micșorează fluid: la lățimi mici „Traducere (EN)" și „Status" mâncau două rânduri
   fiecare și împingeau butonul de salvare. Capetele scării sunt tokeni (regula: `clamp()` ascunde
   literalele de gate — treptele stau tot în tokeni), fluid doar la mijloc. */
.trad-table th { font-size: clamp(var(--font-3xs), 1.6vw, var(--font-xs)); }

/* ── Traduceri pe telefon: aici NU merge „se strânge cât poate", fiindcă celula de traducere e o
   SUPRAFAȚĂ DE EDITARE, nu o valoare de citit. Cu `table-layout: fixed` și coloana de traducere la
   41%, la 360px rămâneau ~97px pentru un textarea + butonul lui — adică imposibil de folosit
   (raport user). Deci: coloanele se rebalansează în favoarea traducerii ȘI tabelul primește o
   podea, ca restul să se ia prin tragere laterală în loc să sufoce câmpul.
   Sursa rămâne citibilă — se poate derula la ea; traducerea trebuie SCRISĂ, ea are prioritate. ── */
@media (max-width: 640px) {
    .trad-table { min-width: 44rem; }
    .trad-col-ent { width: 16%; }
    .trad-col-field { width: 10%; }
    .trad-col-src { width: 20%; }
    .trad-col-status { width: 4.5rem; }
}

/* Sisteme de jurizare — grilă carduri (≈3 coloane după lățime).
   ⚠️ `min(100%, …)` e plasa anti-depășire, idiomul propriu al proiectului (base-layout.css,
   `.arch-list`). Fostul `minmax(330px, 1fr)` cerea 330px dintr-o cutie de ~259px la 360px (după
   marginile lui .panel-strip + .panel-acc__body), iar restul era înghițit de `overflow: hidden`
   de pe .admin-section — ce dispărea era exact clusterul de acțiuni din dreapta cardului
   (pauză / reactivare / ștergere). */
.judging-grid {
    --judging-col-min: 330px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--judging-col-min)), 1fr));
    gap: 0.5rem; padding: clamp(.35rem, 1.5vw, .5rem) clamp(.35rem, 2vw, .6rem);
    align-items: start;
}
.judging-card {
    border: 1px solid var(--border-hair); border-radius: var(--radius-sm);
    background: var(--card); padding: 0.4rem 0.5rem;
    display: flex; flex-direction: column; gap: 0.4rem;
    min-width: 0;   /* item de grilă: minimul automat e min-content → un nume lung ar lăți pista */
}
.judging-card strong { overflow-wrap: anywhere; }
/* Antetul cardului e `justify-content: space-between` cu două clustere; fără `min-width: 0` cel din
   stânga (nume + insigne) nu poate coborî sub conținutul lui, deci împinge acțiunile afară în loc
   să se rupă. `flex-wrap` pe antet ca ultimă plasă: la nume foarte lungi acțiunile trec dedesubt,
   nu în afara ecranului. */
.judging-card > .d-flex { flex-wrap: wrap; }
.judging-card > .d-flex > * { min-width: 0; }
/* Formularele mici din card (adaugă skill / atașează panel): lățimile utilitare CEDEAZĂ lățimii
   cardului — același precedent ca `.jgrid .input-w-*` din components.css. `flex-wrap` prin CSS,
   nu prin clasă în Twig: formularele care nu sunt `d-flex` (toggle, ștergere) sunt `display: block`,
   deci regula e inertă pe ele. `.input-w-score-sm` rămâne îngust — e câmpul de scor maxim, n-are
   ce face cu lățimea numelui de criteriu. */
.judging-card form { flex-wrap: wrap; }
.judging-card .input-w-skill { width: auto !important; min-width: 0; flex: 1 1 5.5rem; }
.judging-card .input-w-score-sm { flex: 0 0 3.2rem; }
.judging-card .form-select { min-width: 0; }
.judging-card:hover { background: var(--paper-2); }
/* Sisteme inactive — VIZIBILE, doar marcate. Regula veche era `display:none` + o clasa de
   dezvaluire pusa de un toggle cu `onclick` inline; toggle-ul a fost scos (regula: zero handlere
   inline), dar ascunderea a ramas -> un sistem dezactivat disparea din admin si NU mai putea fi
   reactivat, desi butonul lui exista in markup. Marcajul e suficient: cardul poarta deja badge-ul
   „inactiv" si butonul de reactivare. */
.judging-card--inactive { opacity: 0.55; border-style: dashed; }
.judging-card--inactive:hover { opacity: 1; }

/* Panele specialiste — grup de sisteme cu 1 skill, un jurat pe rol (OUR-3/OUR-5) */
/* Marginile + paddingul sunt FLUIDE: la 360px, lanțul .panel-strip → .panel-acc__body → .judging-grid
   mânca ~80px din lățime înainte ca vreun card să fie desenat. Pe desktop rămân valorile de azi. */
.panel-strip { border: 1px dashed var(--border-hair); border-radius: var(--radius-sm); padding: clamp(.3rem, 1.5vw, .45rem) clamp(.35rem, 2vw, .6rem); margin: 0 clamp(.3rem, 2vw, .6rem) 0.6rem; display: flex; flex-direction: column; gap: 0.45rem; }
.panel-strip__head { font-size: var(--font-sm); font-weight: 700; display: flex; align-items: center; flex-wrap: wrap; gap: 0.4rem; }
/* Singurul supraviețuitor al vechiului grid de panel-carduri (admin folosește .panel-acc):
   mesajul „fără roluri" din corpul acordeonului. Restul blocului = șters la auditul 2026-08-06. */
.panel-card__empty { font-size: var(--font-xs); }
.panel-strip__create { max-width: 360px; }

/* Copierea line-up-ului dintr-o categorie soră — ACELAȘI bloc pentru jurați (_copy_judges) și pentru
   DJ/host (_copy_staff); diferă doar ce se randează în rânduri. Zero JS: `<details>` + un formular
   gata randat per sursă. Acordeon pe surse prin `<details name>`, ca la .panel-acc — deschizi o
   sursă, se închide cealaltă. */
.copy-picker { margin-top: .35rem; }
.copy-picker > summary,
.copy-picker__src > summary {
    display: flex; align-items: center; gap: .3rem;
    cursor: pointer; user-select: none; list-style: none;
    font-size: var(--font-xs); font-weight: 700; color: var(--fg3);
}
.copy-picker > summary::-webkit-details-marker,
.copy-picker__src > summary::-webkit-details-marker { display: none; }
.copy-picker > summary:hover, .copy-picker__src > summary:hover { color: var(--fg1); }
.copy-picker__list { padding: .35rem 0 0 .5rem; display: flex; flex-direction: column; gap: .25rem; }
.copy-picker__src { border-left: 2px solid var(--border-hair); padding-left: .5rem; }
.copy-picker__count { color: var(--fg4); font-weight: 400; }
.copy-picker__form { display: flex; flex-direction: column; gap: .25rem; align-items: flex-start; padding: .35rem 0; }
.copy-picker__row { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.copy-picker__row--here { opacity: .55; }
.copy-picker__pick { display: flex; align-items: center; gap: .3rem; font-size: var(--font-xs); cursor: pointer; margin: 0; }
.copy-picker__note { font-size: var(--font-2xs); color: var(--fg4); }

/* Acordeon panel (native <details name>) — deschide un panel îl închide pe celălalt, zero JS */
/* `min-width: 0` în locul lui `overflow: hidden` — aceeași motivație ca la `.admin-section`:
   acordeonul e tot un container care înghițea tăcut cardurile prea late în loc să le lase văzute. */
.panel-acc { border: 1px solid var(--border-hair); border-radius: var(--radius-sm); background: var(--card); min-width: 0; }
.panel-acc + .panel-acc { margin-top: 0.35rem; }
.panel-acc--inactive { opacity: 0.6; }
.panel-acc > summary {
    display: flex; align-items: center; flex-wrap: wrap; gap: 0.4rem;
    padding: 0.45rem 0.6rem; cursor: pointer; font-weight: 700; font-size: var(--font-sm);
    list-style: none; user-select: none;
}
.panel-acc > summary::-webkit-details-marker { display: none; }
.panel-acc > summary::after { content: "\F282"; font-family: "bootstrap-icons"; margin-left: auto; font-size: 0.8em; transition: transform 0.15s ease; color: var(--fg4); }
.panel-acc[open] > summary::after { transform: rotate(180deg); }
.panel-acc > summary:hover { background: var(--paper-2); }
.panel-acc__name { font-weight: 900; }
.panel-acc__body { padding: clamp(.35rem, 1.5vw, .5rem) clamp(.35rem, 2vw, .6rem) 0.6rem; border-top: 1px solid var(--border-hair); display: flex; flex-direction: column; gap: 0.5rem; }
.panel-acc__actions { display: flex; gap: 0.3rem; flex-wrap: wrap; }
.panel-acc__actions form { display: inline; }
@media (prefers-reduced-motion: reduce) { .panel-acc > summary::after { transition: none; } }

/* Marcaj panel pe cardul sistemului */
.sys-panel-tag { display: inline-flex; align-items: center; gap: 0.2rem; font-size: var(--font-xs); padding: 1px 7px; border-radius: var(--radius-sm); background: var(--paper-2); border: 1px solid var(--border-hair); align-self: flex-start; }
.sys-panel-tag__form { display: inline; }
.sys-panel-tag__del { border: 0; background: transparent; color: var(--danger); padding: 0 0 0 2px; line-height: 1; cursor: pointer; }
/* Accent culoare per panel — leagă cardul panelului de sistemele membre din grid */
.jacc-0 { border-left: 3px solid #e8590c; }
.jacc-1 { border-left: 3px solid #2f9e44; }
.jacc-2 { border-left: 3px solid #1971c2; }
.jacc-3 { border-left: 3px solid #f08c00; }
.jacc-4 { border-left: 3px solid #9c36b5; }
.jacc-5 { border-left: 3px solid #0c8599; }

/* Singurul supraviețuitor al vechiului grid de carduri Dansatori (tabul e acum .admin-table):
   crew-ul de lângă numele dansatorului. Restul blocului = șters la auditul 2026-08-06. */
.dancer-card__crew { color: var(--fg3); font-size: var(--font-xs); margin-left: 0.3rem; }


/* === 11b. CONTEST EDIT — /cont/{id}/edit ============== */

/* Muchia stângă = semnătura de STIL (aceeași ca .style-pill/.cat-strip__item): hue-ul vine din
   markup (`--style-h`, filtrul style_hue), S/L din lista de consumatori din kf-skin. Diferențiază
   categoriile între ele și de panourile .form-panel din jur (nivel 1 = ramă uniformă). */
.ecat {
    border: 2px solid var(--border-strong);
    border-left: 3px solid hsl(var(--style-h, 0) var(--style-s, 70%) var(--style-l-accent, 45%));
    border-radius: var(--radius-sm); background: var(--card); margin-bottom: .5rem;
}
/* Headerul poartă TENTA stilului (aceeași scară ca .style-pill: --style-l-bg 90% light / 22% dark,
   din listele de consumatori kf-skin) — fostul var(--paper-2) diferea de fundal cu un micro-pas și
   zonele nu se distingeau (raport user 2026-08-16). Cerneala titlului vine din aceeași scară. */
.ecat__hdr {
    display: flex; align-items: center; justify-content: space-between; gap: 6px;
    padding: .3rem .6rem;
    background: hsl(var(--style-h, 0) var(--style-s, 70%) var(--style-l-bg, 90%));
    border-bottom: 1px solid var(--border-hair);
}
.ecat__title { font-family: var(--font-display); font-size: var(--font-md); font-weight: 900; text-transform: uppercase; letter-spacing: .03em; color: hsl(var(--style-h, 0) var(--style-s, 70%) var(--style-l-fg, 30%)); }
.ecat__meta { font-size: var(--font-xs); color: hsl(var(--style-h, 0) var(--style-s, 70%) var(--style-l-fg, 30%)); opacity: .75; font-weight: 400; text-transform: none; letter-spacing: 0; }
.ecat__body { padding: .5rem .65rem; }
.rounds-form { display: flex; align-items: center; flex-wrap: wrap; gap: .4rem; }
.config-pill--lock { opacity: .6; border-style: dashed; }
.inp-poster { max-width: 160px; }
.edit-locked-note {
    font-size: var(--font-xs); color: var(--fg3);
    display: inline-flex; align-items: center; gap: 4px;
}

/* Câmp modificat dar nesalvat — semnal vizual (form-dirty.js îl pune/scoate). Bară accent la stânga.
   !important: bate border-color-ul cu stare al Bootstrapului (:focus/.is-invalid pe .form-control),
   altfel semnalul dispare exact pe câmpul în care omul tocmai scrie. */
.is-dirty {
    border-color: var(--accent) !important;
    box-shadow: inset 3px 0 0 0 var(--accent);
}

/* Bară unică de salvare, lipită jos — un singur „Salvează modificările" pentru tot ce e configurabil. */
.edit-savebar {
    position: sticky; bottom: 0; z-index: 10;
    display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
    margin-top: .75rem; padding: .55rem .7rem;
    background: var(--surface);
    border: 2px solid var(--border-strong); border-radius: var(--radius-sm);
    box-shadow: var(--shadow-hard-sm);
    transition: border-color .15s ease, background-color .15s ease;
}
/* Stare „nesalvat" — semnal vizual în pagină (fără popup), accent pe bară + status. */
.edit-savebar--dirty { border-color: var(--accent); background: var(--bg-elevated); }
.savebar-status {
    font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
    letter-spacing: .06em; font-size: var(--font-xs); color: var(--accent);
}





} /* END @layer app */
