/* ============================================================
   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).
   components.css - S3 TABLES, S4 BADGES, S5/5b PILLS/TABS, S6 CHIPS,
   S7 CARDS+cont, S9 FORMS, S12/12b/12c PUBLIC, S14 RANKING, S15 AUTH/ERROR,
   S18 RESULTS.
   ============================================================ */
@layer vendor, app, tokens, base, layout, components, utilities;

@layer app {
/* === 3. TABLES ============================================= */

/* Tabel compact */


/* Coloane fixe frecvente */


.col-actions { width: 100px; text-align: right; white-space: nowrap; }

/* Stat column */

.stat-value { font-weight: 700; color: var(--fg1); }


/* Results table */


/* Section header */


/* === 4. BADGES & STATUS ==================================== */

/* Badge status concurs */
.badge-status {
    font-family: var(--font-display);
    font-size: var(--font-xs);
    font-weight: 900;
    padding: var(--pad-badge);
    border-radius: var(--radius-md);
    display: inline-block;
    white-space: nowrap;
    line-height: 1.4;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
.badge-status--draft    { background: var(--status-draft-bg);   color: var(--status-draft-fg); }
.badge-status--open     { background: var(--status-open-bg);    color: var(--status-open-fg); }
.badge-status--closed   { background: var(--status-closed-bg);  color: var(--status-closed-fg); }
.badge-status--active   { background: var(--status-active-bg);  color: var(--status-active-fg); }
.badge-status--done     { background: var(--status-done-bg);    color: var(--status-done-fg); }

/* Badge status battle/bout */

.badge-battle--pending   { background: var(--battle-pending-bg);   color: var(--battle-pending-fg); }
.badge-battle--progress  { background: var(--battle-progress-bg);  color: var(--battle-progress-fg); }
.badge-battle--completed { background: var(--battle-completed-bg); color: var(--battle-completed-fg); }

/* Badge faza bracket */


/* Badge categorie */
.badge-category {
    font-size: var(--font-xs);
    font-weight: 700;
    padding: var(--pad-badge);
    border-radius: var(--radius-md);
    background: var(--surface-inverse);
    color: var(--text-on-inverse);
    text-decoration: none;
    display: inline-block;
    transition: background 0.1s;
}
.badge-category:hover { background: var(--primary); color: var(--on-primary); }

/* Badge metoda calificare */


/* Valori semantice */


/* === 5. PILLS & FILTERS ==================================== */

.filter-pill {
    font-size: var(--font-sm);
    padding: var(--pad-pill);
    border-radius: var(--radius-sm);
    border: 1.5px solid var(--border-control);
    background: var(--card);
    color: var(--fg2);
    cursor: pointer;
    transition: background 0.1s, color 0.1s;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    line-height: 1.3;
}
.filter-pill:hover  { background: var(--volt); color: var(--volt-ink); border-color: var(--volt-ink); }
.filter-pill.active { background: var(--surface-inverse); color: var(--text-on-inverse); }

/* Rândul tab-uri + filtru (/concursuri): nav-ul și pill-ul „Concursurile mele" pe aceeași linie,
   pill-ul aliniat dreapta, la aceeași înălțime vizuală cu tab-urile. */
.tabs-row { display: flex; align-items: center; justify-content: space-between; gap: .5rem; flex-wrap: wrap; margin-bottom: 1rem; }
.tabs-row .folder-tabs { margin-bottom: 0; }
.tabs-row .filter-pill { padding: .4rem .85rem; font-size: var(--font-xs); text-transform: uppercase; letter-spacing: .06em; font-weight: 700; }


/* === 5b. FOLDER TABS (segmented page tabs, lipite de conținut) === */
.folder-tabs {
    display: flex; flex-wrap: wrap; gap: .25rem; align-items: flex-end;
    border-bottom: 2px solid var(--border-strong);
    margin-bottom: 1rem;
}
.folder-tab {
    display: inline-flex; align-items: center; gap: 6px;
    padding: .4rem .85rem; margin-bottom: -2px;        /* acoperă rigla containerului */
    background: transparent; border: 2px solid transparent; border-bottom: none;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    font-family: var(--font-display); font-weight: 900; text-transform: uppercase;
    letter-spacing: .05em; font-size: var(--font-xs); line-height: 1.3;
    color: var(--text-muted); text-decoration: none; cursor: pointer;
    transition: background .1s, color .1s;
}
.folder-tab:hover  { background: var(--volt); color: var(--volt-ink); }
.folder-tab.active { background: var(--surface); border-color: var(--border-strong); color: var(--text); }


/* === 6. CHIPS ============================================== */

/* Chip competitor inline */


/* Chip judecator */
.judge-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: var(--font-sm);
    padding: var(--pad-chip);
    border: 1.5px solid var(--border-strong);
    border-radius: var(--radius-md);
    background: var(--card);
    color: var(--fg1);
    text-decoration: none;
    transition: background 0.1s, color 0.1s;
    line-height: 1.4;
}
.judge-chip:hover { background: var(--volt); color: var(--volt-ink); border-color: var(--volt-ink); }

.judge-chip .chip-system  { font-size: var(--font-xs); color: var(--fg3); background: var(--paper-2); padding: 0 3px; border-radius: var(--radius-sm); }
.judge-chip__del-form { display: inline; line-height: 0; }
.judge-chip__del { border: 0; background: transparent; color: var(--danger); padding: 0; line-height: 1; cursor: pointer; font-size: var(--font-xs); }
.judge-chip:hover .judge-chip__del { color: var(--volt-ink); }
/* Jurat marcat pentru eliminare (staged) — se aplică la „Salvează modificările" */


/* Hint jurați per categorie (panel: X/N roluri · mai alege …) */
.exhint { font-size: var(--font-xs); margin-bottom: 2px; min-height: 1em; }
.exhint--ok   { color: var(--success); }
.exhint--warn { color: var(--warning); }
.exhint--err  { color: var(--danger); font-weight: 600; }


/* === 7. CARDS — Hub organizator ============================= */

.hub-card {
    border: 2px solid var(--border-strong);
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: var(--card);
    transition: box-shadow .1s;
}
.hub-card:hover { box-shadow: var(--shadow-hard); }

/* Strip status colorat (top) */
.hub-strip {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: .28rem .75rem;
    font-family: var(--font-display);
    font-size: var(--font-xs);
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: .1em;
    border-bottom: 2px solid var(--border-strong);
}
.hub-strip--open   { background: var(--status-open-bg);   color: var(--status-open-fg); }
.hub-strip--closed { background: var(--status-closed-bg); color: var(--status-closed-fg); }
.hub-strip--active { background: var(--status-active-bg); color: var(--status-active-fg); }

/* Descriere concurs (sub hero, în metarow) */


/* Rândul de arhivă (.arch-*) trăiește ACUM într-un singur bloc, în secțiunea „Arhivă publică"
   de mai jos — căutați `--- Arhivă publică (/arhiva) ---`. Clasele vechi `hub-head`/`hub-thumb`
   au fost redenumite acolo (2026-07-27); `hub-card`/`hub-strip` de pe home sunt alt component. */

/* Acțiuni de stare pe rândul de categorie — următorul pas explicit */
.cat-actions { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .35rem; }
.cat-actions form { display: inline; margin: 0; }

/* === Cont organizator (profil) === */
.acct-card {
    display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem;
    padding: .6rem .75rem; border: 2px solid var(--border-strong);
    border-radius: var(--radius-lg); background: var(--surface);
}
.acct-card__id { display: flex; align-items: center; gap: .55rem; flex: 1 1 auto; min-width: 0; }
.acct-card__ico { font-size: var(--font-4xl); color: var(--text-muted); }
.acct-card__name { font-family: var(--font-display); font-weight: 900; text-transform: uppercase; letter-spacing: .02em; font-size: var(--font-base); color: var(--text); }
.acct-card__email { font-size: var(--font-sm); color: var(--text-secondary); }
.acct-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: .6rem; padding-top: .6rem; margin-top: .5rem; border-top: 1px solid var(--border-hair); }
.acct-form__row { display: flex; flex-direction: column; gap: .15rem; flex: 1 1 220px; }
.acct-form__lbl { font-size: var(--font-xs); text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); font-weight: 700; }
.acct-form__actions { flex: 0 0 auto; }



/* === 9. FORMS ============================================== */

.form-label-xs {
    font-family: var(--font-display);
    font-size: var(--font-xs);
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fg3);
    margin-bottom: 2px;
    display: block;
}
.form-control-xs { height: 26px; font-size: var(--font-sm); padding: 0.15rem 0.4rem; }
.form-select-xs  { height: 26px; font-size: var(--font-sm); padding: 0.1rem 1.5rem 0.1rem 0.4rem; }
.form-row-compact {
    display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0.65rem 0.55rem;
}
.judge-inline-row,
.staff-inline-row { display: flex; gap: 0.4rem 0.5rem; align-items: flex-end; flex-wrap: wrap; }

/* === TOP-ALIGNED label — SSOT label câmpuri creare/editare concurs ==========================
   Cercetare UX: label deasupra inputului = cel mai scanabil pt formulare dense (vezi plan/Surse).
   Markup: control ÎNTÂI, <label> DUPĂ → `flex-direction: column-reverse` afișează label-ul DEASUPRA
   fără reordonare DOM (dropdown autocomplete rămâne absolut → neafectat). Font Archivo 600, text
   ÎNTREG (fără trunchiere). Padding sus/jos pe control = lizibilitate (anti-aglomerare). */
.form-field { display: flex; flex-direction: column-reverse; gap: 3px; min-width: 0; align-items: flex-start; }
.form-field > label {
    margin: 0; padding: 0;
    font-family: var(--font-sans); font-weight: 600; font-size: var(--font-sm);
    color: var(--text-secondary); line-height: 1.15; white-space: nowrap;
}
.form-field > .form-control,
.form-field > .form-select,
.form-field > textarea.form-control {
    width: 100%; height: auto; min-height: 1.95rem;
    padding: 0.32rem 0.55rem; font-size: var(--font-md); line-height: 1.3;
}
.form-field > textarea.form-control { min-height: 3rem; }
/* Câmp FIXAT (disabled, ex. structuralele la edit după creare) = clar ne-editabil, în temă:
   chenar dashed stins + text muted + lacăt pe label (pattern consistent cu .config-pill--lock). */
.form-field > .form-control:disabled,
.form-field > .form-select:disabled {
    background-color: transparent;
    border-style: dashed; border-color: var(--border-hair);
    color: var(--text-muted); cursor: not-allowed;
    opacity: 1;  /* anulează estomparea Bootstrap pe select — dashed+muted e deja semnalul */
}
.form-field:has(> :disabled) > label { color: var(--text-faint); }
.form-field:has(> :disabled) > label::after {
    font-family: 'bootstrap-icons'; content: "\f47a";  /* bi-lock-fill */
    font-size: .85em; margin-left: .25rem; opacity: .7;
}
/* stepper „Runde/fază": label (cod fază) deasupra, input îngust centrat */
/* Baze de creștere pentru câmpurile dintr-un `.form-row-compact`: se împachetează progresiv, unul
   câte unul, în loc să se prăbușească toate la un breakpoint. `8.5rem` = minimul sub care un
   `<input type="date">` nativ își taie propriul text (`zz.ll.aaaa`). */
.fld-grow2 { flex: 2 1 10rem; }
.fld-date  { flex: 1 1 8.5rem; }
/* Grupul celor două date (Data + Până la) = sub-flex care pică ÎMPREUNĂ sub locație când rândul
   se îngustează (col-lg-4 la creare) — intervalul e o singură informație, „Până la" nu rămâne
   orfan pe rândul lui. Foarte îngust → datele se rup și între ele (wrap interior, progresiv). */
.fld-dates { display: flex; flex-wrap: wrap; gap: 0.65rem 0.55rem; flex: 2 1 17.5rem; min-width: 0; }
.form-field--num { width: 3.4rem; }
.form-field--num > .form-control { width: 100%; text-align: center; }
/* Câmpurile de TIMP („Rundă (s)" / „Smoke (min)"): etichetele-s mai late decât cutia de 3.4rem a
   stepper-elor de fază și se revărsau peste câmpul vecin (labelul e nowrap) — variantă cu loc. */
.form-field--time { width: 5.2rem; }

/* Premiul categoriei (B8 revizuit; 2026-08-10): DOAR locul 1, DOAR pe liniile de listă din
   /concursuri — 🏆 (auriul medaliilor) + textul liber. */
/* Mono: e o CIFRĂ (suma premiului), deci rolul de numerale — și era una din cele două insigne rămase
   pe familia sans în rândul de categorie. */
.prize-line { display: inline-flex; align-items: center; gap: .25rem; font-family: var(--font-mono); font-size: var(--font-xs); font-weight: 700; letter-spacing: .04em; color: var(--fg2); }
.prize-line .bi-trophy-fill { color: var(--rank-gold-ink); }

/* Anvergura concursului — DOUĂ zone cu titlu („Intră / Nu intră în clasament"): apartenența la
   ELO se vede din structură, nu din text în <option>. Pill = radio ascuns accesibil (:checked /
   :focus-visible pe input) + label derivat din rețeta .filter-pill.
   LIZIBILITATE (feedback 2026-08-10): chenarul NU e static pe zona de clasament (imita starea
   „selectat") — chenarul urmează SELECȚIA REALĂ (:has(:checked)), iar pastila aleasă poartă și
   BIFĂ (se citește fără percepția culorii). Zona de clasament se distinge doar prin header
   (trofeu + primary). */
.tier-pick { border: 0; padding: 0; margin: 0; min-width: 0; }
.tier-pick__legend {
    float: none; width: auto; margin: 0 0 3px; padding: 0;
    font-family: var(--font-sans); font-weight: 600; font-size: var(--font-sm);
    color: var(--text-secondary); line-height: 1.15;
}
.tier-pick__zones { display: flex; flex-wrap: wrap; gap: .5rem; }
.tier-pick__zone {
    flex: 1 1 12rem; min-width: 0; padding: .45rem .55rem;
    border: 1px solid var(--border-hair); border-radius: var(--radius-sm); background: var(--paper-2);
}
/* Chenarul = unde E selecția (nu unde am vrea să fie): zona cu radio-ul bifat. */
.tier-pick__zone:has(.tier-pick__input:checked) { border-color: var(--primary); background: var(--surface-2); }
.tier-pick__head {
    font-size: var(--font-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
    color: var(--fg3); margin-bottom: .35rem;
}
.tier-pick__zone--rank .tier-pick__head { color: var(--primary); }
.tier-pick__opts { display: flex; flex-wrap: wrap; gap: .35rem; }
.tier-pick__opt {
    display: inline-flex; align-items: center; gap: .3rem;
    font-size: var(--font-sm); font-weight: 600; line-height: 1.3;
    padding: .3rem .6rem; border-radius: var(--radius-sm);
    border: 1.5px solid var(--border-control); background: var(--card); color: var(--fg2);
    cursor: pointer; margin: 0;
}
.tier-pick__opt .tier-pick__check { display: none; }
.tier-pick__opt:hover { background: var(--volt); color: var(--volt-ink); border-color: var(--volt-ink); }
.tier-pick__input:checked + .tier-pick__opt { background: var(--surface-inverse); color: var(--text-on-inverse); border-color: var(--surface-inverse); }
.tier-pick__input:checked + .tier-pick__opt .tier-pick__check { display: inline; }
.tier-pick__input:focus-visible + .tier-pick__opt { outline: 2px solid var(--primary); outline-offset: 2px; }
.tier-pick__input:disabled + .tier-pick__opt { opacity: .55; cursor: not-allowed; }
/* în rândurile jurat/staff: câmpul = coloană proprie (label sus, control jos) */
.judge-inline-row .form-field,
.staff-inline-row .form-field { min-width: 0; }

/* Panou formular pe temă (kinetic sharp light×brutalist) — înlocuiește card+bg-dark Bootstrap
   pe creare/editare concurs. Cap deschis cu hairline tare + label display uppercase. */
.form-panel {
    border: 2px solid var(--border-strong);
    border-radius: var(--radius-lg);
    background: var(--surface);
    overflow: hidden;
    display: flex;
    flex-direction: column;
}
.form-panel__head {
    background: var(--surface-2);
    color: var(--text);
    border-bottom: 2px solid var(--border-strong);
    font-family: var(--font-display);
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: var(--font-sm);
    padding: 0.5rem 0.75rem;
    display: flex;
    align-items: center;
}
.form-panel__head--action { justify-content: space-between; gap: 0.5rem; }
.form-panel__body { padding: 0.75rem; flex: 1 1 auto; }

/* Tabel PhaseRoundConfig */


/* Formular QualificationConfig */



/* === 12. PUBLIC — /concursuri ============================== */

/* Pagina LIVE = proiector fullscreen, fără chrome. Clasă pe <body> (NU body{} inline — evită
   bug-ul de fundal scurs prin reconcilierea <head> la navigare Turbo, vezi UI_RULES). */
.live-projector { background: var(--paper); min-height: 100vh; }
/* Proiector = lățime MAXIMĂ (datele trebuie citite din sală), conținut centrat ORIZONTAL și lipit de
   marginea de SUS. Vertical NU se mai centrează (2026-08-14): pagina duce mult conținut sub antet
   (calificări, bracket, smoke), iar centrarea împingea capul paginii în jos și scotea rândurile de
   jos din ecran — exact informația pentru care se uită sala la proiector.
   Bate plafonul page-wide 1600px (vine mai târziu în fișier). Zoom-ul A−/A+ = proprietatea CSS
   `zoom` (re-layout real, ca Ctrl+/−) prin --proj-zoom setat pe <html> (morph-ul Turbo atinge
   doar body → variabila supraviețuiește auto-refresh-ului). */
.live-projector .app-wrap {
    max-width: none; padding: 1rem 1.5rem;
    min-height: calc(100dvh - 1rem);   /* -1rem = mt-3 (utilitar !important, nu-l putem tăia) */
    display: flex; flex-direction: column;
}
/* Zoom-ul se aplică pe CONȚINUT (rândul de sus), NU pe wrapperul full-height: pe wrapper,
   min-height-ul de 100dvh se scala și el (130dvh la 1.3×) → spații mari sus/jos. Pe rând:
   wrapperul rămâne exact viewportul, iar conținutul mărit curge în jos din marginea de sus. */
.live-projector .app-wrap > .row { margin-block: 0; zoom: var(--proj-zoom, 1); }
/* Antet + tab-uri centrate orizontal */
/* Proiector: din antetul mare de concurs rămâne DOAR rândul de identitate (stare + nume) — sala
   trebuie să știe la ce concurs se uită și dacă e LIVE, dar afișul, locația/data, programul și
   butoanele ownerului sunt chrome de birou și fură din înălțime. Ascunderea e STRUCTURALĂ (copiii
   antetului), nu o listă de clase per element — un element nou în antet rămâne ascuns din start.
   ⚠️ Butoanele ownerului stau ACUM în rândul păstrat, deci nu mai sunt ascunse de structură: le
   ascunde `.proj-hide` de pe `.res-hero__acts` (regula UI_RULES „ce trebuie să poată fi ascuns de un
   mod primește clasă semantică" — „Editează/Șterge" sunt <a>, nu <form>). */
.live-projector .res-hero { display: block; padding: 0 0 .4rem; margin-bottom: .6rem; }
.live-projector .res-hero__poster,
.live-projector .res-hero__main > :not(.res-hero__body),
.live-projector .res-hero__body > :not(.res-hero__id) { display: none; }
.live-projector .res-hero__id { justify-content: center; }
/* Banda de categorii RĂMÂNE pe proiector (ADR 0019): e comanda manuală a ecranului — un click
   fixează sala pe o categorie, iar comutatorul din .proj-zoom o dă înapoi pe urmărire. Centrată și
   mai mare, fiindcă se apasă în picioare, lângă proiector, nu cu mouse-ul la 40 cm. */
/* ⚠️ Centrare pe CUTIE (`fit-content` + `margin-inline: auto`), NU `justify-content: center`: banda
   e acum un container care SCROLLEAZĂ, iar centrarea conținutului într-un scroller împinge începutul
   la offset NEGATIV — zonă inaccesibilă. Cu 6 categorii, primele tab-uri ar deveni invizibile ȘI
   neapăsabile exact pe ecranul unde banda E comanda manuală (ADR 0019). */
.live-projector .cat-strip { width: fit-content; max-width: 100%; margin-inline: auto; }
/* Capul benzii (eticheta „Categorii" + săgețile de derulare) e ajutor de navigare pentru un om cu
   telefonul în mână, nu informație pentru sală. Șina blocului de categorie la fel: pe proiector
   conținutul e centrat, iar o șină pe stânga l-ar decala. */
.live-projector .cat-nav__hd { display: none; }
.live-projector .cat-block { border-inline-start: 0; padding-inline-start: 0; }
/* Ținta de click, nu doar textul: se apasă în picioare, lângă proiector. Mărimea se pune pe LINIILE
   tabului, nu pe item: liniile își declară singure treapta (rolurile tipografice), deci un
   `font-size` pe părinte n-ar mai ajunge la text. */
.live-projector .cat-strip__item { padding: .35rem .8rem; }
.live-projector .cat-strip__l1 { font-size: var(--font-2xl); }
.live-projector .cat-strip__l2 { font-size: var(--font-sm); }
.live-projector .res-cat-head { width: fit-content; max-width: 100%; margin-inline: auto; }
/* Rândul „Înscriși" (tab calificare) — centrat ca restul antetului. */
.live-projector .cat-entries-row { justify-content: center; }
/* Mod prezentare = fără controale de management pe ecranul public (ROUTING_GUIDELINES §2):
   ascunde formularele de acțiune ale ownerului — lifecycle din antet (Deschide/Pornește/
   Rezolvă/Bracket), Start/Finalizează din panoul battle-ului curent, ștergerea/adăugarea
   de înscriși — și notele de lucru ale organizatorului (.owner-note: panel incomplet,
   departajare). Butonul „Proiector" (button simplu, nu form) rămâne = ieșirea din mod.
   `.proj-hide` = aceeași regulă pentru elementele care NU sunt formulare (ex. linkul „Ecran de
   sală": pe proiector ești deja acolo). */
.live-projector .action-group form,
.live-projector .bk-current__ctrl form,
.live-projector .e-chip-del__form,
.live-projector .owner-note,
.live-projector .proj-hide,
.live-projector [data-bs-target^="#f"] { display: none; }
.live-projector .cat-tabs { justify-content: center; }
/* Scoreboard + bracket = UNITATE centrată împreună: scoreboard-ul iese din plafonul de 33%
   (lățime fixă confortabilă), bracketul rămâne la lățimea lui naturală (shrink → .bk-scroll preia),
   perechea e centrată cu justify-content. Alinierea verticală reciprocă = align-self: center existent. */
.live-projector .bk-layout { justify-content: center; }
/* Aceeași adaptare ca pe ecranul organizatorului, dar cu praguri de proiector: panoul are ca BAZĂ
   exact lățimea fixă de dinainte (deci cu bracket mare nimic nu se schimbă), poate CREȘTE în spațiul
   pe care un bracket mic nu-l cere, dar NU se micșorează.
   Bracketul rămâne `flex: 0 1 auto` — dimensionat de conținut, se strânge, dar NU crește; astfel
   surplusul rămas după plafonul panoului devine margine, iar `justify-content: center` de mai sus
   ține grupul centrat, adică exact aspectul de proiector de acum.
   Plafonul e mai generos decât la organizator (65vw vs 60%): aici cardul se citește din fundul sălii,
   deci un battle mare la un bracket de 4 e chiar scopul, nu un exces. */
.live-projector .bk-layout__current { flex: 1 0 min(30rem, 40vw); width: auto; max-width: min(70rem, 65vw); }
.live-projector .bk-layout__bracket { flex: 0 1 auto; }
/* Tabul Calificare: coloanele dense citesc mai bine plafonate + centrate */
.live-projector .tab-pane > .row { max-width: 1500px; margin-inline: auto; }
/* Butoanele de zoom: există în DOM mereu, vizibile DOAR în mod proiector */
.proj-zoom { display: none; }
.live-projector .proj-zoom {
    display: flex; gap: .25rem;
    position: fixed; right: 1rem; bottom: 1rem; z-index: 50;
}
/* Ecran FIXAT manual (nu mai urmărește organizatorul, 2026-08-10): pastila „Urmărește" pulsează —
   starea de pin nu mai e tăcută (incidentul „promite că vine și nu vine": un tap pe banda de
   categorii fixa ecranul fără niciun semnal). Același ritm ca smoke-queue-pulse (.9s). */
@keyframes proj-follow-off-pulse { 50% { box-shadow: 0 0 0 4px var(--warning); } }
.live-projector .proj-zoom__follow--off {
    background: var(--warning-soft); color: var(--on-warning-soft); border-color: var(--warning);
    animation: proj-follow-off-pulse .9s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) { .live-projector .proj-zoom__follow--off { animation: none; } }

/* Badge-uri tip eveniment */


/* (.badge-style-0..7 eliminate — înlocuite de .style-pill cu hue din name|style_hue) */

/* ── CONTEST GRID — masonry pe coloane (JS: assets/js/masonry-columns.js).
   Card = bandă poster SUS (titlu + meta peste) + categorii dedesubt. Coloanele-s independente
   → expand-ul unei înscrieri crește DOAR coloana cardului (fără salt, fără împins rândul de jos).
   Fallback fără JS = CSS Grid de mai jos. ── */
.bcast-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; align-items: start; }
@media (max-width: 760px)  { .bcast-grid { grid-template-columns: 1fr; } }
.bcast-grid.is-masonry { display: flex; align-items: flex-start; }   /* JS a construit coloane independente */
.bcast-col { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1rem; }

/* FĂRĂ overflow:hidden pe card: dropdown-ul de autocomplete al formularului de înscriere
   (.ac-dropdown, absolut, 210px) trebuie să poată ieși din card — clip-ul îl reteza la marginea
   cardului. Ce avea de clipuit clip-ul (colțurile posterului) se face pe .ccard__hero. */
.ccard {
    background: var(--surface);
    border: 2px solid var(--border-strong);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-hard-sm);
}
/* Cardul cu dropdown-ul DESCHIS urcă peste frați: containment-ul kf (container-type pe .ccard)
   face fiecare card stacking context atomic, pictat în ordinea DOM — fără raise, cardul de
   DEDESUBT din aceeași coloană ar picta peste lista de sugestii. z-index merge fără position:
   cardurile sunt flex items (.bcast-col) / grid items (.bcast-grid). */
.ccard:has(.ac-dropdown.ac-open) { z-index: 2; }

/* HERO — poster bandă sus, full-width, cu titlu + meta PESTE (gradient pt lizibilitate) */
.ccard__hero { position: relative; aspect-ratio: 16 / 9; background: var(--surface-inverse); overflow: hidden; border-radius: inherit; }
.ccard__hero[data-lightbox] { cursor: zoom-in; }
.ccard__hero img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* SCRIM-UL trebuie să fie plin ACOLO UNDE E TEXTUL, nu doar jos. Varianta veche se stingea complet
   spre partea de sus a suprapunerii — adică fix peste titlu, care e primul copil: pe un afiș încărcat
   numele concursului se pierdea în imagine (raport user 2026-08-16). Acum e plin până deasupra
   titlului și se stinge în ultimii ~12%, care cad în padding, deci deasupra numelui.
   `color-mix` peste tokenul de cerneală, nu `rgba()` literal (regula „zero hex/rgba în componente").
   Scrim PINNAT (același pe ambele teme) fiindcă textul de deasupra e pinnat alb.
   ⚠️ Stopurile de AICI sunt calculate pe `inset: 0` (suprapunerea acoperă tot afișul, conținutul e
   împins jos de `justify-content`), iar cele din `body.kf` pe `inset: auto 0 0 0` (suprapunerea e
   exact cât conținutul). Aceleași procente în ambele locuri ar acoperi trei sferturi din afiș aici.
   Regula care se vede în producție e cea din kf-skin — asta e plasa pentru o pagină fără skin. */
.ccard__hero-ov  { position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: flex-end; gap: 2px; padding: .55rem .65rem; background: linear-gradient(to top, color-mix(in srgb, var(--c-ink-900) 88%, transparent) 0%, color-mix(in srgb, var(--c-ink-900) 88%, transparent) 40%, color-mix(in srgb, var(--c-ink-900) 40%, transparent) 62%, transparent 80%); }
.ccard__title    { font-family: var(--font-display); font-weight: 900; text-transform: uppercase; letter-spacing: -.01em; line-height: 1.05; font-size: clamp(1.1rem, 1.5vw, 1.45rem); color: var(--c-white); }
/* Titlul-link spre pagina canonică a concursului — moștenește look-ul titlului, underline la hover */
.ccard__title-link { color: inherit; text-decoration: none; }
.ccard__title-link:hover { text-decoration: underline; }
.ccard__herometa { display: flex; flex-wrap: wrap; align-items: center; gap: .1rem .7rem; font-size: var(--font-sm); color: rgba(255,255,255,.88); }
.ccard__herometa i { opacity: .8; }
.ccard__hero-badges { position: absolute; top: 6px; right: 6px; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 4px; max-width: 75%; }
.cbc-days        { font-family: var(--font-mono); font-size: var(--font-xs); font-weight: 700; background: var(--ink); color: var(--text-on-inverse); padding: 2px 7px; border-radius: var(--radius-sm); white-space: nowrap; }
.cbc-days--today { background: var(--primary); color: var(--on-primary); }
.ccard__zoom { position: absolute; bottom: 6px; right: 6px; background: rgba(0,0,0,.55); color: var(--c-white); font-size: var(--font-2xs); padding: 1px 5px; border-radius: var(--radius-sm); }

/* ══ PROGRAM — LINIE DE TIMP (templates/contest/_schedule_timeline.html.twig) ══════════════════
   Un „stop" = oră / punct pe linie / etichetă / pastilă de stil (opțională). Spațierea e EGALĂ, nu
   proporțională cu ora: la ore apropiate pozițiile proporționale suprapun etichetele, iar o pauză de
   patru ore ar lăsa jumătate de bandă goală.

   ALINIEREA ÎNTRE STOPURI o ține gridul, nu min-height-uri ghicite: `.tline__stops` declară TREI
   rânduri (sus / punct / jos), iar fiecare `.tline__stop` le moștenește prin `subgrid`. De aici vine
   și alternanța: `--flip` doar schimbă între ele rândul orei și rândul textului, deci linia de puncte
   rămâne la aceeași înălțime la toate stopurile, indiferent pe ce parte le cade conținutul.

   PODEAUA COLOANEI e mai joasă decât lățimea de citire a etichetei, și asta NU e o scăpare: pe un rând,
   vecinul orizontal al unei etichete e MEREU o oră (alternanța `--flip` e globală peste zile, deci pe
   rândul de sus se succed oră / text / oră / text). Ora are lățime FIXĂ și mică — „10:00" în Space Mono
   la `--font-xs` = 5 × .6em + padding ≈ 2.4rem — deci lângă ea rămâne un culoar liber pe care nimeni
   nu-l folosește. Eticheta îl împrumută (`--tline-bleed`, revărsare simetrică peste vecini), și de aici
   coloana poate coborî de la 5.5rem la 4rem fără ca textul să se apropie de oră: la W=4rem eticheta are
   4.8rem de citit, cu `--tline-text-gap` de respirație până la cutia orei. Relația e derivată, nu
   ghicită — muți `--tline-stop-min` și revărsarea se recalculează singură.
   ⚠️ Ce se sprijină pe alternanță: dacă cineva scoate `--flip`, două etichete ajung vecine pe același
   rând și revărsarea le suprapune. Alternanța e portantă, nu decor.

   ⚠️ DIMENSIUNILE NU sunt `cqi` aici, deși regula generală o cere — și motivul e o constrângere de
   spec, nu comoditate. Ce contează pentru înghesuială e lățimea unui STOP, nu a benzii; dar ca stopul
   să fie container de interogare i-ar trebui `container-type: inline-size`, iar containment-ul face
   `subgrid` să se calculeze ca `grid` simplu → rândurile nu s-ar mai alinia între stopuri, adică fix
   ce ține componenta în picioare. Iar `cqi` măsurat pe `.tline` e inutil: pe un card lat clamp-ul
   lovește mereu plafonul, oricâte momente ar fi în bandă. Adaptarea e deci STRUCTURALĂ, nu tipografică:
   podea pe coloană (`--tline-stop-min`) + scroll + alternanță sus/jos, cu fonturi fixe din tokeni.

   CULOAREA ZILEI = hue, ca la `.style-pill`: saturația/luminozitatea vin din tokeni theme-aware, hue-ul
   din modificatorul segmentului. Culorile de STATUS (--success/--warning/--danger) NU se împrumută
   aici — în restul aplicației înseamnă terminat/atenție/eroare, iar „ziua a doua" nu e niciuna.

   ⚠️ `scripts/contrast-audit.php` NU poate verifica blocul ăsta: nu evaluează `hsl()` compus din
   variabile, `color-mix()` și nici alpha peste un gradient (limitări scrise în capul scriptului).
   A adăuga perechile în `PAIRS` ca hex-uri ar da fals-pozitive, fiindcă scriptul le-ar evalua pe
   AMBELE teme cu aceeași valoare. Deci contrastul e calculat de mână și scris aici, ca următoarea
   sesiune să nu-l re-derive. Cel mai prost caz per set (praguri: 4.5 text, 3.0 element UI):
     light s62/l26 → 5.44:1 (hue 76 pe card #f4f4f1)   · l30 pica la 4.30:1
     dark  s55/l66 → 5.39:1 (hue 285 pe card #1f211c)
     media s58/l76 → 4.91:1 (hue 285) / linia 45% alb → 3.53:1, ambele peste poster ALB sub
                     gradientul .82, adică fundalul cel mai deschis posibil. ══ */
.tline {
    min-width: 0;
    margin-top: .55rem;
    --tline-stop-min: 4rem;     /* sub asta nu se mai strânge; de aici încolo railul scrollează */
    --tline-time-w: 2.4rem;     /* „10:00" la --font-xs în Space Mono (5 × .6em) + padding-ul orei */
    --tline-text-gap: .4rem;    /* respirația dintre eticheta revărsată și cutia orei vecine */
    /* Cât poate ieși eticheta din coloana ei, în FIECARE parte: jumătatea de culoar liberă de lângă ora
       vecină, minus respirația. `max(0px, …)` ca o podea prea mică să nu producă revărsare negativă. */
    --tline-bleed: max(0px, calc((var(--tline-stop-min) - var(--tline-time-w)) / 2 - var(--tline-text-gap)));
    --tline-dot: 7px;           /* punctul rămâne px: sub ~5px dispare, indiferent de container */
    --tline-dot-row: 1.05rem;   /* înălțimea rândului punctului = distanța dintre oră și etichetă */
    --tline-s: 62%;
    --tline-l: 26%;             /* accent pe fundal DESCHIS; 30% pica hue-ul de brand la 4.30:1 */
    --tline-ink: var(--text);
    --tline-ink-muted: var(--text-muted);
    /* --border-control, nu --border-strong: hairline-ul de card (1.43:1) e invizibil, iar aici linia
       E componenta. Tokenul ăsta există exact pentru „conturul care trebuie să se vadă". */
    --tline-line: var(--border-control);
}
[data-theme="dark"] .tline { --tline-s: 55%; --tline-l: 66%; }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme]) .tline { --tline-s: 55%; --tline-l: 66%; }
}
/* Peste poster: gradientul heroului e întunecat FIX, indiferent de temă. Fundal pinned → cerneală
   pinned (UI_RULES) — moștenirea rolurilor ar da text închis pe întuneric la prima temă care le
   inversează. Aceeași logică ca `.ccard__herometa` de mai sus. */
.tline--onmedia {
    margin: .3rem 0 .4rem;
    /* Valorile sunt măsurate pe cazul CEL MAI RĂU (poster alb sub gradientul .82), nu pe unul comod:
       la s62/l68 hue-ul violet al zilei 4 cădea la 3.67:1, iar linia la 38% alb la 2.97:1. */
    --tline-s: 58%;
    --tline-l: 76%;
    --tline-ink: var(--c-white);
    --tline-ink-muted: color-mix(in srgb, var(--c-white) 72%, transparent);
    --tline-line: color-mix(in srgb, var(--c-white) 45%, transparent);
}

.tline__rail {
    display: flex; align-items: flex-start;
    margin: 0; padding: 0; list-style: none;
    overflow-x: auto; overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    scrollbar-width: none;                  /* banda are ~3rem — o bară de scroll ar dubla-o */
    /* Capetele railului n-au vecin peste care să se reverse: fără padding, eticheta primului stop ar
       ieși în stânga originii de scroll (zonă inaccesibilă) și ar fi TĂIATĂ, nu doar ascunsă. */
    padding-inline: var(--tline-bleed);
}
.tline__rail::-webkit-scrollbar { display: none; }

/* FĂRĂ `min-width: 0`: minimul automat al unui flex item e min-content, și AICI e exact ce vrem —
   un segment care poate coborî sub conținutul lui nu se strânge, ci își revarsă chipul de zi peste
   segmentul vecin (raport user: „Ziua 2 intră peste Ziua 1" la ecran îngust). Cu min-content păstrat,
   railul depășește și SCROLLEAZĂ, adică exact mecanismul ales pentru înghesuială. */
.tline__seg {
    flex: 1 1 auto;
    --tline-accent: hsl(var(--tline-h, 76) var(--tline-s) var(--tline-l));
}
.tline__seg--c0 { --tline-h: 76; }    /* hue-ul de brand (lime/olive) */
.tline__seg--c1 { --tline-h: 187; }
.tline__seg--c2 { --tline-h: 22; }
.tline__seg--c3 { --tline-h: 285; }
/* Separatorul dintre zile = PSEUDO-element, nu `border-left`: borderul ar intra în cutia flex și ar
   îngusta exact segmentele marcate față de frații lor (UI_RULES, „linie decorativă pe flex: 1"). */
/* Șanțul dintre zile ține cont de revărsare: etichetele de la marginile a două segmente vecine se
   revarsă UNA SPRE ALTA, iar linia punctată stă exact la mijloc. `bleed + .35rem` de fiecare parte =
   linia rămâne liberă în ambele sensuri; fără termenul `bleed`, textul ar călca peste ea. */
.tline__seg + .tline__seg {
    position: relative;
    margin-left: calc(var(--tline-bleed) + .35rem);
    padding-left: calc(var(--tline-bleed) + .35rem);
}
.tline__seg + .tline__seg::before {
    content: ""; position: absolute; inset-block: 0; left: 0;
    border-left: 1px dashed var(--tline-line); pointer-events: none;
}

/* Chipul zilei stă pe MUCHIA DE SUS a segmentului (pattern fieldset/legend): eticheta care stăpânește
   un grup îl încadrează, nu îl taie prin mijloc. Apare doar când programul chiar are mai multe zile.
   `nowrap` + `white-space: nowrap` sunt PORTANTE, nu cosmetice: ele fac min-content-ul segmentului să
   includă chipul întreg, deci segmentul nu poate ajunge mai îngust decât propria etichetă. */
.tline__day {
    display: flex; align-items: baseline; gap: .3rem; flex-wrap: nowrap; white-space: nowrap;
    font-family: var(--font-display); font-weight: 900;
    text-transform: uppercase; letter-spacing: .06em;
    font-size: var(--font-2xs);
    line-height: 1.3;
    color: var(--tline-accent);
    padding-bottom: .15rem;
}
.tline__daydate {
    font-family: var(--font-mono); font-weight: 400; letter-spacing: .02em;
    color: var(--tline-ink-muted);
}

.tline__stops {
    display: grid; grid-auto-flow: column;
    grid-auto-columns: minmax(var(--tline-stop-min), 1fr);
    grid-template-rows: auto var(--tline-dot-row) auto;   /* sus · punct · jos */
    margin: 0; padding: 0; list-style: none;
}
/* ZERO padding orizontal pe stop: `.tline__dot` se întinde pe lățimea stopului, deci orice padding aici
   ar tăia linia la fiecare punct (raport user: „linia e întreruptă la fiecare pas" — erau 2×2.4px).
   Respirația laterală o iau TEXTELE, care n-au nimic de desenat până la marginea coloanei. */
.tline__stop {
    display: grid; grid-row: 1 / -1; grid-template-rows: subgrid;
    justify-items: center; text-align: center;
    scroll-snap-align: start;
    padding: 0;
}
/* ALTERNANȚĂ sus/jos: implicit ora deasupra liniei și textul dedesubt; la fiecare al doilea punct se
   inversează. Nu e decor — la spațiere egală, două etichete lungi vecine se citesc greu una lângă
   alta; puse pe rânduri diferite își recapătă respirația fără să lățim coloana. */
.tline__time { grid-row: 1; align-self: end; }
.tline__dot  { grid-row: 2; }
.tline__text { grid-row: 3; align-self: start; }
.tline__stop--flip .tline__time { grid-row: 3; align-self: start; }
.tline__stop--flip .tline__text { grid-row: 1; align-self: end; }

/* `width`, nu `max-width`: stopul aliniază cu `justify-items: center`, adică lățimea copilului e
   shrink-to-fit FAȚĂ DE CELULĂ — un `max-width` mai mare n-ar crește-o niciodată, doar ar ridica un
   plafon pe care nimeni nu-l atinge. Lățimea explicită o duce peste celulă, iar centrarea o revarsă
   simetric, deci eticheta rămâne centrată pe punctul ei. */
.tline__text {
    display: flex; flex-direction: column; align-items: center; gap: .15rem;
    min-width: 0; padding-inline: .15rem;
    width: calc(100% + var(--tline-bleed) * 2);
}

/* Linia ȘI punctul într-un singur element: așa punctul e garantat pe linie, iar linia se întinde pe
   toată lățimea coloanei — stopurile lipite dau o linie continuă, fără nimic poziționat absolut față
   de un container care scrollează. */
.tline__dot { position: relative; justify-self: stretch; align-self: center; height: var(--tline-dot-row); }
.tline__dot::before {
    content: ""; position: absolute; left: 0; right: 0; top: calc(50% - .5px);
    height: 1px; background: var(--tline-line);
}
.tline__dot::after {
    content: ""; position: absolute; top: 50%; left: 50%;
    width: var(--tline-dot); height: var(--tline-dot);
    transform: translate(-50%, -50%);
    background: var(--tline-accent); border-radius: 50%;
}
/* Capetele se opresc ÎN primul/ultimul punct, nu în gol. */
.tline__seg:first-child .tline__stop:first-child .tline__dot::before { left: 50%; }
.tline__seg:last-child  .tline__stop:last-child  .tline__dot::before { right: 50%; }

.tline__time {
    font-family: var(--font-mono); font-weight: 700;
    font-size: var(--font-xs);
    font-variant-numeric: tabular-nums; letter-spacing: .01em;
    line-height: 1.4; white-space: nowrap;
    padding-inline: .15rem;
    color: var(--tline-ink);
}
.tline__label {
    font-family: var(--font-display); font-weight: 900;
    text-transform: uppercase; letter-spacing: .02em; line-height: 1.2;
    font-size: var(--font-2xs);
    color: var(--tline-ink-muted);
    max-width: 100%;
    /* Maxim două rânduri: un „Battle-uri finale open style" ar întinde banda peste tot cardul.
       Eticheta întreagă rămâne în program, pe pagina de concurs. */
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
    overflow: hidden; overflow-wrap: anywhere;
}
/* Pastila de stil: aceeași componentă ca pe rândurile de categorie, la scara benzii.
   Formatul (1v1 / 2v2) e ce diferențiază două categorii cu ACELAȘI stil, deci nu are voie să fie el
   cel tăiat: `flex: none` pe format + truncherea pe numele stilului. */
.tline__cat { max-width: 100%; min-width: 0; gap: .3em; }
.tline__catname { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tline__catfmt { flex: none; font-weight: 400; }

/* CATEGORIE — bloc pe 3 rânduri + bară „înscrie-te" full-width jos.
   /concursuri tab Deschise: detaliile = link spre pagina concursului (.ccat__stretch acoperă cardul),
   ÎNSCRIEREA se comută DOAR din butonul .ccat__cta. Elementele interactive (CTA, acțiuni owner,
   „Vezi toți") stau DEASUPRA link-ului prin z-index. Celelalte taburi: .ccat e direct un <a> (link). */
/* Bara de acțiuni a ownerului pe card (editează/șterge concursul) — RÂND al cardului, nu butoane
   plutind: aceeași margine interioară ca `.ccat` + același hairline + etichetă `.ccat__lbl`, ca să
   citească la fel cu „Acțiuni" / „Înscriși" de dedesubt. (Înainte: `px-2 pt-2 justify-content-end`,
   care nu se alinia cu nimic din card.) */
.ccard__owner { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .45rem; padding: .45rem .65rem; border-top: 1px solid var(--border-hair); }
.ccat { display: block; padding: .5rem .65rem .6rem; border-top: 1px solid var(--border-hair); cursor: pointer; text-decoration: none; color: inherit; }
.ccat:first-of-type { border-top: none; }
.ccat:hover { background: var(--bg-elevated); }
.ccat--enroll { position: relative; }
.ccat__stretch { position: absolute; inset: 0; z-index: 1; }
.ccat--enroll .ccat__cta,
.ccat--enroll .cat-actions,
.ccat--enroll .chips-more-btn { position: relative; z-index: 2; }
/* `wrap`, nu `nowrap` + `overflow: hidden`. Regula veche era COD MORT care inducea în eroare: pe orice
   pagină `kf` (adică toate cele publice) `body.kf .ccat__l1` din `@layer components` o comuta oricum
   pe `wrap`. Citind doar `@layer app` credeai că rândul TAIE conținutul la strâmtoare — nu taie.
   Aliniat cu realitatea, ca următoarea sesiune să nu „repare" un bug care nu există. */
.ccat__l1  { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem; }
.ccat__row { display: flex; flex-wrap: wrap; align-items: center; gap: .2rem; margin-top: .3rem; }
.ccat__row--entries { align-items: flex-start; }   /* zona Înscriși = 2 linii fixe → label la vârf */
.ccat__lbl { font-family: var(--font-display); font-weight: 900; text-transform: uppercase; letter-spacing: .06em; font-size: var(--font-2xs); color: var(--text-muted); margin-right: 2px; }
.ccat__cta { width: 100%; display: flex; align-items: center; justify-content: center; gap: .35rem; margin-top: .5rem; padding: .35rem .5rem; background: var(--surface-inverse); color: var(--text-on-inverse); border: 2px solid var(--border-strong); border-radius: var(--radius-sm); font-family: var(--font-display); font-weight: 900; text-transform: uppercase; letter-spacing: .05em; font-size: var(--font-xs); cursor: pointer; transition: background .1s, color .1s, border-color .1s; }
.ccat__cta .bi-chevron-down { transition: transform .2s; }
.ccat__cta:hover, .ccat__cta[aria-expanded="true"] { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.ccat__cta[aria-expanded="true"] .bi-chevron-down { transform: rotate(180deg); }
.ccat-form { padding: .6rem .65rem .7rem; background: var(--bg-elevated); border-top: 2px solid var(--border-strong); }
/* Formular de înscriere adus în prim-plan la deschidere (enroll-scroll.js) → lasă loc sub navbarul
   sticky (~4rem) ca titlul formularului să nu ajungă sub el. */
[data-enroll-form] { scroll-margin-top: 4.5rem; }
.ccat-form .pc-form-title { margin-bottom: .5rem; }
.e-chip-list { display: inline-flex; flex-wrap: wrap; gap: .2rem; }

/* Confirmare „te-ai înscris" în formular — apare, ține câteva secunde, apoi se estompează și se pliază,
   lăsând formularul gol gata de o nouă înscriere (înlocuit prin Turbo Stream). */
@keyframes regDoneFade {
    0%, 60% { opacity: 1; max-height: 3rem; padding-top: .35rem; padding-bottom: .35rem; margin-bottom: .4rem; }
    100%    { opacity: 0; max-height: 0;    padding-top: 0;       padding-bottom: 0;       margin-bottom: 0; }
}
.reg-done {
    font-family: var(--font-display); font-weight: 900; text-transform: uppercase; letter-spacing: .04em;
    font-size: var(--font-sm); color: var(--success); overflow: hidden;
    animation: regDoneFade 4.5s ease forwards;
}

/* Lightbox poster — overlay seamless, view-only (poster-lightbox.js) */
body.lightbox-open { overflow: hidden; }
.lightbox { position: fixed; inset: 0; z-index: 2000; display: none; align-items: center; justify-content: center; background: rgba(0,0,0,.88); padding: 2rem; }
.lightbox.is-open { display: flex; }
.lightbox__img { max-width: 95vw; max-height: 92vh; border: 3px solid var(--ink); box-shadow: var(--shadow-hard); }
.lightbox__close { position: absolute; top: 1rem; right: 1.2rem; width: 40px; height: 40px; background: var(--ink); color: var(--c-white); border: 2px solid var(--c-white); border-radius: var(--radius-sm); font-size: var(--font-xl); cursor: pointer; display: flex; align-items: center; justify-content: center; }
.lightbox__close:hover { background: var(--primary); border-color: var(--primary); }


/* Form collapse row */


/* Grid formular dancer — `.dancer-grid` ștearsă 2026-08-14 (markupul ei nu mai există). */
/* 700, nu 900: pe paginile `kf` familia devine mono, iar asta era singura combinație mono-900 din
   formular — o etichetă de câmp n-are de ce să fie mai grea decât eticheta de grup de lângă ea. */
.dancer-lbl  { font-family: var(--font-display); font-size: var(--font-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--fg3); margin-bottom: 1px; display: block; }
.pc-form-title { font-family: var(--font-display); font-size: var(--font-xs); font-weight: 900; text-transform: uppercase; letter-spacing: .1em; color: var(--fg3); margin-bottom: 0.5rem; }

/* Pill spoturi */


/* Judecător pill: [Nume | Meta] — Flash-pink tint */
/* Tenta vine din tokenii de accent, NU din roz literal: pill-ul rămăsese pe flash-pink-ul
   „Battle Broadcast" după re-skin, deci avea ramă roz cu text olive/lime în interior. */
.j-pill     { display: inline-flex; align-items: stretch; font-size: var(--font-xs); border: 1px solid var(--border-control); border-radius: var(--radius-sm); background: var(--primary-soft); overflow: hidden; white-space: nowrap; line-height: 1.7; vertical-align: middle; text-decoration: none; }
/* .j-pill ca <a> (link spre pagina juratului, doar owner) — fără underline la hover, cursor arată clickabil. */
a.j-pill:hover { text-decoration: none; border-color: var(--primary); }
.j-pill__n  { padding: 0 5px; font-weight: 700; color: var(--primary-strong); }
.j-pill__m  { padding: 0 5px; background: var(--primary-soft); color: var(--on-primary-soft); border-left: 1px solid var(--border-hair); font-size: var(--font-2xs); }
/* Staff (DJ/Host) line-up pills — same frame as judge pills, distinct neutral/ink accent. */
.s-pill              { border-color: var(--border-control); background: var(--surface-2); }
.s-pill .j-pill__n   { color: var(--text); }
.s-pill__r           { display: inline-flex; align-items: center; padding: 0 5px; font-weight: 700; font-size: var(--font-2xs); text-transform: uppercase; letter-spacing: .04em; background: var(--surface-inverse); color: var(--text-on-inverse); }
/* HEAD COACH = subliniere pe nume, nu un segment de text „HEAD" (2026-08-16): cuvântul repeta ce
   spune deja poziția (ADR 0007: primul din listă E head-ul) și mânca ~34px pe fiecare rând de juriu,
   pe fiecare card. Cuvântul rămâne pentru cititoarele de ecran (`visually-hidden` în markup).
   `--primary` = marcajul care urmează tema (olive 6.06:1 pe light / lime-dim pe dark) — NU `--volt`,
   care ca linie dă 1.10:1 pe light. Aceeași rețetă de subliniere ca `.sc-av__v.is-win b`. */
.j-pill--head .j-pill__n { text-decoration: underline; text-underline-offset: .18em; text-decoration-thickness: .09em; text-decoration-color: var(--primary); }
.s-pill .j-pill__m   { background: var(--surface); color: var(--text-muted); border-left-color: var(--border-hair); }

/* Competitor chip simplu */
.e-chip     { display: inline-block; font-size: var(--font-xs); padding: 0 5px; border: 1px solid var(--border-hair); border-radius: var(--radius-sm); background: var(--paper-2); color: var(--fg2); white-space: nowrap; line-height: 1.7; vertical-align: middle; }
.e-chip .e-city { color: var(--fg4); }
/* Zona „Înscriși" = înălțime FIXĂ 2 rânduri de e-chip peste tot (uniform, indiferent de câți).
   Colapsat: max 2 linii + „Vezi toți (N)" (JS); deschis (.is-open): crește inline pe loc.
   ~2.6rem = 2×(line-height 1.7 × .67rem) + gap-ul de wrap; sigur pt gap .2rem (default) ȘI .3rem (kf). */
/* Zona „Înscriși" = înălțime fixă 2 linii (uniform). Pliere LINE-BASED în JS: chip-urile de pe
   linia 3+ se ascund, iar „… Vezi toți (N)" se pune INLINE după ultimul chip vizibil (în flux,
   nu absolut). Deschis (.is-open): tot vizibil + „Ascunde". Selectorul e pe ATRIBUT pur: plierea
   trăiește și pe /concursuri (.e-chip-list) și pe pagina de categorie (.cat-entries-row). */
[data-collapse-entries] { min-height: 2.6rem; align-content: flex-start; }
/* Varianta pe O linie (pagina de categorie / ecran de sală): fără rezerva de 2 linii. */
[data-collapse-lines="1"] { min-height: auto; }
.chips-more-btn {
    appearance: none; border: 0; background: none; cursor: pointer;
    margin-left: .2rem; padding: 0 .15rem;
    font-family: var(--font-mono); font-size: var(--font-xs); font-weight: 700;
    text-transform: uppercase; letter-spacing: .03em; color: var(--primary);
    text-decoration: underline; text-underline-offset: 2px;
}
.chips-more-btn:hover { color: var(--text); }

/* Competitor chip cu buton X delete — hub /cont + acțiuni organizator (prezență/invitat/șterge).
   Înălțime minimă generoasă (--chip-act-h) ca fiecare acțiune să fie ușor de atins cu degetul; pe
   telefon crește la --tap-min (44px, a11y). */
.e-chip-del {
    --chip-act-h: 1.9rem;
    display: inline-flex; align-items: stretch;
    font-size: var(--font-xs);
    min-height: var(--chip-act-h);
    border: 1px solid var(--border-hair);
    border-radius: var(--radius-sm);
    background: var(--paper-2);
    color: var(--fg2);
    white-space: nowrap;
    line-height: 1.4;
    vertical-align: middle;
    overflow: hidden;
    margin-bottom: 3px;
}
.e-chip-del__name { display: inline-flex; align-items: center; padding: 0 8px; }
.e-chip-del__name .e-city { color: var(--fg4); }
.e-chip-del__form { display: inline-flex; margin: 0; padding: 0; }
/* Butoanele-acțiune (× și ★) = cutii pătrate, lățime confortabilă, separator vizibil între ele. */
.e-chip-del__x,
.e-chip-del__act {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 30px;
    background: var(--paper-2);
    border: none; border-left: 1px solid var(--border-strong);
    color: var(--fg3); line-height: 1;
    cursor: pointer; padding: 0;
    transition: background .1s, color .1s;
}
.e-chip-del__x { font-size: var(--font-md); }
.e-chip-del__act { font-size: var(--font-sm); }
.e-chip-del__x:hover { background: var(--danger); color: var(--on-danger); }
/* Fără X pe concursuri nemodificabile */
.e-chip-del:not(.e-chip-del--rm) .e-chip-del__name { padding: 0 8px; }

/* --- Invitat (calificat direct) + apel prezență --- */
/* Marcaj INVITAT — micro-badge pe chip (public ȘI organizator), derivat din tokenii de accent. */
/* `--font-2xs`, nu `--font-3xs`: era singura treaptă de 3xs de pe pagină — o excepție de o singură
   folosire nu e o treaptă de scară, e o valoare uitată. */
.e-chip__inv {
    font-size: var(--font-2xs); font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
    padding: 0 3px; border-radius: var(--radius-sm);
    background: var(--primary); color: var(--on-primary); vertical-align: middle;
}
/* Numele = ținta de tap pentru apel (buton, dar arată ca text în chip). */
button.e-chip-del__name {
    appearance: none; border: 0; background: transparent; color: inherit;
    font: inherit; text-align: left; cursor: pointer;
}
.e-chip-del__cform { display: inline-flex; margin: 0; padding: 0; min-width: 0; flex: 1 1 auto; }
.e-chip-del__cform .e-chip-del__name { width: 100%; }
.e-chip-del__tick { color: var(--success); margin-right: .25rem; }
/* Confirmat prezent = fundal verde discret pe tot chipul; invitat = chenar accent. */
.e-chip-del--in  { background: var(--success-soft); }
.e-chip-del--inv { border-color: var(--primary); }
/* Comutatorul ★ „invitat" — pornit = accent plin (se vede clar că e invitat). */
.e-chip-del__act:hover { background: var(--primary); color: var(--on-primary); }
.e-chip-del__act--on { background: var(--primary); color: var(--on-primary); }

/* Spinner de procesare la tap (prezență/invitat) — spațiul e rezervat mereu (lățime 0 → nu mișcă
   nimic), devine vizibil doar pe .is-busy. */
.e-chip-del__spin {
    display: inline-flex; align-items: center; justify-content: center;
    width: 0; overflow: hidden;
    transition: width .1s;
}
.e-chip-del__spin::before {
    content: ""; width: 12px; height: 12px;
    border: 2px solid var(--border-strong); border-top-color: var(--primary);
    border-radius: 50%;
}
.e-chip-del.is-busy { opacity: .65; }
.e-chip-del.is-busy .e-chip-del__spin { width: 20px; }
.e-chip-del.is-busy .e-chip-del__spin::before { animation: e-chip-spin .6s linear infinite; }
/* Cât procesează, nu mai accepta un al doilea tap pe același chip. */
.e-chip-del.is-busy .e-chip-del__name,
.e-chip-del.is-busy .e-chip-del__act,
.e-chip-del.is-busy .e-chip-del__x { pointer-events: none; }
@keyframes e-chip-spin { to { transform: rotate(360deg); } }

/* Poster thumb */
.poster-thumb       { height: 42px; width: auto; object-fit: cover; }


.spots { font-family: var(--font-mono); font-size: var(--font-xs); font-weight: 700; padding: 0 7px; border-radius: var(--radius-sm); line-height: 1.8; white-space: nowrap; flex-shrink: 0; }


/* (.pc-form-title / .dancer-lbl = definite mai sus în secțiunea form; dup scos) */

/* Autocomplete dancer name */
.ac-wrap { position: relative; }
.ac-dropdown {
    display: none; position: absolute; top: 100%; left: 0; right: 0;
    background: var(--card); border: 2px solid var(--border-strong);
    border-top: none; border-radius: 0 0 var(--radius-sm) var(--radius-sm);
    max-height: 210px; overflow-y: auto; z-index: 1050;
    box-shadow: var(--shadow-hard);
}
.ac-dropdown.ac-open { display: block; }
/* Autocomplete în rânduri inline (jurat/staff): wrap lățime fixă ca inputul direct (nu full-width,
   altfel butonul +/× sare pe rândul următor); dropdown lăsat mai lat ca să încapă numele. */
.judge-inline-row .ac-wrap,
.staff-inline-row .ac-wrap { display: inline-block; width: 150px; vertical-align: middle; }
/* Câmpul de nume e și .form-field → trebuie flex column-reverse (label DEASUPRA), nu inline-block. */
.judge-inline-row .ac-wrap.form-field,
.staff-inline-row .ac-wrap.form-field { display: flex; flex-direction: column-reverse; width: auto; }
.judge-inline-row .ac-wrap .form-control,
.staff-inline-row .ac-wrap .form-control { width: 100%; }
.judge-inline-row .ac-dropdown,
.staff-inline-row .ac-dropdown { right: auto; min-width: 230px; }
.ac-item {
    padding: 5px 8px; font-size: var(--font-md); cursor: pointer;
    border-bottom: 1px solid var(--border-hair); line-height: 1.45;
    background: var(--card);
}
.ac-item:last-child { border-bottom: none; }
.ac-item:hover, .ac-item.ac-item--hover { background: var(--volt); color: var(--volt-ink); }
/* Eticheta de rol în sugestia de persoană unificată (contribuitor / ↔ legat). */
.ac-tag {
    display: inline-block; margin-left: 4px; padding: 0 5px;
    font-size: var(--font-2xs); font-weight: 600; line-height: 1.5;
    border: 1px solid var(--border-hair); border-radius: var(--radius-sm); color: var(--fg4);
}
.ac-item:hover .ac-tag, .ac-item.ac-item--hover .ac-tag { color: inherit; border-color: currentColor; }
/* Badge per-rol (dansator / jurat / DJ / Host) în sugestie — accent flash subtil, distinct de .ac-tag. */
.ac-role {
    display: inline-block; margin-left: 4px; padding: 0 5px;
    font-size: var(--font-2xs); font-weight: 700; line-height: 1.5; text-transform: lowercase;
    border: 1px solid var(--accent-soft); border-radius: var(--radius-sm); color: var(--primary); background: var(--accent-soft);
}
.ac-item:hover .ac-role, .ac-item.ac-item--hover .ac-role { color: inherit; border-color: currentColor; background: transparent; }
.ac-hint { font-size: var(--font-xs); color: var(--fg4); margin-top: 2px; margin-bottom: 4px; }

/* Tabel categorii în card */
.pub-cat-table { font-size: var(--font-md); width: 100%; border-collapse: collapse; }
.pub-cat-table td { padding: 0.3rem 0.6rem; vertical-align: top; border: none; }
.pub-cat-table tr + tr td { border-top: 1px solid var(--border-hair); }

/* Rândul de entries */
.cat-entries-row { display: flex; flex-wrap: wrap; align-items: center; gap: 2px; margin-top: 3px; }
.cat-entries-lbl { font-family: var(--font-display); font-size: var(--font-xs); font-weight: 900; color: var(--fg1); text-transform: uppercase; letter-spacing: .08em; white-space: nowrap; margin-right: 3px; }

/* Badge format battle (1v1, 2v2) */
/* ⚠️ INSIGNELE DE PE RÂNDUL DE CATEGORIE (`.ccat__l1` pe /concursuri) folosesc ACELAȘI tracking .04em
   și aceeași familie. Audit 2026-08-16: aveau trei valori diferite (.04 / .05 / .03), iar două dintre
   ele erau pe familia sans într-un rând altfel integral mono — pe același rând, la aceeași mărime,
   ochiul citește diferențele astea ca „alt fel de informație", deși nu sunt.
   Regula de tăiere: familia, cazul și tracking-ul vin din ROL (components.css § 18b); MĂRIMEA rămâne
   decizie de componentă. */
.badge-battle-fmt { font-size: var(--font-xs); color: var(--fg2); background: var(--paper-2); border: 1px solid var(--border-hair); border-radius: var(--radius-sm); padding: 1px 5px; font-weight: 600; white-space: nowrap; }

/* Discriminatorii categoriei (U18, Feminin) — `_discriminators.html.twig`, aceeași insignă oriunde
   apare o categorie: tab-uri, antet, carduri, arhivă, admin. Din familia lui .badge-battle-fmt, dar pe
   accent: ele sunt exact diferența dintre două categorii cu același nume, deci trebuie să sară în
   ochi mai tare decât formatul. */
.cat-disc {
    font-family: var(--font-mono);
    font-size: var(--font-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
    color: var(--primary); background: var(--primary-soft);
    border: 1px solid var(--primary); border-radius: var(--radius-sm);
    padding: 0 5px; white-space: nowrap;
}
/* Variantă fără insignă — pentru contexte unde fundalul din jur E deja rama (linia de context a
   tabului activ din banda de categorii). DUPĂ regula de bază: aceeași specificitate, deci ordinea
   în sursă e cea care decide. Culoarea vine prin moștenire, nu se re-declară. */
.cat-disc--plain { background: transparent; border: 0; padding: 0; color: inherit; }

/* Badge TOP N */
.badge-top-n { font-family: var(--font-mono); font-size: var(--font-2xs); text-transform: uppercase; letter-spacing: .04em; color: var(--fg1); background: var(--paper-2); border: 1px solid var(--border-hair); border-radius: var(--radius-sm); padding: 0 5px; font-weight: 700; white-space: nowrap; }

/* Separator inline */
.cat-sep { color: var(--border-hair); margin: 0 3px; font-size: var(--font-sm); }

/* Label număr dansator */

/* Sloturile dancer în formular multi-dansator */


/* === 12b. CATEGORY ROW (formular creare concurs) =========== */

/* padding-right REZERVĂ colțul pentru ×-ul absolut (pattern .alert-dismissible): fără el, câmpurile
   din flex-wrap ajungeau SUB buton — tap pe „Vârstă" pe telefon ștergea toată categoria. Pe mobil
   butonul crește la --tap-min (base-layout §16), unde rezerva se lărgește la fel. */
.category-row { border-radius: var(--radius-md); margin-bottom: 0.5rem; position: relative; padding: 8px 2rem 8px 10px; border: 2px solid var(--border-strong); }
.category-row--0 { background: var(--style3-bg); }
.category-row--1 { background: var(--style1-bg); }
.category-row--2 { background: var(--style2-bg); }
.category-row--3 { background: var(--style4-bg); }
.category-row--4 { background: var(--style5-bg); }
.category-row--5 { background: var(--style0-bg); }

/* Pastelurile de mai sus sunt FIXE (deschise) în AMBELE teme → textul de pe ele se pinuiește la
   ink închis fix, nu la tokeni tematici (pe dark deveneau gri/roșu deschis → ilizibil pe pastel). */
.category-row .form-field > label,
.category-row .judges-section__label { color: var(--c-kf-on-var); }
.category-row .text-muted  { color: var(--c-kf-on-var) !important; }  /* utilitarele Bootstrap au !important */
.category-row .text-danger { color: var(--c-kf-error) !important; }
.category-row .exhint--ok   { color: var(--c-kf-green); }
.category-row .exhint--warn { color: var(--c-kf-amber); }
.category-row .exhint--err  { color: var(--c-kf-error); }
[data-theme="dark"] .category-row .btn-close { filter: none; }  /* X-ul alb (dark) dispărea pe pastel */

.judges-section { border-top: 1px solid var(--border-hair); padding-top: 6px; margin-top: 6px; }
.judges-section__label { font-family: var(--font-sans); font-weight: 600; font-size: var(--font-sm); color: var(--fg3); }

/* Jurați + DJ/Host UNUL LÂNGĂ ALTUL (2 coloane desktop, stivuit pe mobil). Rândurile interioare
   rămân pe O linie: numele se întinde/strânge (flex), restul fixe, butonul × pe aceeași linie. */
/* Jurații au 4 coloane (nume · țară · sistem · ×), staff-ul doar 3 → 1fr/1fr le dădea la fel de mult. */
.judges-staff-grid { display: grid; grid-template-columns: 3fr 2fr; gap: 0 14px; }
.judges-staff-grid .judges-section { margin-top: 0; }
/* Rândul de jurat/staff se ține pe O linie prin coloane ELASTICE, nu prin wrap.
   DE CE nu se ținea: `.input-w-system` are `min-width: 110px !important` și NICIUN `max-width`, iar
   wrapperul lui e shrink-to-fit ⇒ selectul creștea cât cea mai lungă opțiune din listă (nemărginit);
   plus țara rigidă la 116px. Rândul cerea ~458px într-o coloană de ~333px, deci sistemul și × cădeau
   pe linia a doua. Al doilea vinovat: niciun copil n-avea `min-width: 0`, deci nimic nu putea micșora
   (minimul automat al unui flex item e min-content, nu 0).
   Țara e acum selectul COMPACT (`.cs--flag`, doar steagul) — 116px → 54px. */
.judges-staff-grid .judge-inline-row,
.judges-staff-grid .staff-inline-row { flex-wrap: wrap; row-gap: 4px; }
.judges-staff-grid .judge-inline-row > *,
.judges-staff-grid .staff-inline-row > * { min-width: 0; }
.judges-staff-grid .ac-wrap { flex: 2 1 5.5rem; width: auto; min-width: 0; }   /* numele = coloana mare */
.judges-staff-grid .jr-sys  { flex: 1 1 4.5rem; }
.judges-staff-grid .jr-sys > .form-select { min-width: 0 !important; }          /* bate .input-w-system */
.judges-staff-grid .input-w-name { max-width: none !important; }
/* `.form-field > label` e `white-space: nowrap` — acum că wrapperul poate micşora, eticheta ar ieşi
   din coloana ei. Se taie cu elipsă în loc să împingă rândul. */
.judges-staff-grid .form-field > label { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
/* Listele jurați/staff: intrările curg UNA LÂNGĂ ALTA când e loc (nu stivuiesc pe rânduri noi degeaba —
   ex. DJ/Host la edit, col lat). Fiecare intrare = lățime de conținut. */
.judges-list, .staff-list { display: flex; flex-wrap: wrap; gap: .5rem .75rem; align-items: flex-end; }
.judges-list > .judge-inline-row, .staff-list > .staff-inline-row { flex: 0 1 auto; }
@media (max-width: 640px) {
    .judges-staff-grid { grid-template-columns: 1fr; }
    .judges-staff-grid .judge-inline-row,
    .judges-staff-grid .staff-inline-row { flex-wrap: wrap; }
}

/* Staff DJ/Host — line-up dens grupat pe rol (compact skill: line-up pe roluri, info puțină). */
.staff-groups { display: flex; flex-wrap: wrap; gap: .2rem .9rem; align-items: center; margin: 2px 0 4px; }
.staff-grp { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.staff-grp__lbl { font-size: var(--font-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--fg4); }

/* === 12c. FORM ELEMENT WIDTHS ============================== */

.input-w-country  { width: 116px !important; }  /* select țară: steag + nume RO */
/* Select țară COMPACT (rândul de înscriere): îngust cât un steag. Mecanismul e „customizable select"
   (`appearance: base-select`, Chrome/Edge 135+): browserul randează `<selectedcontent>` = o copie a
   opțiunii alese, din care ascundem numele → în starea închisă rămâne doar steagul, iar lista deschisă
   arată numele întregi. Fără suport, tot blocul `@supports` e ignorat → select nativ îngust cu numele
   trunchiat (fallback funcțional; codul ISO ajunge la server la fel). */
.cs--flag {
    width: 3.4rem !important;
    /* FĂRĂ săgeată: steagul spune singur că se alege ceva, iar o săgeată într-un control de 3,4rem
       fură jumătate din lățime. `background-image`, nu `background:` — shorthand-ul ar reseta și
       culoarea (UI_RULES, disciplina cascadei pct. 4). */
    background-image: none !important;
    padding-right: .35rem !important;
    padding-left: .35rem !important;
    text-align: center;
}
@supports (appearance: base-select) {
    /* În modul base-select controlul e desenat de UA și își pune propria `::picker-icon` — a doua
       săgeată, peste cea a Bootstrapului. Se scoate, iar înălțimea se aliniază la restul rândului
       (`.form-field > .form-select`), altfel controlul iese mai înalt decât vecinii lui. */
    .cs--flag { appearance: base-select; min-height: 1.95rem; padding-block: .32rem; }
    .cs--flag::picker-icon { display: none; }
    .cs--flag selectedcontent .cs-name { display: none; }
}
.input-w-role     { width: 56px !important; }   /* DJ / Host */
.input-w-spots    { width: 48px !important; }   /* 4/8/16/32 — max 2 cifre */
.input-w-age      { width: 62px !important; }
.input-w-gender   { width: 80px !important; }
.input-w-tie      { width: 100px !important; }   /* „Rundă extra" / „Scor total" */
.input-w-group    { width: 84px !important; }    /* concurenți pe grupă (2-8) + label „Pe grupă" */
.input-w-name     { max-width: 112px !important; }  /* nume jurat ≈ 15 caractere */
.input-w-system   { min-width: 110px !important; }
.input-w-skill    { width: 90px !important; }
.input-w-score-sm { width: 50px !important; }

.input-w-format   { width: 70px !important; }   /* „5vs5" / „crew" */
.input-w-prize    { width: 110px !important; }  /* „500 EUR" / „adidași + trofeu" */
.input-w-dancers  { width: 55px !important; }
.input-w-style    { min-width: 120px !important; }

/* Săgeată compactă pe selecturi înguste — SVG mai mic + padding-right redus, ca textul scurt
   (Gen / Zi / format / rol) să nu fie acoperit de săgeata Bootstrap. Aplicat prin clasă (scoped). */
.sel-tight { background-size: 8px 8px !important; padding-right: 1.05rem !important; background-position: right .3rem center !important; }



/* === 14. RANKING & TIER ==================================== */

/* Coloane cu procent + mini bar */
.col-stat-pct   { width: 90px; text-align: right; }
.lb-col-rank    { width: 26px; }
.stat-pct-value { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--font-md); font-weight: 700; }
.pct-high       { color: var(--success); }
.pct-low        { color: var(--danger); }

.stat-pct-bar   { height: 3px; border-radius: var(--radius-sm); background: var(--paper-2); margin-top: 2px; overflow: hidden; }
/* lățimea vine din template ca --w (singura formă de style inline permisă) */
.stat-pct-bar .bar-fill { height: 100%; border-radius: var(--radius-sm); width: var(--w, 0%); }
.bar-win        { background: var(--success); }

/* Δ ELO (evoluția la ultimul concurs) + formă (ultimele 5 battle-uri, V/Î) — /clasament */
.lb-delta       { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--font-sm); font-weight: 700; color: var(--fg3); white-space: nowrap; }
.lb-delta--up   { color: var(--success); }
.lb-delta--down { color: var(--danger); }
.lb-form        { display: inline-flex; gap: .2rem; justify-content: flex-end; }
.form-pip       { font-family: var(--font-mono); font-size: var(--font-xs); font-weight: 700; line-height: 1; }
.form-pip--w    { color: var(--success); }
.form-pip--l    { color: var(--danger); }


/* Entity display */
.col-entity   { min-width: 160px; }


.entity-name { font-weight: 700; font-size: var(--font-md); color: var(--fg1); }


/* Tier list */
.role-tabs  { display: flex; gap: 0; border-bottom: 2px solid var(--border-strong); margin-bottom: 1rem; }
.role-tab {
    padding: 0.35rem 0.9rem; font-family: var(--font-display); font-size: var(--font-md); font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--fg3); border-bottom: 3px solid transparent;
    text-decoration: none; white-space: nowrap; margin-bottom: -2px;
    transition: color .1s, border-color .1s;
}
.role-tab:hover  { color: var(--primary); }
.role-tab.active { color: var(--fg1); border-bottom-color: var(--primary); }

/* .tier-header / .tier-badge / .tier-S..D + tokenii --tier-* = ȘTERSE 2026-08-03: zero referințe în
   templates/, src/, assets/. Erau pattern-ul de tier list din skill, niciodată adoptat — /clasament
   folosește doar .tier-table + .role-tabs + .rank-*. Dacă revine, se ia din
   .claude/skills/compact-dance-events-skill/references/tier-list-pattern.html.twig. */

.tier-table      { font-size: var(--font-md); width: 100%; border-collapse: collapse; }
.tier-table td   { padding: 0.3rem 0.5rem; border-bottom: 1px solid var(--border-hair); vertical-align: middle; }
.tier-table tbody tr:last-child td { border-bottom: none; }
.tier-table tbody tr:hover { background: var(--volt); color: var(--volt-ink); }
.tier-table-header 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.25rem 0.5rem; border-bottom: 2px solid var(--border-strong);
    background: var(--surface-inverse); white-space: nowrap; text-align: right;
}
.tier-table-header th:first-child,
.tier-table-header th:nth-child(2) { text-align: left; }

.col-rank-small { width: 28px; text-align: center; font-family: var(--font-mono); font-size: var(--font-sm); font-weight: 700; color: var(--fg4); }

/* Medalii loc 1/2/3 — utilitar GLOBAL, cerut de trei tabele fără legătură între ele: /clasament
   (dansatori + crew-uri, `.tier-table`), clasamentul calificărilor (`.pub-cat-table`) și clasamentul
   final de smoke (`.smoke-standings`). Toate trei compun clasa dinamic (`'rank-' ~ rank`), de-aia
   auditul de dead-code din 2026-08-06 n-a văzut-o și a șters-o: greppul după `rank-1` literal nu
   prinde un nume construit în Twig. Reînviată global 2026-08-14 (varianta scopată pe smoke lăsa
   celelalte două clasamente cu clasă fără reguli). Rank partajat ⇒ o medalie poate colora 2 rânduri. */
.rank-1 { color: var(--rank-gold-ink);   font-weight: 900; }
.rank-2 { color: var(--rank-silver-ink); font-weight: 900; }
.rank-3 { color: var(--rank-bronze-ink); font-weight: 900; }

/* === 15. AUTH / LOGIN ====================================== */
/* Scoped pe .login-page (clasă pe <body>), NU pe `body` global.
   Regula `body { background }` inline din template scurgea fundalul negru
   în celelalte pagini la navigarea Turbo (head-ul rămânea în DOM). */
/* Fundalul = ACELAȘI cu restul site-ului (--paper), NU --surface-inverse. `inverse` se întoarce
   cu tema (bandă închisă în light, DESCHISĂ în dark) — pe o suprafață de mărimea unei pagini asta
   dădea un login negru în light și alb în dark, iar textele scrise pe el erau crem hardcodat, deci
   dispăreau exact în tema opusă. Un fundal de pagină urmează tema, nu o inversează. */
.login-page { background: var(--paper); font-family: var(--font-sans); }
.login-brand { font-family: var(--font-display); font-weight: 900; font-size: var(--font-3xl); text-transform: uppercase; letter-spacing: -.01em; color: var(--text); }
.login-brand .bi-trophy-fill { color: var(--primary); }
.login-sub { font-size: var(--font-sm); color: var(--text-muted); text-transform: uppercase; letter-spacing: .1em; font-family: var(--font-mono); }
.login-error { font-size: var(--font-md); border-radius: var(--radius-sm); border: 2px solid var(--danger); }
/* --surface-2, nu --card: pagina e acum tot --paper, iar --card e ACEEAȘI valoare → cardul s-ar fi
   dizolvat în fundal (1.06:1) și n-ar mai fi rămas decât umbra care să-l țină. */
.login-card { background: var(--surface-2); border: 2px solid var(--border-strong); border-radius: var(--radius-sm); box-shadow: 6px 6px 0 0 var(--primary); }
.login-card .form-label { font-family: var(--font-display); font-size: var(--font-xs); font-weight: 900; text-transform: uppercase; letter-spacing: .1em; color: var(--fg2); }
.login-card .input-group-text { background: var(--paper); border: 2px solid var(--border-strong); border-right: none; color: var(--text); }
.login-card .form-control { border: 2px solid var(--border-strong); border-left: none; font-family: var(--font-sans); }
.login-card .form-control:focus { box-shadow: none; border-color: var(--primary); }
.btn-login { font-family: var(--font-display); font-weight: 900; text-transform: uppercase; letter-spacing: .08em; background: var(--surface-inverse); color: var(--text-on-inverse); border: 2px solid var(--border-strong); border-radius: var(--radius-sm); padding: .6rem 1rem; transition: background .1s, color .1s; }
.btn-login:hover { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }

/* Pagini de eroare (error403/404) — scoped pe .error-page, NU pe `body` global. */
.error-page { background: var(--paper); font-family: "Archivo", system-ui, sans-serif; }
.err-code { font-size: var(--font-10xl); font-weight: 900; color: var(--text); line-height: 1; text-transform: uppercase; letter-spacing: -.04em; }
.err-code--alert { color: var(--primary); }
.err-title { font-weight: 900; font-size: var(--font-2xl); text-transform: uppercase; letter-spacing: .04em; color: var(--text); }
.err-msg { color: var(--fg3); font-size: var(--font-md); }
/* .btn-ink* → base-layout.css „CHROME PARTAJAT" (amendament ADR 0023): modalul de confirmare e
   construit în JS (confirm-action.js) și apare pe TOATE audiențele, inclusiv pe pagina juratului,
   care nu încarcă components.css. */

/* Pagină de confirmare server-side pentru acțiuni ireversibile (B13, _confirm_page.html.twig) */
.confirm-page { display: flex; justify-content: center; padding: 2rem 1rem; }
.confirm-page__card { max-width: 34rem; width: 100%; padding: 1.25rem 1.5rem; border-left: 4px solid var(--danger); }
.confirm-page__lines { margin: .75rem 0 0; padding-left: 1.1rem; font-size: var(--font-sm); }
.confirm-page__lines li { margin-bottom: .25rem; }
.confirm-page__warn { font-weight: 700; color: var(--danger); font-size: var(--font-sm); margin: .5rem 0 1rem; }
.confirm-page__actions { display: flex; gap: .6rem; align-items: center; }

/* .confirm-modal* → base-layout.css „CHROME PARTAJAT" (amendament ADR 0023), împreună cu .btn-ink*. */


/* --- „7 to Smoke" (ADR 0026, layout v4) — vederea publică a sesiunii de coadă (_smoke_section) ---
   Derivat vizual din vocabularul existent (tier-table, badge-status, battle-timer); ecranul e
   gândit pentru proiector (/ecran): totul fluid din clamp/cqi, fără @media dur. Blocul principal =
   grila headerului de scoreboard (rețeta .sc-jc, NU clasele ei — smoke nu atinge sc__*). Stările
   (verdict verde / handover / egalitate portocalie) sunt 100% server-randate — zero JS de stare. */

/* Perechea de pe ring — cel mai mare text de pe ecran; nume | mijloc | nume. */
.smoke-vs { --smoke-dot: clamp(.8rem, 1.8vw, 1.3rem); display: grid; grid-template-columns: 1fr minmax(7rem, 16rem) 1fr; align-items: center; gap: .5rem clamp(.75rem, 3vw, 2rem); margin: .5rem 0 0; text-align: center; }
/* container-type: numele (COPIL) se mărește din lățimea coloanei (cqi), nu din viewport. */
.smoke-vs__side { display: flex; flex-direction: column; align-items: center; gap: .15rem; min-width: 0; padding: .4rem clamp(.4rem, 1.5vw, 1rem) .55rem; border-radius: var(--radius-sm); container-type: inline-size; }
/* Stările laturilor — VERDE/PORTOCALIU LITERAL (--success/--warning, nu --winner-* — sub body.kf
   familia winner e remapată la cerneala kf; cerința e culoarea în orice skin). Text rămâne --text:
   tentele -soft sunt din aceeași temă. --win urmează CÂȘTIGĂTORUL: la verdict pe latura votată,
   la handover pe stânga (King = câștigătorul, garantat de builder). --in = challengerul proaspăt
   intrat (handover). --tie = ambele laturi la flash-ul de egalitate. */
.smoke-vs__side--win { background: var(--success-soft); box-shadow: inset 0 0 0 3px var(--success); }
.smoke-vs__side--in { background: var(--surface-2); box-shadow: inset 0 0 0 3px var(--primary); }
.smoke-vs__side--tie { background: var(--warning-soft); box-shadow: inset 0 0 0 3px var(--warning); }
/* Auto-fit pe O linie: bucket de lungime din builder (smokeNames.size) × lățimea containerului.
   ≈0.62em/caracter (Archivo uppercase): ≤10 car. plin, 11-16 mediu, ≥17 mic — la maximul
   bucket-ului numele umple ~o linie; overflow-wrap rămâne plasa de siguranță. */
.smoke-vs__name { font-family: var(--font-display); font-weight: 900; text-transform: uppercase; line-height: 1.02; font-size: clamp(1.6rem, 15cqi, 5rem); overflow-wrap: break-word; max-width: 100%; }
.smoke-vs__name--m { font-size: clamp(1.3rem, 10cqi, 3.75rem); }
.smoke-vs__name--l { font-size: clamp(1.1rem, 6.7cqi, 2.5rem); }
.smoke-vs__x { color: var(--fg3); font-weight: 700; font-size: clamp(.9rem, 2.5vw, 2rem); }
/* Tag-ul + rândul juraților se randează MEREU (min-height rezervă rândul) → numele celor două
   laturi stau la aceeași înălțime, nimic nu sare la schimbarea de mod. */
.smoke-vs__tag { font-size: clamp(var(--font-2xs), 1.5vw, var(--font-md)); font-weight: 900; letter-spacing: .08em; color: var(--fg2); min-height: 1.3em; }
.smoke-vs__judges { display: block; font-size: clamp(var(--font-sm), 1.8vw, var(--font-lg)); font-weight: 700; min-height: 1.2em; }
/* Mijlocul — verdict: tally-ul juraților MARE; tie: EGALITATE / RUNDĂ EXTRA; handover/live:
   PE RING + numărătoarea; next: VS + URMEAZĂ. Ceasul de SESIUNE stă MIC aici, în toate modurile
   (inversarea am.4 — cronometrul de rundă e cel MARE, sub grilă, pe .battle-timer de bază). */
.smoke-vs__mid { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .3rem; min-width: 0; }
.smoke-vs__tally { font-family: var(--font-display); font-weight: 900; font-size: clamp(1.4rem, 5vw, 3.5rem); line-height: 1; font-variant-numeric: tabular-nums; color: var(--success); }
.smoke-vs__ties { font-size: var(--font-sm); color: var(--fg2); }
.smoke-vs__eq { font-family: var(--font-display); font-weight: 900; font-size: clamp(1.2rem, 4vw, 2.6rem); line-height: 1.05; color: var(--warning); }
.smoke-vs__eq-sub { font-size: clamp(var(--font-sm), 2vw, var(--font-lg)); font-weight: 900; letter-spacing: .06em; color: var(--warning); }
/* Badge-ul persistent al rundei extra (combinat cu .badge-status) — ține cât ține runda. */
.smoke-vs__extra { background: var(--warning-soft); color: var(--on-warning-soft); }
.smoke-now__votes { font-size: var(--font-xs); color: var(--fg2); font-weight: 700; }

/* Bilele verzi = victoriile din sesiune, sub nume oriunde apare omul. Containerul se randează
   MEREU (spațiu rezervat) ca itemele vecine să rămână aliniate. VERDE LITERAL (--success) în orice
   skin — vezi nota de la .smoke-vs__side--win; în perechea uriașă cresc din --smoke-dot. */
.smoke-dots { display: flex; flex-wrap: wrap; justify-content: center; gap: .25rem; min-height: var(--smoke-dot, .7em); }
.smoke-dots__dot { width: var(--smoke-dot, .7em); height: var(--smoke-dot, .7em); border-radius: 50%; background: var(--success); }

/* Coada — SUS, centrată; ordinea e informația-cheie, primul (evidențiat) intră următorul.
   Inelul lui vine din box-shadow, nu din border 2px — lățimea itemelor nu se mișcă între morphs. */
.smoke-queue { display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-start; gap: clamp(.35rem, 1.2vw, .75rem); margin: .4rem 0; }
.smoke-queue__lbl { font-size: var(--font-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--fg3); align-self: center; }
.smoke-queue__item { display: inline-flex; flex-direction: column; align-items: center; gap: .2rem; font-family: var(--font-display); text-transform: uppercase; font-size: clamp(var(--font-sm), 2vw, var(--font-lg)); font-weight: 700; background: var(--paper-2); border: 1px solid var(--border-hair); border-radius: var(--radius-sm); padding: clamp(2px, .5vw, 6px) clamp(6px, 1.2vw, 14px); }
.smoke-queue__item--next { border-color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); background: var(--surface-2); }
/* Challengerul care TOCMAI intră (faza „verdict"): puls periodic VIZIBIL de departe (scale +
   inel gros) — restartul la morph e invizibil pe o animație infinită. */
@keyframes smoke-queue-pulse { 50% { box-shadow: inset 0 0 0 4px var(--primary); transform: scale(1.06); } }
.smoke-queue__item--enter { animation: smoke-queue-pulse .9s ease-in-out infinite; }
/* Pierzătorul fazei de verdict (am.5) CLIPEȘTE sincron cu challengerul din coadă — aceeași durată
   și curbă, pornite la același morph — ca sala să vadă cine PLEACĂ și cine îl înlocuiește, în
   același ritm. Tenta e NEUTRĂ (inel --fg3 + scădere de prezență), nu danger: plecarea nu e o
   pedeapsă, iar roșul ar concura cu verdele verdictului de alături. Opacitatea nu coboară sub .6 —
   textul rămâne lizibil pe tot ciclul. */
@keyframes smoke-leave-pulse { 50% { box-shadow: inset 0 0 0 3px var(--fg3); opacity: .6; } }
.smoke-vs__side--out { background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--border-hair); animation: smoke-leave-pulse .9s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .smoke-queue__item--enter, .smoke-vs__side--out { animation: none; } }

/* Finalul sesiunii (am.5): clasament | desfășurător — coloane FLUIDE, pică una sub alta pe
   îngust (flex-wrap + basis, fără @media dur). */
.smoke-final { display: flex; flex-wrap: wrap; align-items: flex-start; gap: clamp(.5rem, 2vw, 1.25rem); }
.smoke-final > * { flex: 1 1 22rem; min-width: 0; }

/* Desfășurătorul: primele ~8 rânduri (≈ înălțimea clasamentului) MEREU la vedere; restul în
   <details> nativ (zero JS). `open`-ul e apărat de garda de morph din live-refresh.js. */
.smoke-log { margin: .5rem 0; border: 1px solid var(--border-hair); border-radius: var(--radius-sm); background: var(--paper-2); }
.smoke-log__head { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; padding: .45rem .7rem .2rem; }
.smoke-log__lbl { font-size: var(--font-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--fg3); }
.smoke-log__count { font-size: var(--font-2xs); color: var(--fg2); }
.smoke-log__list { margin: 0; padding: .2rem .7rem .45rem; list-style: none; display: flex; flex-direction: column; gap: .3rem; }
/* Un rând = fapte pe o linie care se împachetează natural pe îngust (flex-wrap). */
.smoke-log__row { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem; font-size: var(--font-sm); }
.smoke-log__no { font-variant-numeric: tabular-nums; color: var(--fg3); font-size: var(--font-xs); min-width: 2.2ch; }
.smoke-log__win { font-weight: 900; text-transform: uppercase; }
.smoke-log__def { color: var(--fg3); font-size: var(--font-xs); }
.smoke-log__lose { color: var(--fg2); text-transform: uppercase; }
.smoke-log__tally { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--success); }
.smoke-log__tie { font-size: var(--font-2xs); font-weight: 900; letter-spacing: .05em; color: var(--on-warning-soft); background: var(--warning-soft); border-radius: 4px; padding: 0 .3rem; }
.smoke-log__summary { padding: .3rem .7rem .45rem; cursor: pointer; font-size: var(--font-xs); font-weight: 700; color: var(--fg2); list-style: none; }
.smoke-log__summary::-webkit-details-marker { display: none; }
.smoke-log__summary:hover { color: var(--text); }
/* Eticheta summary-ului se schimbă cu starea (deschide ↔ restrânge) — două span-uri, text în
   markup (nu în `content:` — ar scăpa de traduceri), comutate din [open]. */
.smoke-log__more:not([open]) .smoke-log__close { display: none; }
.smoke-log__more[open] .smoke-log__open { display: none; }

.smoke-standings { margin: .5rem 0; }
/* Medaliile clasamentului final vin din utilitarul global `.rank-1/2/3` (secțiunea tabelelor);
   duplicatul scopat a fost scos 2026-08-14 — aceeași declarație în două locuri. */

/* === 18. RESULTS — pagina /rezultate (concurs terminat, cu chrome) =====
   Identică cu /live (tab-uri Calificare|Bracket, partiale read-only), DOAR că în sistem (cu nav) +
   antet de concurs LIZIBIL. Datele dense (bracket/scoruri) rămân compacte; titlurile + detaliile
   publice = mărite/citibile (NU stil compact-data) — pagina e exact ce caută vizitatorul. */
/* AȘEZAREA (revizuită 2026-08-15): afiș STÂNGA · identitate+meta MIJLOC · program DREAPTA.
   Afișul stătea în dreapta ca să nu împingă titlul înăuntru și să nu rupă linia verticală cu ce vine
   dedesubt (banda de categorii). Argumentul a căzut când marginea din dreapta a primit un ocupant
   real: programul. Cu afiș la dreapta ȘI program la dreapta, unul din ele ar fi trebuit să treacă pe
   un rând propriu, adică exact înălțimea pe care antetul o pierdea. Afișul rămâne îngust
   (clamp(4.5rem, 11vw, 9rem)), deci indentarea titlului e mică și constantă. */
.res-hero { display: flex; align-items: stretch; gap: clamp(.6rem, 2vw, 1.1rem); padding: .25rem 0 1rem; border-bottom: var(--border-dark); margin-bottom: 1rem; }
/* Textul + programul, unul lângă altul, cu wrap PROGRESIV: programul cade sub text când nu mai
   încape, fără breakpoint dur. `flex: 1 1 <bază>` pe fiecare = pragul de rupere e lățimea de citire
   a fiecăruia, nu o cifră de viewport. */
.res-hero__main { flex: 1 1 0; min-width: 0; display: flex; flex-wrap: wrap; align-items: flex-start; gap: .35rem clamp(.9rem, 3vw, 2rem); }
/* Coloana de text ia tot restul; min-width: 0 ca un nume lung să se rupă, nu să împingă afișul. */
.res-hero__body { flex: 1 1 22rem; min-width: 0; }
/* Programul: aceeași regulă de bază ca textul, doar cu o lățime de citire mai mică — banda de
   momente e utilă de pe la ~18rem în sus, sub asta oricum ar scrolla. */
.res-hero__aside { flex: 1 1 18rem; min-width: 0; }
/* Zona liberă de la BAZA coloanei de text (sub nume + meta), unde cade banda „acum se întâmplă aici".
   A stat o rundă ca a treia coloană, lângă program — greșit: se citea ca o CONTINUARE a liniei de
   timp, adică drept încă un moment din program.
   `:not(:has(*))`, nu `:empty`: pe paginile fără categorie blocul primește spații albe din Twig, deci
   `:empty` n-ar prinde — iar un bloc gol ar lăsa un rând mort sub detalii. */
.res-hero__extra { min-width: 0; margin-top: .45rem; }
.res-hero__extra:not(:has(*)) { display: none; }
.res-hero__extra .live-sign { margin: 0; }
/* Programul nu mai e „încă un rând sub text", ci coloană soră → marginea lui de sus (gândită pentru
   cazul stivuit) l-ar coborî față de rândul de identitate. */
.res-hero__aside .tline { margin-top: 0; }
/* Rândul de identitate: stare + nume + acțiuni de owner. Clasă proprie, nu `d-flex`: utilitarele
   Bootstrap sunt `!important` și nu pot fi ascunse/rearanjate de modul proiector. Gap fluid, wrap
   progresiv — badge-urile și grupul de butoane cad pe rând nou pe măsură ce se îngustează. */
.res-hero__id { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem clamp(.5rem, 2vw, 1rem); }
/* Acțiunile ownerului la capătul rândului. `auto` pe margine, nu `justify-content: space-between`:
   cu wrap, space-between ar împrăștia și badge-ul de stare față de titlu când rândul se rupe. */
.res-hero__acts { margin-inline-start: auto; }
/* Afișul: înălțimea NU e ghicită — o dă coloana de text (align-self: stretch), deci afișul e exact
   „cât încape" în antet. Lățimea e fluidă (clamp), iar `cover` pe o cutie mai îngustă decât un A4
   taie doar marginile; afișul întreg se vede la click, în lightbox.
   Afișul e PRIMUL și în DOM, și vizual (fostul `order: 2` a picat odată cu mutarea la stânga), deci
   pe telefon devine bandă deasupra titlului fără nicio inversare de ordine. */
.res-hero__poster {
    flex: 0 0 auto; align-self: stretch;
    width: clamp(4.5rem, 11vw, 9rem); min-height: 6rem;
    overflow: hidden; cursor: zoom-in;
    border: var(--border-dark); background: var(--surface-2);
}
.res-hero__poster img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* MOBIL (de unde vine majoritatea vizitatorilor) — afișul devine BANDĂ lată deasupra titlului, nu
   fâșie subțire pe margine: pe 360px o coloană de 4.5rem nu arată nimic din afiș și fură din lățimea
   textului. Bandă tăiată la o fâșie (aspect-ratio), NU afișul întreg: altfel antetul s-ar lungi cât
   un ecran și ar împinge informația reală (program, categorii, calificări) sub linia de plutire.
   Aici `@media` e corect: nu strânge un grup de informații, ci COMUTĂ axa layoutului (side-by-side →
   stivuit) — asta nu se poate exprima din flex-wrap. */
@media (max-width: 640px) {
    .res-hero { flex-direction: column; }
    .res-hero__poster { width: auto; min-height: 0; aspect-ratio: 16 / 6; }
    /* Puțin peste centru: afișele își pun titlul/logo-ul în treimea de sus. */
    .res-hero__poster img { object-position: center 35%; }
}
/* ROL 1 — TITLU. Un singur element pe pagină. Fluid, deci NU poate refolosi `.page-head` (fix la
   `--font-8xl`): titlul stă într-un rând care se înfășoară, lângă un badge și butoane. `.page-head`
   îi e frate, nu duplicat. Trepte din TOKENI în clamp: literalele treceau de gate doar fiindcă
   regexul `css-no-literal-font-size` nu se uită în interiorul lui `clamp()`. */
.res-hero__name {
    font-family: var(--font-display); font-weight: 900; text-transform: uppercase; letter-spacing: .01em;
    font-size: clamp(var(--font-4xl), 4.5vw, var(--font-8xl)); line-height: 1.04; color: var(--text); margin: 0;
}
/* Meta PLAT: un grup după altul pe același rând, wrap progresiv. Fostele `.res-hero__meta-col`
   (locație+dată pe o coloană, anvergură+stiluri pe alta) forțau DOUĂ rânduri chiar și când era loc
   de unul singur — două coloane de câte două intrări sunt o grupare inventată, nu una din date.
   `align-items: baseline` ca iconițele și textul să stea pe aceeași linie de scris. */
.res-hero__meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: .2rem clamp(.9rem, 3vw, 2rem); font-size: var(--font-lg); color: var(--fg2); }
.res-hero__meta i { color: var(--primary); margin-right: .4rem; }
.res-hero__meta b { color: var(--text); font-weight: 700; }

/* Banda de categorii (`.cat-nav` + `.cat-strip`) și blocul de conținut al categoriei (`.cat-block`)
   sunt definite în scoreboard.css, lângă restul componentelor paginii de concurs. */

/* `.res-cat-name` / `.res-cat-fmt` / `.res-cat-title` = ȘTERSE 2026-08-15. Titlul categoriei repeta
   exact ce scrie în tabul activ din bandă (stil + format + discriminatori): aceeași informație în
   două locuri, cu două rețete de text. Subtitlul paginii E acum tabul activ (`.cat-strip__item--on`),
   care poartă și badge-urile categoriei. Antetul de categorie păstrează doar Line-up + Juriu + acțiuni. */

/* Antetul categoriei = Line-up + Juriu unul lângă altul (.res-cat-cluster), acțiunile ownerului în
   dreapta (.res-cat-top = space-between, wrap). Titlul a plecat de aici în tabul activ, deci rândul
   ăsta nu mai plătește o linie de titlu doar ca să repete banda de deasupra.
   Gap orizontal FLUID (clamp) → aerisit pe ecran mare, strâns pe mic; grupurile pică pe rând nou
   PROGRESIV (flex-wrap, fără breakpoint dur). Fiecare grup e aliniat la STÂNGA în div-ul lui.
   ALINIEREA celor două etichete NU cere subgrid aici: sunt amândouă pe UN rând, în același rol
   tipografic, deci au aceeași înălțime și pornesc din același `align-items: flex-start`. Subgridul
   se plătește când înălțimile pot să difere (vezi `.tline__stops`), nu preventiv. */
.res-cat-top { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: .5rem 1rem; }
.res-cat-cluster { display: flex; flex-wrap: wrap; align-items: flex-start; gap: .5rem clamp(1.25rem, 4vw, 3rem); min-width: 0; }
/* Etichetă DEASUPRA, valorile pe un rând care se înfășoară dedesubt. Fostul `--stacked` (valorile
   una sub alta) a dispărut odată cu titlul: cu rândul de titlu eliberat, pastilele au loc pe
   orizontală, iar antetul câștigă înălțime în loc s-o cheltuie pe o coloană de nume. */
.res-jury { display: flex; flex-direction: column; align-items: flex-start; gap: .2rem; min-width: 0; }
.res-jury__lbl { font-size: var(--font-sm); text-transform: uppercase; letter-spacing: .04em; color: var(--fg3); font-weight: 700; }
.res-jury > .ccat__vals { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem; min-width: 0; }

/* === 18b. TIPOGRAFIE — CINCI ROLURI (pagina de concurs) ====================
   Pagina amesteca ~9 rețete de text (display 900 / mono / sans × 6 trepte de mărime × uppercase ×
   trei valori de tracking). NU e o problemă de FAMILII — proiectul are exact două fonturi reale
   (Archivo variabilă + Space Mono), adică fix regula standard „două fonturi"; problema erau
   COMBINAȚIILE. SSOT: cinci roluri, fiecare declarat O SINGURĂ DATĂ ca listă de selectori. Un
   element nou se ADAUGĂ la lista rolului lui, nu-și scrie a zecea rețetă. (Același pattern ca lista
   de mono din kf-skin.css.)

   ⚠️ Un selector care are ȘI o regulă `body.kf` în @layer components NU poate fi controlat de aici
   (ordinea layerelor bate specificitatea). Cele două cazuri — `.cat-tabs .nav-link` și
   `.cat-strip__item--on` — au fost curățate în kf-skin de proprietățile pe care le deține rolul.

   ROL 1 (TITLU) stă lângă `.res-hero__name`, unde se citește împreună cu mărimea lui fluidă. */

/* ROL 3 — ETICHETĂ: tot ce NUMEȘTE ceva (etichete de grup, tab-uri INACTIVE, sub-tab-uri).
   Declarat ÎNAINTEA rolului 2 ca ordinea în sursă să nu-l poată bate: rolul 2 e scopat cu `--on`,
   deci are specificitate mai mare oricum. */
.res-jury__lbl,
.cat-nav__lbl,
.cat-strip__item:not(.cat-strip__item--on) .cat-strip__l1,
.cat-tabs .nav-link,
.cat-entries-lbl {
    font-family: var(--font-mono); font-weight: 700;
    text-transform: uppercase; letter-spacing: .06em;
    font-size: var(--font-xs); line-height: 1.3;
}
/* Excepție de MĂRIME, nu de rol: titlul unui tab trebuie citit de la distanța de braț pe telefon,
   deci urcă o treaptă față de restul etichetelor. Familia/tracking-ul rămân ale rolului. */
.cat-strip__item:not(.cat-strip__item--on) .cat-strip__l1 { font-size: var(--font-sm); }

/* ROL 2 — SUBTITLU: un singur element pe pagină, tabul de categorie ACTIV. A înlocuit
   `h2.res-cat-name`, deci moștenește rețeta lui (display 900 uppercase).
   `--font-lg`, nu `--font-xl`: de când TOATE tab-urile au două linii, saltul de mărime al activului
   se plătește în înălțimea întregii benzi (toate cutiile se întind la cea mai înaltă). Raportul
   1.33× față de tab-urile inactive e suficient — activul mai are umplerea volt și muchia aprinsă. */
.cat-strip__item--on .cat-strip__l1 {
    font-family: var(--font-display); font-weight: 900;
    text-transform: uppercase; letter-spacing: .02em;
    font-size: var(--font-lg); line-height: 1.15;
}

/* ROL 4 — CORP: singura zonă de text „normal" din antet. */
.res-hero__meta {
    font-family: var(--font-sans); font-weight: 400;
    font-size: var(--font-lg); line-height: 1.35; color: var(--text-secondary);
}

/* ROL 5 — CIFRE / META: contoare, insigne, linia de context. Mono + tabular.
   SCOPAT LA PAGINĂ: `.badge-top-n` și `.cat-disc` sunt componente globale (/concursuri, /arhiva,
   admin) — promovarea lor la rol e o schimbare separată, mai mare decât livrarea asta. */
.cat-strip__l2,
.cat-tabs .nav-link .tab-badge {
    font-family: var(--font-mono); font-weight: 700;
    font-size: var(--font-2xs); letter-spacing: .04em;
    font-variant-numeric: tabular-nums;
}


} /* END @layer app */
