/* ============================================================
   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, site-palette; juratul: 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;

/* ARCHIVO CONDENSAT (B234, Arena): titlurile de afiș cer axa `wdth`, pe care fețele statice din `vendor-local/fonts/fonts.css` n-o
   au (fișierele lor variază doar pe `wght`). Fișierele de aici sunt Archivo variabil (wght 100–900, wdth 62–125; OFL), luate de pe
   fonts.gstatic.com v25 și găzduite local (CSP `font-src 'self'`). Fețele declară `font-stretch: 62% 99%`, deci browserul le alege
   DOAR pentru textul condensat: textul la 100% rămâne pe fețele statice, iar fișierele se descarcă abia când apare un titlu Arena.
   Stau AICI, nu în `fonts.css` și nici în paletă: ecranul juratului încarcă `fonts.css`, iar paleta nu are voie să conțină
   altceva decât tokeni (SitePaletteCssScopeTest). Componentele de site sunt singura foaie pe care juratul n-o încarcă. */
@font-face {
  font-family: 'Archivo'; font-style: normal; font-weight: 400 900; font-stretch: 62% 99%; font-display: swap;
  src: url("../vendor-local/fonts/archivo-wdth-latin-ext-iEdfVTB.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Archivo'; font-style: normal; font-weight: 400 900; font-stretch: 62% 99%; font-display: swap;
  src: url("../vendor-local/fonts/archivo-wdth-latin-Wa7z_Iw.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@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(--ui-ink); }


/* Results table */


/* Section header */


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

/* Badge status concurs */
/* Marcaj STERS la B159 L10 F1 ca ORFAN. Justifica o diferenta care nu mai exista: pe editarea
   concursului insignele de stare primesc de acum acelasi aspect ca in rest — aceeasi decizie
   ca la butoane (owner, 2026-09-23). Diferenta era un accident: pagina n-a primit niciodata clasa. */
.badge-status {
    font-family: var(--font-display);
    font-size: var(--font-xs);
    font-weight: var(--type-status-weight, 900);
    padding: var(--pad-badge);
    border-radius: var(--radius-md);
    display: inline-block;
    white-space: nowrap;
    line-height: 1.4;
    text-transform: var(--type-status-case, uppercase);
    letter-spacing: var(--type-status-tracking, 0.08em);
}
.badge-status--draft    { background: var(--ui-quiet);   color: var(--ui-ink-muted); }
.badge-status--open     { background: var(--ui-quiet);    color: var(--ui-ink); }
.badge-status--closed   { background: var(--ui-quiet);  color: var(--ui-ink); }

/* ---- INSIGNE DE STARE: venit din kf-skin.css la B159 L10 (F1) ----
   Neprefixat, aceeasi specificitate ca regulile de baza → decide ordinea in text, exact
   precedenta pe care o dadea layerul inainte. */
  /* status badge → fill plat pătrat (flat, fără border). Numărătoarea de zile de pe afiș (`.cbc-days`) a plecat cu cardul vechi (B214). */
  .badge-status {
    border: 0; border-radius: var(--radius-status, 0);
    padding: .22rem .55rem; font-size: var(--font-xs); font-weight: 700;
    font-family: var(--kf-font-mono); letter-spacing: var(--type-status-tracking, .06em); text-transform: var(--type-status-case, uppercase);
    display: inline-flex; align-items: center;
  }
  .badge-status--active { background: var(--ui-live);  color: var(--ui-on-live); }
  .badge-status--done   { background: var(--ui-quiet); color: var(--ui-ink-muted); }

.badge-status--active   { background: var(--ui-live);  color: var(--ui-on-live); }
.badge-status--done     { background: var(--ui-quiet);    color: var(--ui-ink-muted); }

/* Badge status battle/bout */

/* `--over` = contorul „peste prag" din titlul „Calificați" (B187.1; fost `bg-danger` vopsit prin `--bs-danger-rgb`): același roșu. */
.badge-battle--progress,
.badge-battle--over      { background: var(--ui-live);  color: var(--ui-on-live); }
.badge-battle--completed { background: var(--ui-win); color: var(--ui-on-win); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.qual-tab .cat-panel-hdr .badge-battle--progress,
.qual-tab .cat-panel-hdr .badge-battle--over { color: var(--ui-on-live); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.qual-tab .cat-panel-hdr .badge-battle--completed { color: var(--ui-on-win-fill); }

/* 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(--ui-quiet);
    color: var(--ui-ink);
    text-decoration: none;
    display: inline-block;
    transition: background 0.1s;
}
.badge-category:hover { background: var(--ui-inverse); color: var(--ui-on-inverse); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.ecat__hdr .badge-category:hover { background: var(--ui-subtle); color: var(--ui-ink); }

/* 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(--ui-line);
    background: var(--ui-flat);
    color: var(--ui-ink);
    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  {    }
/* B234 (Arena): pastila APĂSATĂ = cerneala plină (inversul paginii); violetul rămâne al acțiunii principale. */
.filter-pill.active { background: var(--ui-inverse); color: var(--ui-on-inverse); border-color: var(--ui-inverse); }

/* ---- PAGINARE / PASTILE DE FILTRU: venit din kf-skin.css la B159 L10 (F1) ----
   Neprefixat, aceeasi specificitate ca regulile de baza → decide ordinea in text, exact
   precedenta pe care o dadea layerul inainte. */
  /* Paginare numere. Nota veche „scoped kf — nu atinge paginile legacy cu .filter-pill" NU mai e
     adevarata: toate template-urile care randeaza `.filter-pill` (home, arhiva, concursuri, clasament,
     admin/traduceri, `_pager`, `_tab_dansatori`) sunt azi pe pagini cu `kf`. Verificat la B159 L10 F1.
     `color`, `background` si variantele lor de stare n-au venit incoace: skinul le da intregi. */
  /* B234 (Arena): eticheta pastilei = majuscule 800, tracking deschis. */
  .filter-pill {
    font-family: var(--kf-font-mono); border: 1px solid var(--ui-line);
    border-radius: var(--radius-control, 0);
    font-weight: 800; text-transform: uppercase; letter-spacing: .04em;
  }


/* ── Paginare — SSOT pentru toate listele paginate (`_pager.html.twig`) ─────────────────────
   Trăiește lângă `.filter-pill` fiindcă din ea e făcută: paginile SUNT pastile, deci moștenesc
   gratis și ținta de atingere de 44px de la ≤640px (§16). Aici rămâne doar aranjamentul rândului
   plus separatorul de interval — restul e refolosire, nu componentă nouă.

   Pagina curentă e `<span>`, nu `<a>`: un link către pagina pe care ești deja e o țintă de tap
   care nu face nimic. `.filter-pill` acoperă ambele tag-uri (n-are selector de element). */
.pager      { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem; padding: .5rem; }
.pager__gap { font-family: var(--font-mono); font-size: var(--font-sm); color: var(--ui-ink-muted); padding-inline: .1rem; }
/* Săgețile poartă doar o iconiță: fără o lățime minimă ar fi mai înguste decât pastilele cu cifre
   și rândul s-ar citi neregulat. */
.pager__nav { justify-content: center; min-width: 2rem; }

/* Rândul tab-uri + filtru (/concursuri): nav-ul și pill-ul „Ale mele" pe aceeași linie, la aceeași
   înălțime vizuală.
   Pill-ul stă IMEDIAT DUPĂ tab-uri, nu împins la capătul opus (B68): cu `justify-content:
   space-between` rămânea singur în dreapta și se citea ca destinație de meniu, nu ca filtru al
   listei de dedesubt — exact raportul „nu se înțelege ce e". Gap-ul mai mare decât cel dintre
   tab-uri îl ține un grup distinct, fără să-l exileze. */
.tabs-row { display: flex; align-items: center; gap: clamp(.5rem, 2vw, 1.25rem); flex-wrap: wrap; margin-bottom: 1rem; }
.tabs-row .filter-pill { padding: .4rem .85rem; font-size: var(--font-xs); }
/* Contorul din pill = semnalul care îl face să se citească a FILTRU („câte rămân dacă apăs"), nu a
   buton. Îl scrie mine-filter.js: serverul nu-l poate calcula, filtrarea e client-side. Tabular ca
   să nu salte lățimea pill-ului la fiecare recalculare. */
.filter-pill__n { font-variant-numeric: tabular-nums; opacity: .65; }
/* Pe pastila ACTIVĂ contorul e plin: alb la 80% pe violet dădea 4.35:1 la 12px, sub 4.5 (B204). */
.filter-pill.active .filter-pill__n { opacity: 1; }

/* Pastila de TIER (rang / local), pe `/arhiva` și pe tabloul de bord. Clasă proprie tocmai ca să nu
   atingă `text-bg-*` din Bootstrap, care e `!important` în `@layer vendor`.
   Venită din `kf-skin.css` la B159 L10 (F1, prima familie deblocată de B178): acolo era singura ei
   definiție — nicio regulă de bază, nicio suprascriere de skin — deci mutarea e doar o schimbare de
   layer, cu valorile calculate neatinse. Tokenii `--kf-*` rămân ai ei până la promovarea din F3. */
.tier-pill {
    border: 0; border-radius: var(--radius-control, 0); padding: .2rem .5rem;
    background: var(--ui-quiet); color: var(--ui-ink-muted);
    font-family: var(--kf-font-mono); font-weight: 700; font-size: var(--font-xs);
    text-transform: var(--type-status-case, uppercase); letter-spacing: var(--type-status-tracking, .03em);
    display: inline-flex; align-items: center;
}
.tier-pill--rank { background: var(--ui-subtle); color: var(--ui-ink); }


/* === 5b. FOLDER TABS (segmented page tabs, lipite de conținut) === */
.folder-tabs {
    align-items: flex-end;
}
.folder-tab {
    line-height: 1.3; text-decoration: none; cursor: pointer;
}

/* ---- TAB-URI DE PAGINA: venit din kf-skin.css la B159 L10 (F1) ----
   Neprefixat, aceeasi specificitate ca regulile de baza → decide ordinea in text, exact
   precedenta pe care o dadea layerul inainte. */
  /* ---- Folder tabs → B234 (Arena): tab-uri SUBLINIATE pe un fir comun (nu pistă tonală) ---- */
  .folder-tabs {
    display: flex; flex-wrap: wrap; gap: 1.25rem;
    margin-bottom: var(--kf-5);
    padding: 0; border-radius: 0; box-shadow: inset 0 -1px 0 var(--ui-hair);
    width: fit-content; max-width: 100%;
  }
  .folder-tab {
    border: 0; margin: 0;
    border-radius: 0;
    padding: 0 0 .6rem;
    /* B234 (Arena): tabul de PAGINĂ = titlu condensat, 900, mărimea `--ar-fs-tab`; rolul `tab` deține cazul și tracking-ul. */
    font-family: var(--font-display); font-stretch: var(--ar-wdth);
    font-weight: 900; font-size: var(--ar-fs-tab); text-transform: var(--type-tab-case, uppercase); letter-spacing: var(--type-tab-tracking, .06em);
    color: var(--ui-ink-muted);
    background: transparent;
    display: inline-flex; align-items: center; gap: .4rem;
    min-height: var(--tap-min);   /* B212.2: tabul de pagină = navigație principală pe telefon (avea 32px) */
    transition: none;
  }
  @media (hover: hover) { .folder-tab:not(.active):hover { color: var(--ui-ink); } }
  /* Tabul activ = cerneala + sublinierea de 3px în umplerea de identitate (semn grafic, ADR 0057). */
  .folder-tab.active {
    color: var(--ui-ink);
    box-shadow: inset 0 -3px 0 var(--ui-accent-fill);
  }



/* === 5c. RAIL — o bandă care SCROLLEAZĂ pe orizontală ========================================
   SSOT al mecanicii. Era scrisă de doua ori (`.tline__rail` mai jos in fisier, `.cat-strip` in
   scoreboard.css), iar banda de tab-uri din admin ar fi fost a treia copie. Regula scrisa:
   UI_RULES „Tab-urile stau pe UN rand care scrolleaza, niciodata pe doua".

   Mecanica si ESTOMPAREA sunt clase SEPARATE, pentru ca nu merg mereu impreuna:
     `.rail`      = deruleaza + ascunde bara de scroll  → benzi de tab-uri (au cap + sageti)
     `.rail-fade` = doar masca de margine               → containere care isi PASTREAZA bara
                                                          (la un tabel bara E afordanta, nu zgomot)
   ⚠️ NU declara `padding-inline` aici: `.tline__rail` isi pune singur revarsarea (`--tline-bleed`)
      si, fiind mai jos in acelasi fisier, o regula de aici i-ar bate-o.
   ⚠️ NU `justify-content: center` la consumatori: centrarea continutului impinge inceputul la
      offset NEGATIV = zona inaccesibila. Se centreaza CUTIA (width: fit-content; margin-inline: auto). */
.rail {
    /* `nowrap` e valoarea inițială, dar e scrisă explicit fiindcă e CONTRACTUL benzii: un rail care
       ajunge să se împacheteze pe două rânduri nu mai e rail. (Inertă pe consumatorii care nu
       sunt flex, ex. wrapperul de tabel.) */
    flex-wrap: nowrap;
    overflow-x: auto; overscroll-behavior-x: contain;
    scroll-snap-type: x proximity; scroll-padding-inline: .5rem;
    scrollbar-width: none;
}
.rail::-webkit-scrollbar { display: none; }

/* Masca spune IN CE PARTE mai e continut. Starea vine din `data-ov`, pus de controllerul `rail`
   (stare in CSS, nu in JS: JS-ul raporteaza faptul, CSS-ul decide aspectul). Masca lucreaza pe
   canalul ALFA — `black`/`transparent` de aici nu sunt culori de brand, ci opacitate.
   ⚠️ Nu e gratuita: `mask-image` diferit de `none` creeaza stacking context si promoveaza
   elementul la strat compus, deci antialiasingul textului cade pe grayscale. De-aia clasa se pune
   DOAR pe benzile care chiar primesc `data-ov`, niciodata „pentru orice eventualitate".
   Selectorul acopera ambele cazuri: controllerul poate sta pe un stramos SAU pe banda insasi
   (Stimulus permite controller si target pe acelasi element). */
.rail-fade { --rail-fade-l: 0px; --rail-fade-r: 0px;
    mask-image: linear-gradient(to right,
        transparent 0, black var(--rail-fade-l),
        black calc(100% - var(--rail-fade-r)), transparent 100%);
}
[data-ov~="l"] .rail-fade, .rail-fade[data-ov~="l"] { --rail-fade-l: 1.75rem; }
[data-ov~="r"] .rail-fade, .rail-fade[data-ov~="r"] { --rail-fade-r: 1.75rem; }

/* Capul benzii: NUMESTE controlul, spune CATE elemente sunt si da sageti de derulare. Fara el, o
   banda care scrolleaza e invizibila ca mecanism pe telefon: omul vede doua elemente si n-are de
   unde sti ca mai exista trei (raport user 2026-08-15). Markup-ul = macro `_rail.html.twig`. */
.rail-nav__hd  { display: flex; align-items: center; justify-content: space-between; gap: .5rem; padding-bottom: .15rem; }
.rail-nav__lbl { display: inline-flex; align-items: baseline; gap: .35rem; color: var(--ui-ink-muted); }
.rail-nav__n {
    font-family: var(--font-mono); font-size: var(--font-2xs); font-weight: 700;
    background: var(--ui-subtle); color: var(--ui-ink-muted);
    border: 1px solid var(--ui-hair); padding: 0 4px;
}
/* `hidden` in markup = starea implicita FARA JS (sagetile n-ar face nimic). Controllerul il scoate
   doar cand banda chiar depaseste. `display: flex` pierde in fata lui `[hidden]` prin reboot-ul Bootstrap
   (`[hidden] { display: none !important }`, @layer vendor) — o regula `[hidden]` aici n-ar avea efect. */
.rail-nav__arrows { display: flex; gap: .2rem; }
.rail-nav__ar {
    display: inline-flex; align-items: center; justify-content: center;
    width: 1.5rem; height: 1.5rem; padding: 0;
    border: 1px solid var(--ui-line); background: var(--ui-flat);
    color: var(--ui-ink); cursor: pointer; line-height: 1;
}
.rail-nav__ar:hover:not(:disabled) { background: var(--ui-quiet); color: var(--ui-ink); border-color: var(--ui-ink); }
.rail-nav__ar:disabled { opacity: .35; cursor: default; }
/* „‹ ›" la CAPETELE benzii (B218 → B219, ADR 0059; macroul `rail.more(dir)`): indiciile de derulare pe RÂNDUL
   elementelor, peste primul / ultimul element tăiat — ținta de 44px pentru cine nu trage cu degetul. Absolute
   față de `.rail-nav__row` (învelitoarea rândului, de mai jos), NU față de `.cat-nav`: acela e `sticky` și, pus
   `relative`, și-ar pierde lipirea; iar față de el butoanele ar fi acoperit și capul benzii. `hidden` în markup =
   starea fără JS; controllerul le arată doar cât mai e conținut în direcția lor (fără regulă `[hidden]` aici:
   reboot-ul Bootstrap o bate cu `!important`). Gradientul din fundalul paginii întărește estomparea
   `.rail-fade`; cercul tonal e ținta VĂZUTĂ, butonul întreg ținta reală. */
/* RÂNDUL benzii = blocul conținător al butoanelor „‹ ›" (B219, raportul ownerului: „umbrele laterale au rămas la mărimea veche, mai
   mici decât pastilele"): butoanele erau fixate la 44px și pastilele au crescut la 52px cu rândul de diviziuni. Legate de rând
   (`top: 0; bottom: 0`), gradientele acoperă MEREU toată înălțimea pastilelor, oricât ar fi ea — nu o cifră ghicită. Învelitoarea e
   DOAR `position: relative`, nu e lipicioasă; `.cat-nav` rămâne sticky deasupra ei. */
.rail-nav__row { position: relative; }
.rail-nav__more {
    position: absolute; right: 0; top: 0; bottom: 0;
    width: var(--tap-min); min-height: var(--tap-min); padding: 0; border: 0;
    display: grid; place-items: center; cursor: pointer;
    background: linear-gradient(to right, transparent, var(--ui-page) 45%); color: var(--ui-ink);
    font-size: var(--font-lg);
}
.rail-nav__more .bi {
    display: grid; place-items: center; width: 1.75rem; height: 1.75rem;
    border-radius: 50%; background: var(--ui-raised); box-shadow: var(--ui-shadow-raised);   /* B226: pe pagină — tonul cardului */
}
.rail-nav__more:hover .bi { background: var(--ui-quiet); }
/* „‹" (B219, decizia ownerului: săgețile stau DOAR peste rând, pe ambele părți): oglinda lui „›" la stânga — gradientul se întoarce,
   ca ultimul / primul element tăiat să se estompeze spre butonul lui. Apare abia după prima derulare (controllerul: `left`). */
.rail-nav__more--prev { right: auto; left: 0; background: linear-gradient(to left, transparent, var(--ui-page) 45%); }


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

/* Chip competitor inline */


/* Formularul de eliminare al unui jurat / om din line-up (pe editare). Chipul de jurat de dinainte (`.judge-chip`) a plecat — fără consumator. */
.judge-chip__del-form { display: inline; line-height: 0; }
/* 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(--ui-win-ink); }
.exhint--warn { color: var(--ui-warning); }
.exhint--err  { color: var(--ui-danger); font-weight: 600; }


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

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

/* Banda colorată de sus a ușilor de pe prima pagină (`.hub-strip`) a plecat la B214 — ușile sunt `.home-door` (base-layout §17).
   `.hub-card` RĂMÂNE: confirmarea înscrierii și pagina de gestionare a înscrierii îl folosesc. */

/* ---- CONTUL MEU + ACTIUNI DE CATEGORIE + USILE: venit din kf-skin.css la B159 L10 (F1) ----
   Neprefixat, aceeasi specificitate ca regulile de baza → decide ordinea in text, exact
   precedenta pe care o dadea layerul inainte. */
  /* ═══════════ DASHBOARD „Contul meu" /cont (scoped body.kf) ═══════════ */

  /* Page header → titlu display + acțiune dreapta, hairline jos */
  .page-header {
    display: flex; align-items: flex-end; justify-content: space-between;
    flex-wrap: wrap; gap: var(--kf-3);
    border-bottom: 1px solid var(--ui-hair); padding-bottom: var(--kf-3); margin-bottom: var(--kf-5);
  }
  .page-header__title {
    font-family: var(--kf-font-display); font-weight: var(--type-display-weight, 900); font-stretch: var(--ar-wdth);
    font-size: clamp(2.5rem, 1rem + 5cqi, 5.5rem); line-height: .9; letter-spacing: var(--type-display-tracking, .01em); text-transform: var(--type-display-case, uppercase);
    color: var(--ui-ink); margin: 0;
  }

  /* Familia BUTOANELE INK a plecat in base-layout.css la B159 L10 (F1). */


  /* Card profil organizator → flat hairline */
  .acct-card {
    border: 1px solid var(--ui-hair); border-radius: var(--radius-card, 0);
    padding: var(--kf-3) var(--kf-4);
  border-color: var(--ui-frame); }
  .acct-card__ico { color: var(--ui-ink-muted); }
  .acct-card__name {
    font-family: var(--kf-font-display); font-weight: var(--type-title-weight, 900); text-transform: var(--type-title-case, uppercase);
    letter-spacing: var(--type-title-tracking, .02em); font-size: var(--font-xl); color: var(--ui-ink);
  }
  .acct-card__email { font-family: var(--kf-font-mono); font-size: var(--font-sm); color: var(--ui-ink-muted); }
  .acct-form { border-top: 1px solid var(--ui-hair); }
  .acct-form__lbl {
    font-family: var(--kf-font-mono); font-size: var(--font-2xs); font-weight: 700;
    text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .05em); color: var(--ui-ink-muted);
  }
  .acct-card .form-control {
    background: var(--ui-flat); border: 1px solid var(--ui-line);
    /* ⚠️ `border-radius: var(--radius-field, 0)` RAMANE desi nu se randeaza azi (regula generica a
       campurilor e mai specifica in lant): e ULTIMUL call-site din tot repo-ul al rolului de forma
       `field`, iar un rol fara cititor moare — `TypeRoleTokensTest` il cere. Fallbackul e colțul de
       azi. Stearsa o data de ucigasul de treziri la B159 L10 (F3), pusa la loc cu motivul. */
    border-radius: var(--radius-field, 0);
    color: var(--ui-ink); font-family: var(--kf-font-mono); font-size: var(--font-md); box-shadow: none;
  }

  /* Rând de arhivă (/arhiva) — afiș portret + coloană de text.
     AICI stă DOAR ce un token nu poate exprima: fontul mono, uppercase, filtrul grayscale→color
     și fundalul paginii. Bordurile, razele (=0) și suprafețele vin gratis din remap-ul global de
     tokeni de mai sus — NU scrie reguli de culoare pentru ele. Dimensiunile (aspect-ratio, clamp,
     container query) rămân în @layer app: kf-ul e o piele, nu un layout. */
  /* Familia `.arch-*` a plecat in base-layout.css § „Arhiva publica" la B159 L10 (F1): fiecare
     declaratie kf adauga o proprietate pe care regula de baza n-o avea, deci a fost o reuniune
     curata, fara conflict.
     Cele doua reguli de `filter` (grayscale pe afis + revenirea la hover) NU s-au mutat: erau MOARTE.
     `body.skin-modern .arch-poster img { filter: none }` statea in `@layer skin`, care batea
     `@layer components` inaintea specificitatii — deci nici macar regula de hover nu ajungea la
     element. Odata cu ele, `filter: none` a ramas fara ce sa anuleze si a disparut la F2. */

  /* Familia TABEL DE CALIFICARE a plecat in components.css la B159 L10 (F1). */

  /* `.tier-pill` a plecat în components.css § 5 la B159 L10 (F1): era singura ei definiție din tot
     repo-ul, deci mutarea n-a fost decât o coborâre de layer. B178 a deblocat-o — până atunci ieșea
     din scopul `body.kf` al trecerii de reguli și producea chei fantomă. */

/* Coborata din `@layer skin` la B159 L10 (F2). */
.btn-dark { --bs-btn-color: var(--ui-on-accent-fill); --bs-btn-bg: var(--ui-accent-fill); --bs-btn-border-color: var(--ui-accent-fill); --bs-btn-hover-color: var(--ui-on-accent-fill); --bs-btn-hover-bg: var(--ui-accent-fill-hover); --bs-btn-hover-border-color: var(--ui-accent-fill-hover); --bs-btn-active-color: var(--ui-on-accent-fill); --bs-btn-active-bg: var(--ui-accent-fill-hover); --bs-btn-active-border-color: var(--ui-accent-fill-hover); --bs-btn-disabled-color: var(--ui-ink-muted); --bs-btn-disabled-bg: var(--ui-quiet); --bs-btn-disabled-border-color: var(--ui-quiet); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.tab-actions .btn-dark { --bs-btn-color: var(--ui-ink); --bs-btn-bg: var(--ui-quiet); --bs-btn-border-color: var(--ui-line); --bs-btn-hover-color: var(--ui-ink); --bs-btn-hover-bg: color-mix(in srgb, var(--ui-ink) 12%, var(--ui-quiet)); --bs-btn-hover-border-color: var(--ui-line); --bs-btn-active-color: var(--ui-on-pressed); --bs-btn-active-bg: var(--ui-pressed); --bs-btn-active-border-color: var(--ui-pressed-edge); --bs-btn-disabled-color: var(--ui-ink-muted); --bs-btn-disabled-bg: transparent; --bs-btn-disabled-border-color: var(--ui-edge); }

  /* Editează profil → outline hairline mono transparent */
  .acct-card .btn-outline-secondary {
    border-radius: var(--radius-control, 0); border: 1px solid var(--ui-line);
    font-family: var(--kf-font-mono); font-weight: 700; font-size: var(--font-xs);
    text-transform: var(--type-control-case, uppercase); letter-spacing: var(--type-control-tracking, .04em);
    transition: none;
  border-color: var(--ui-line); color: var(--ui-ink); background: var(--ui-quiet); }
  /* `background`, `color` si tot hover-ul au plecat: skinul le da intregi. */

  /* Familia LANDING / HERO a plecat in base-layout.css la B159 L10 (F1). */



  /* Hub cards (confirmarea + gestionarea înscrierii) → flat hairline */
  .hub-card {
    /* `--kf-border` era `1px solid var(--kf-line)`: ramane 1px, culoarea vine din paleta de azi
     (coborata din `@layer skin` la B159 L10, F2). */
    border: 1px solid var(--ui-frame); border-radius: var(--radius-card, 0);
    transition: none;
  box-shadow: var(--ui-shadow-float); }


/* 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` (confirmare / gestionarea înscrierii) e alt component. */

/* === Cont organizator (profil) === */
.acct-card {
    display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem;
background: var(--ui-raised); }
.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); }
.acct-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: .6rem; padding-top: .6rem; margin-top: .5rem; }
.acct-form__row { display: flex; flex-direction: column; gap: .15rem; flex: 1 1 220px; }
.acct-form__actions { flex: 0 0 auto; }



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

.form-label-xs {
    font-family: var(--font-display);
    font-size: var(--font-xs);
    font-weight: var(--type-label-weight, 900);
    text-transform: var(--type-label-case, uppercase);
    letter-spacing: var(--type-label-tracking, 0.08em);
    color: var(--ui-ink-muted);
    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;
}

/* === GRUPURI DE CÂMPURI într-un rând dens (B144) ============================================
   Rândul de configurare al unei categorii avea 14 câmpuri într-un singur `.form-row-compact`:
   identitatea, calificarea, battle-ul și afișajul amestecate, iar `flex-wrap` rupea rândul prin
   mijlocul unui cluster. Aici câmpurile intră în grupuri cu nume, iar ruptura cade ÎNTRE ele.

   Separatorul e GAP-ul, nu o linie: o hairline verticală ar rămâne orfană când grupul cade pe
   rândul lui pe telefon și ar cere un `@media` ca s-o ștergem (UI_RULES: „un nivel = un mecanism",
   breakpoint dur = ultim resort). Capul de grup e mecanismul.

   Grupul se STRÂNGE înainte să cadă: câmpurile lui se înfășoară în interior (`.fgroup__b` are
   wrap), fiindcă `min-width: 0` îl lasă să coboare sub min-content. Fără el, minimul automat al
   unui flex item e min-content și nimic nu se micșorează. */
/* RÂNDURI LOGICE, nu o grilă de celule (rescris 2026-09-04, it. 4). Am încercat, în ordine: șir
   plat, grupuri-cutie (câmpuri decalate între grupuri — respins), grilă uniformă de celule (toate
   câmpurile ajungeau la aceeași lățime, deci „prea lungi" — respins). Ce a rămas e cel mai simplu
   lucru care le face pe toate: TREI `.form-row-compact` una sub alta, fiecare cu înțelesul ei —
   identitate · calificare+runde · reguli de battle — plus banda de premii.

   Fiecare câmp e cât conținutul lui (eticheta sau controlul, care e mai lat), iar la îngustare
   câmpurile pică unul câte unul, în interiorul rândului lor. Gruparea se citește din VECINĂTATE și
   din ruptura dintre rânduri, fără nicio cutie și fără niciun cap de secțiune.

   `.frow-sep` = hairline subțire între rânduri: separă fără să adauge înălțime cât un cap de grup. */
.frow-sep { border-top: 1px solid var(--ui-hair); padding-top: 0.45rem; margin-top: 0.15rem; }
/* Stepperele de fază vin dintr-un `<template>` clonat într-un container: `display: contents` le
   scoate pe fiecare direct în rând, ca să curgă lângă restul câmpurilor. */
.phases-cell { display: contents; }
/* Nota „se recalculează la salvare" de lângă rundele de fază (/edit): fazele se regenerează abia la
   salvare, fiindcă inputurile sunt cheiate pe id-urile config-urilor EXISTENTE. */
.frow-note { align-self: center; font-size: var(--font-xs); color: var(--ui-warning); }
/* Glosa unui RÂND întreg (nu a unui câmp): `flex: 1 1 100%` o rupe pe linia ei în `.form-row-compact`,
   deci nu îngustează niciun câmp. Scrisă permanent — spre deosebire de ⓘ, care explică UN câmp — de
   aceea câmpul care ar fi purtat același text nu mai primește ⓘ (ar deschide ce scrie deasupra lui). */
.frow-gloss { flex: 1 1 100%; margin: 0; font-size: var(--font-xs); line-height: 1.3; color: var(--ui-ink-muted); }

/* ⓘ stă ABSOLUT în colțul câmpului, pe linia etichetei: în flux ar fi ocupat o celulă de grilă
   întreagă doar pentru o iconiță. La ÎNCEPUTUL etichetei, nu la sfârșit (it. 5): la dreapta, cutia de
   24px călca peste text (eticheta rezerva 1.25rem = 20px) și stătea după cuvânt, adică se citea după
   ce deja aveai nevoie de ea — raportat de owner: „semnele ⓘ stau peste scris și în față".

   Cutia de ATINGERE rămâne `--tap-aa` (24px, podeaua WCAG 2.2 SC 2.5.8 AA — vezi UI_RULES „Ținte
   touch": sub 24px nu se coboară). Se micșorează doar GLIFA, iar cutia se centrează pe linia
   etichetei (`top: -5px`), ca surplusul ei de înălțime să cadă în gap-ul de deasupra rândului, nu peste
   control. `flex-start` lipește glifa de marginea stângă — centrată într-o cutie de 24px ar fi lăsat o
   gaură între ea și cuvânt. */
.fhint {
    position: absolute; top: -5px; left: 0; z-index: 2;
    display: inline-flex; align-items: center; justify-content: flex-start;
    min-width: var(--tap-aa); height: var(--tap-aa); padding: 0;
    border: 0; background: none; color: var(--ui-ink-muted); font-size: var(--font-xs);
}
.fhint:hover, .fhint:focus-visible { color: var(--ui-inverse); }
/* Rezerva de pe etichetă stă LÂNGĂ `.form-field > label`, mai jos în fișier — nu aici. Pusă aici,
   era ștearsă tăcut de shorthandul `padding: 0` al regulii de bază: aceeași specificitate (0,1,1),
   același layer, deci decidea ordinea din fișier. Vezi comentariul de la `.form-field--hinted`. */
/* Clasa, nu atributul `hidden`: reboot-ul Bootstrap are `[hidden]{display:none!important}`, deci o
   cutie ascunsă cu `hidden` n-ar mai putea fi deschisă din CSS. */
/* Cutia PLUTEȘTE peste conținut (absolut), nu în flux: în flux, deschiderea ei împingea rândul
   următor și lăsa o gaură mare la închidere — raportat de owner („când apare lasă spațiu mare pe
   următorul rând"). Un strat care se deschide și se închide nu are voie să miște layoutul. */
.fhint__box {
    display: none;
    position: absolute; top: 100%; left: 0; z-index: 20;
    width: max-content; max-width: min(20rem, 70vw);
    margin-top: 2px; padding: 0.35rem 0.5rem;
    font-size: var(--font-xs);
}
/* ASPECTUL stratului care plutește la cerere — o singură rețetă pentru explicația ⓘ de aici și bula cu membrii unei echipe
   (`.e-members`, pastila de înscris, B204). Poziția și deschiderea rămân ale fiecăruia. */
.fhint__box,
.e-members {
    background: var(--ui-raised); border: 1px solid var(--ui-float-edge); border-radius: var(--radius-sm);
    box-shadow: var(--ui-shadow-float);
    line-height: 1.35; color: var(--ui-ink);
}
.fhint__box.is-open { display: block; }
.judge-inline-row,
.staff-inline-row { display: flex; gap: 0.4rem 0.5rem; align-items: flex-end; flex-wrap: wrap; }

/* Grila juraților (edit + builder): 4 coloane Nume · Rol/Sistem · Țară · × cu headerele O DATĂ în
   cap. Coloanele trebuie să se alinieze ÎNTRE rânduri → UN grid pe CONTAINER, iar rândurile
   (.judge-inline-row) devin display:contents ca celulele tuturor să curgă în același grid
   (UI_RULES: ce se aliniază între frați nu poate sta în interiorul lor). Fără wrap până la 320px:
   coloanele fixe ≈ 168px, numele ia restul și taie cu ellipsis. */
.jgrid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(5.5rem, 8.5rem) 2.4rem 1.5rem; gap: 4px 6px; align-items: center; }
.jgrid > .judge-inline-row,
.jgrid > .staff-inline-row,
.jgrid > .jgrid-rows,
.jgrid > .jgrid-rows > .judge-inline-row,
.jgrid > .jgrid-rows > .staff-inline-row { display: contents; }
.jgrid__h { font-size: var(--font-2xs); font-weight: 700; text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .06em); color: var(--ui-ink-muted); }
.jgrid__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--font-sm); }
.jgrid__span { grid-column: 1 / -1; }   /* „Fără jurați." peste toate coloanele */
/* lățimile utilitare cedează coloanelor grilei */
.jgrid .input-w-system { min-width: 0 !important; width: 100%; }
.jgrid .input-w-role { width: 100% !important; }
.jgrid .input-w-name { max-width: none !important; }
/* rolul static al staff-ului existent — aceeași pastilă ca la juratul blocat */
.jgrid .chip-system { font-size: var(--font-xs); color: var(--ui-ink-muted); background: var(--ui-subtle); padding: 0 3px; border-radius: var(--radius-sm); justify-self: start; }
.jgrid .ac-wrap { width: auto; min-width: 0; }
.jgrid .form-field, .jgrid .jr-sys { min-width: 0; }
/* selectul doar-steag e mult mai îngust în grilă (globalul 3.4rem rămâne pt. formularele de înscriere) */
.jgrid .cs--flag { width: 2.4rem !important; padding-left: .15rem !important; padding-right: .15rem !important; }
/* HEAD = doar subliniat, nu chip (feedback 2026-08-17) */
.jhead { text-decoration: underline; text-underline-offset: 2px; font-weight: var(--type-label-weight, 900); font-size: var(--font-2xs); letter-spacing: var(--type-label-tracking, .04em); }

/* === 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; position: relative; }
/* `margin: 0` DA, `padding: 0` NU. Shorthandul era defensiv (nici UA, nici reboot-ul Bootstrap nu
   dau padding unui `<label>`) și ștergea tăcut rezerva pentru ⓘ: `.form-field--hinted > label` are
   EXACT aceeași specificitate (0,1,1) și același layer, deci câștiga cine era mai jos în fișier.
   A costat două iterații — o dată ca `padding-right` (B144), o dată ca `padding-left` (B146), în
   ambele cazuri fără niciun efect. Emitentul șters, nu specificitatea ridicată. */
.form-field > label {
    margin: 0;
    font-family: var(--font-sans); font-weight: 600; font-size: var(--font-sm);
    color: var(--ui-ink-muted); line-height: 1.15; white-space: nowrap;
}
/* Eticheta începe după iconiță, ca să nu treacă pe sub ea (glifă ~11px + aer). Stă IMEDIAT sub
   regula de bază: relația dintre ele e fragilă și trebuie să se vadă la citit. */
.form-field--hinted > label { padding-left: 1.05rem; }
.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; 
    color: var(--ui-ink-muted); cursor: not-allowed;
    opacity: 1;  /* anulează estomparea Bootstrap pe select — dashed+muted e deja semnalul */
}
/* Selectul dezactivat = același aspect ca inputul dezactivat de dinainte (ADR 0049: blocat =
   ACELAȘI control, `disabled`, fără `name`) — fără caret, că nu e nimic de deschis. */
.form-field > .form-select:disabled { background-image: none; }
.form-field:has(> :disabled) > label { color: var(--ui-ink-muted); }
.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-grow  { flex: 1 1 9rem; }
.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: var(--type-number-tracking, .04em); color: var(--ui-ink-muted); }
.prize-line .bi-trophy-fill { color: var(--ui-rank-gold-ink); }

/* Anvergura concursului — UN câmp cu DOUĂ coloane sub aceeași etichetă („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.
   FĂRĂ chenare per zonă (feedback 2026-08-16): două rame = doi „câmpi" în capul userului — voia
   să completeze amândouă. Coloanele sunt despărțite de O hairline; selecția = pastila inversată
   + BIFĂ (se citește fără percepția culorii); zona de clasament se distinge prin header
   (trofeu + primary). Fostul :has(:checked) pe zonă = semnal mort oricum (--paper-2 și
   --surface-2 se remapează la același --kf-surface-bright). */
.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(--ui-ink-muted); line-height: 1.15;
}
.tier-pick__zones { display: grid; grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); gap: .5rem .9rem; }
.tier-pick__zone { min-width: 0; }
.tier-pick__zone--rank { border-left: 1px solid var(--ui-hair); padding-left: .9rem; }
.tier-pick__head {
    font-size: var(--font-2xs); font-weight: 700; text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .06em);
    color: var(--ui-ink-muted); margin-bottom: .35rem;
}
.tier-pick__zone--rank .tier-pick__head { color: var(--ui-inverse); }
.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(--ui-line); background: var(--ui-flat); color: var(--ui-ink-muted);
    cursor: pointer; margin: 0;
}
.tier-pick__opt .tier-pick__check { display: none; }
.tier-pick__opt:hover {  color: var(--ui-ink);  }
.tier-pick__input:checked + .tier-pick__opt { background: var(--ui-accent-fill); color: var(--ui-on-accent-fill); border-color: var(--ui-accent-fill); }
.tier-pick__input:checked + .tier-pick__opt .tier-pick__check { display: inline; }
.tier-pick__input:focus-visible + .tier-pick__opt { outline: 2px solid var(--ui-inverse); 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.
   FĂRĂ overflow:hidden: reteza dropdown-ul de autocomplete al rândurilor de jurat (aceeași
   poveste ca F6/.ccard, 2026-08-06), iar sub remap-ul kf radius-ul e 0 — clipul nu rotunjea
   nimic. Dacă radius-ul revine vreodată, clipul se mută pe __head, nu înapoi aici. */
.form-panel {
    border: 2px solid var(--ui-line);
    border-radius: var(--radius-lg);
    background: var(--ui-raised);
    display: flex;
    flex-direction: column;
border-color: var(--ui-frame); border-width: 1px; }
.form-panel__head {
    /* Antetul e PICTAT, iar panoul are colt rotunjit: fara asta, banda patrata acopera coltul ramei (semnalat de
       owner la V-ul B159 L6b: „colturile sunt acoperite, nu se vad"). `inherit` ia chiar raza panoului, deci merge
       in toate lumile: 0 pe kf (unde panoul e patrat), raza cardului pe skinul modern. `overflow: hidden` pe panou
       NU e o optiune: `.fhint__box` e pozitionat absolut si iese din panou. */
    border-start-start-radius: inherit; border-start-end-radius: inherit;
    background: var(--ui-raised);   /* B226: capul atinge pagina — tonul panoului; linia de 2px de dedesubt îl desparte de corp */
    color: var(--ui-accent);   /* G1 (ADR 0057): titlul panoului de formular pe identitate */
    border-bottom: 2px solid var(--ui-line);
    font-family: var(--font-display);
    font-weight: var(--type-label-weight, 900);
    text-transform: var(--type-label-case, uppercase);
    letter-spacing: var(--type-label-tracking, 0.04em);
    font-size: var(--font-sm);
    padding: 0.5rem 0.75rem;
    display: flex;
    align-items: center;
border-bottom-color: var(--ui-hair); }
.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(--ui-flat); 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 `--container-max` (0-2-0 vs 0-1-0), nu prin ordinea fișierelor — motivarea „vine mai
   târziu în fișier" era greșită: sunt fișiere diferite. 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>). */
/* ── ANTETUL DE SALĂ (iter. 2o) ──
   Antetul normal ȘI banda de categorii DISPAR pe proiector; le ia locul `.proj-head`, o singură
   linie cu concursul, categoria de pe scenă și faza. Motivul e de citit din fundul sălii: antetul
   căra afiș, meta, butoane de birou; banda arăta cinci categorii dintre care patru nu sunt pe scenă
   acum. Sala are nevoie de trei lucruri, nu de o navigație.
   ⚠️ CONSECINȚĂ pe ADR 0019 §6: „ecranul se comandă din click-uri" nu mai e adevărat pe proiector —
   fixarea manuală pe o categorie se făcea tocmai prin click pe bandă. Urmărirea automată
   (`judgingActiveAt`) rămâne mecanismul principal, iar fixarea rămâne posibilă din ADRESĂ (URL-ul
   canonic al categoriei + `?proiector=1`), adică exact ce făcea butonul „Fixează". Comutatorul
   „Urmărește" din `.proj-zoom` rămâne, fiindcă un ecran deschis pe un URL fixat trebuie să se poată
   întoarce la urmărire. Decizie a userului, consemnată aici ca să nu pară o scăpare. */
.live-projector .res-hero,
.live-projector .cat-nav { display: none; }
/* Antetul de sală: randat doar cu `?proiector=1`, dar ascuns și din CSS ca regula de mod să fie
   completă într-un singur loc (dacă mâine se randează necondiționat, nu apare pe pagina publică). */
.proj-head { display: none; }
/* FĂRĂ linie despărțitoare, nici între segmente, nici sub rând (cererea userului): separă MĂRIMEA
   și spațiul. O riglă în plus pe un ecran care are deja rigla tab-urilor dedesubt e al doilea
   contur concentric, nu un ajutor de citire. */
/* AȘEZAREA: concursul la STÂNGA, categoria la MIJLOC, faza la DREAPTA — trei poziții, trei roluri,
   fiecare acolo unde o cauți. Se face din flex, nu din grid cu coloane fixe: laturile primesc
   `flex: 1 1 0` (spațiu egal), deci categoria cade la mijloc oricât de lungi ar fi numele, iar faza
   se lipește de marginea dreaptă prin `text-align`. Rămâne `flex-wrap`, deci pe ecran îngust cade
   pe rânduri în loc să se strivească.
   FĂRĂ linie despărțitoare, nici între segmente, nici sub rând (cererea userului).

   O SINGURĂ MĂRIME pentru toate trei (`--proj-head-fs`). Prima livrare le dăduse trei trepte
   diferite — concursul mic, categoria uriașă — și userul a respins-o pe bună dreptate: pe un rând
   citit de la distanță, mărimile inegale se citesc ca trei ecrane lipite, nu ca o propoziție.
   Diferența de ROL o poartă FAMILIA (mono vs display), NUANȚA și POZIȚIA, nu scara și nu o umplere.
   Un singur `clamp` = un singur loc de calibrat dacă mai trebuie urcat/coborât. */
.live-projector .proj-head {
    --proj-head-fs: clamp(var(--font-xl), 2.3vw, var(--font-6xl));
    display: flex; flex-wrap: wrap; align-items: center;
    gap: .35rem clamp(.75rem, 2.5vw, 2.5rem);
    min-width: 0;
}
/* Concursul: mono, ca să se distingă de categorie prin FAMILIE, nu prin mărime. */
.proj-head__contest {
    flex: 1 1 0; min-width: 0;
    font-family: var(--font-mono); font-weight: 700;
    text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .06em);
    font-size: var(--proj-head-fs); color: var(--ui-ink);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Categoria = subiectul ecranului. Rețeta era cea a tabului de categorie până la B218 (de atunci pastila
   `.cat-strip__l1` e display 600 / `--font-base` / fără majuscule — antetul de sală își ține rețeta de ETICHETĂ
   de mai sus): numele stilului și formatul la ACEEAȘI mărime, lipite, formatul doar cu altă nuanță
   (`--text-faint`), gap `.35rem`. Umplerea volt a fost încercată și RESPINSĂ de user — fundalul verde
   trage prea mult atenția pe un ecran de sală, unde accentul trebuie păstrat pentru ce se schimbă
   (starea battle-ului), nu pentru o etichetă care stă acolo toată categoria.
   Rândul se citește deci CONTINUU: aceeași mărime peste tot, rolurile din familie și poziție. */
.proj-head__cat {
    flex: 0 1 auto; min-width: 0;
    display: inline-flex; align-items: baseline; flex-wrap: wrap; gap: 0 .35rem;
    color: var(--ui-ink);
    font-family: var(--font-display); font-weight: 900;
    text-transform: uppercase; letter-spacing: .01em;
    font-size: var(--proj-head-fs); line-height: 1.15;
}
/* Formatul (2vs2) e calificativ, nu nume: o treaptă mai jos, dar pe ACEEAȘI cerneală — pe umplerea
   volt, `--text-secondary` ar fi ieșit dintr-o altă pereche de contrast. */
.proj-head__fmt { color: var(--ui-ink-muted); }
/* Discriminatorii (U18, FEMALE) vin din partialul comun — aceeași cerneală ca restul pastilei. */
.live-projector .proj-head__cat .cat-disc { font-size: 1em; letter-spacing: .04em; color: var(--ui-ink-muted); }
/* Faza, la marginea DREAPTĂ: display 900, aceeași mărime, fără fill — perechea „ce categorie /
   unde am ajuns" se citește din poziție și familie, nu din a doua culoare. */
.proj-head__phase {
    flex: 1 1 0; text-align: right;
    font-family: var(--font-display); font-weight: 900;
    text-transform: uppercase; letter-spacing: .03em;
    font-size: var(--proj-head-fs); line-height: 1.15; color: var(--ui-ink);
}
/* B195 L3: în dreapta antetului, STAREA în locul fazei. `Live` = pilula `.now-tag` (SSOT pentru „acum"), adusă la
   mărimea rândului (decizia ownerului: UNA pentru tot antetul); altfel semnul de brand, înalt cât rândul. */
.proj-head__live { font-size: var(--proj-head-fs); padding: .1em .55em; }
.proj-head__brand { display: inline-flex; justify-content: flex-end; }
.proj-head__logo { --brand-logo-h: calc(var(--proj-head-fs) * 1.25); }
/* (`.live-projector .cat-block { border-inline-start: 0 }` ȘTEARSĂ la B218: blocul n-are șină nicăieri.) */
.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 .tab-actions,
.live-projector .roster__form--manage,
.live-projector .owner-note,
.live-projector .proj-hide,
.live-projector [data-bs-target^="#f"] { display: none; }
/* (`.live-projector .cat-tabs { justify-content: center }` ȘTEARSĂ la B218: cele două jumătăți umplu rândul (`flex: 1 1 0`),
   nu mai e nimic de centrat.) */
/* Coborata din `@layer skin` la B159 L10 (F2). */
.cat-tabs { border-bottom: 1px solid var(--ui-hair); gap: 1.25rem; }
/* ⚠️ TOATE regulile de mai jos stau ÎN media query, în oglindă cu cele de bază din scoreboard.css
   (`@media (min-width: 992px)`). Erau nelayerizate pe lățime și se aplicau și în modul COLOANĂ, unde
   nu însemnau ce par:
     · `max-width: min(70rem, 65vw)` plafona panoul la 65vw pe toată lățimea ecranului → 35% rămâneau
       GOI, exact acolo unde stătea bracketul (raportat: „scoreboardul nu sare full width, rămâne un
       spațiu gol în locul bracketului");
     · `flex-basis` pe axa verticală e ÎNĂLȚIME, deci `flex: 1 0 min(30rem, 40vw)` întindea panoul
       pe verticală degeaba;
     · `justify-content` centrează pe axa PRINCIPALĂ, care în coloană e verticala — nu ajuta cu nimic.
   Sub prag, proiectorul se comportă acum identic cu pagina normală: scoreboard pe toată lățimea,
   bracket stivuit dedesubt (MC-ul își ia „cine urmează" tot din bracket, deci nu se ascunde). */
@media (min-width: 992px) {
    /* 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; }
    /* Pe proiector panoul are o bază fixă generoasă, deci bracketului îi rămâne mai mult decât în
       ecranul organizatorului → scala lui (ADR 0040) trebuie să știe asta, altfel ar desena carduri
       de 60% pe un loc de 70% și ar lăsa o bandă goală lângă finală. */
    .live-projector .bk-layout { --bk-share: .68; }
    /* Presetările ecranului de sală (ADR 0041) ridică plafoanele de proiector de mai sus. TREI clase
       deliberat: components.css se încarcă DUPĂ scoreboard.css (ADR 0023), deci regulile de bază
       `.bk-layout--stacked …` de acolo ar pierde la aceeași specificitate în fața celor de aici. */
    .live-projector .bk-layout--stacked { --bk-share: 1; }
    .live-projector .bk-layout--stacked .bk-layout__current,
    .live-projector .bk-layout--panel-only .bk-layout__current { flex-basis: 100%; max-width: 100%; }
}
/* Tabul Calificare: coloanele dense citesc mai bine plafonate + centrate.
   Ținta era `.tab-pane > .row` (Bootstrap-ul care ținea cele două coloane); din iter. 2o tabul e
   `.qual-tab`, iar regula ar fi rămas MOARTĂ tăcut dacă o lăsam pe selectorul vechi. */
.live-projector .qual-tab { max-width: 1500px; margin-inline: auto; }
/* Butoanele de zoom: există în DOM mereu, vizibile DOAR în mod proiector */
.proj-zoom { display: none; }
/* Comenzile ecranului (B114): un singur buton ⚙ jos-dreapta; panoul cu cele trei grupuri se desface
   DEASUPRA lui la click (`html.proj-open` — clasă pe <html>, pe care morph-ul Turbo nu-l atinge, ca
   `--proj-zoom`). După ~5 s fără mouse/tastă/atingere tot clusterul se ascunde (`html.proj-idle`) și
   reapare la prima mișcare — standardul playerelor video: sala nu vede niciun control, operatorul
   îl are la o mișcare de mouse. */
.live-projector .proj-zoom {
    display: flex; flex-direction: column; align-items: flex-end; gap: .4rem;
    max-width: calc(100vw - 2rem);     /* zece butoane: pe ecran îngust se rup pe rând, nu ies din ecran */
    position: fixed; right: 1rem; bottom: 1rem; z-index: 50;
    transition: opacity .25s ease;
}
.proj-zoom__panel { display: none; }
html.proj-open .proj-zoom__panel {
    display: flex; flex-wrap: wrap; justify-content: flex-end;
    gap: .25rem .6rem;                 /* mic ÎN grup (vezi __grp), mai mare ÎNTRE grupuri */
}
/* Același mecanism ca `.tab-actions__grp`: gap mic în grup, wrapul cade ÎNTRE grupuri (zoom ·
   oglindă+urmărire · presetări de afișare, ADR 0041). */
.proj-zoom__grp { display: flex; gap: .25rem; }
/* Starea „deschis" a ⚙: roata se rotește — semnal fără a doua paletă de culori. */
.proj-zoom__toggle .bi { display: inline-block; transition: transform .25s ease; }
html.proj-open .proj-zoom__toggle .bi { transform: rotate(90deg); }
html.proj-idle .proj-zoom { opacity: 0; pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
    .live-projector .proj-zoom, .proj-zoom__toggle .bi { transition: none; }
}
/* 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(--ui-warning); } }
.live-projector .proj-zoom__follow--off {
    background: var(--ui-warning-soft); color: var(--ui-on-warning-soft); border-color: var(--ui-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) */

/* ---- PASTILA DE STIL (mutata din kf-skin.css, B159 L10) -------------------------------------
   Identitatea unui stil de dans: hue din markup (`--style-h`), scara din tokens.css.
   ⚠️ MERGE, nu mutare: fisierul kf avea DOUA reguli, iar cea care se randa era varianta
   `body.kf .style-pill` (mono, 700, muchie de 4px), nu cea de baza. Mutarea regulii de baza ar fi
   schimbat aspectul pe cinci pagini. Aici e rezultatul combinat, cu tokenii kf inlocuiti de
   echivalentii lor globali (`--kf-font-mono` -> `--font-mono`: sub skin amandoi dau aceeasi familie).
   Colturile citesc rolul `chip`, cu valoarea de azi ca fallback. */
.style-pill {
    display: inline-flex; align-items: center; gap: .25rem;
    padding: .2rem .5rem .2rem .42rem;
    border-radius: var(--radius-chip, 999px);
    border: 0; border-left: 4px solid hsl(var(--style-h) var(--style-s) var(--style-l-accent));
    background: hsl(var(--style-h) var(--style-s) var(--style-l-bg));
    color: hsl(var(--style-h) var(--style-s) var(--style-l-fg));
    font-family: var(--font-mono); font-weight: 700; font-size: var(--font-xs);
    text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .04em);
    line-height: 1.25; white-space: nowrap;
}
/* Formatul în pastilă (B214, rândul compact de pe prima pagină: „BREAKING 1 vs 1"): aceeași cerneală, fără majuscule. */
.style-pill__fmt { font-weight: 600; text-transform: none; letter-spacing: 0; }
/* PUNCTUL DE STIL (B195, prototipul fluxului live) — identitatea stilului ca SEMN mic lângă numele lui, unde o pastilă
   ar fi prea grea: antetul ecranului de sală (L3) și, la L4, taburile de categorie. Aceeași nuanță ca muchia pastilei
   (`--style-l-accent`); numele stilului e mereu scris lângă el, deci culoarea nu e singurul canal. `em` → urmează
   mărimea textului lângă care stă. */
.style-dot {
    display: inline-block; flex: none; align-self: center;
    width: .55em; height: .55em; border-radius: 50%;
    background: hsl(var(--style-h) var(--style-s) var(--style-l-accent));
}
/* AVATARUL cu inițiale (B195 L5, prototipul fluxului live) — un jurat / un om din line-up. Nuanța din nume
   (`avatar_hue`, același hash ca stilul de dans — `NameHue`), în OKLCH cu luminozitate și croma FIXE:
   `oklch(50% .12 h)` ține inițialele albe la MINIMUM 5.37:1 pe toate cele 360 de nuanțe (măsurat; garda:
   `AvatarColorContrastTest`). HSL nu poate: la galben, „40%" iese 2.9:1. NEUTRU (DJ / host) = s3 + cerneală.
   Head coach = punctul violet de pe colț, cu inel în culoarea cardului. Mărimea = `--av-size`, pusă de context. */
.avatar {
    position: relative; flex: none;
    display: inline-grid; place-items: center;
    width: var(--av-size, 2.2rem); height: var(--av-size, 2.2rem); border-radius: 50%;
    background: oklch(50% .12 var(--av-h, 0)); color: var(--ui-on-color, #fff);
    font-family: var(--font-display); font-weight: 800; line-height: 1; letter-spacing: .02em;
    font-size: calc(var(--av-size, 2.2rem) * .38);
}
.avatar--neutral { background: var(--ui-quiet); color: var(--ui-ink); }
.avatar--head::after {
    /* Offset 0, nu negativ: colțul pătratului e oricum în afara cercului, deci punctul tot încalecă marginea — iar un
       pseudo-element cu offset negativ se citește drept țintă de tap mărită (garda SitePaletteCssScopeTest). */
    content: ""; position: absolute; inset-block-start: 0; inset-inline-end: 0;
    width: calc(var(--av-size, 2.2rem) * .34); height: calc(var(--av-size, 2.2rem) * .34); border-radius: 50%;
    background: var(--ui-accent-fill); box-shadow: 0 0 0 2px var(--ui-raised);
}
/* STIVA DE AVATARE (B214) — juriul unei categorii / topul clasamentului ca un ȘIR de fețe, unde cardurile de persoană ar fi prea grele
   (ușa „Urmărești" și mini-cartea concursului scos în față, pe prima pagină). Inelul are culoarea suprafeței pe care stă stiva
   (`--stack-ring`, implicit cardul); numele sunt scrise lângă sau în textul ascuns — fețele sunt decor. */
.avatar-stack { display: inline-flex; flex: none; --av-size: 1.9rem; }
.avatar-stack .avatar { box-shadow: 0 0 0 2px var(--stack-ring, var(--ui-raised)); }
.avatar-stack .avatar + .avatar { margin-inline-start: -.45rem; }
.cl-cat .avatar-stack { --stack-ring: var(--ui-flat); }

/* ═══ /concursuri + /arhiva (B204, ADR 0058; B234 — ARENA): CONCURSUL = AFIȘ, CATEGORIILE = PLĂCI ═══
   Unitatea = CATEGORIA: juriul, line-up-ul, înscrișii și butonul sunt ale ei, deci stau în aceeași placă, cu aceeași structură în
   fiecare (etichetele MEREU deasupra). Concursul = regiunea comună (Gestalt, NN/g) care le ține.
   B234 (macheta Arena, Claude Design): concursul e un AFIȘ — coperta alb-negru pe toată lățimea antetului, data și numele mari peste
   ea, degradeul spre placă dedesubt; dunga laterală (`--ar-rail-color`) arată unde începe și unde se termină. Șina lipicioasă a datei
   (B204) a plecat: data stă pe copertă, deci `.cl-contest` și `.cl-cat` pot fi CONTAINERE — mărimile (numele, ziua, formatul, coperta)
   curg din lățimea lor (`cqi`), nu din ecran. Modalele de înscriere sunt randate în afara `.cl` (containment-ul ar captura `fixed`). */
.cl { container-type: inline-size; display: flex; flex-direction: column; gap: var(--kf-5); }

/* Filtrele (controllerul Stimulus `contest-filter`): se apasă și se dezapasă — nimic apăsat = toate; contorul se recalculează.
   Pe telefon NU o bandă care derulează (P1 v5.1, ownerul: „rămân în afara paginii" — măsurat: „Brașov" tăiat la 414px pe 360, fără
   indiciu; NN/g: conținutul de dincolo de margine nu există fără semn): fiecare grup pe rândul lui, pastilele se rup pe rândul următor. */
.cl-filterbar { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem 1.25rem; }
.cl-filters { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem; }
.cl-filters__lbl { font-family: var(--font-mono); font-size: var(--font-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ui-ink-muted); }

/* Secțiunile de timp (and8): luna (/concursuri) și anul (`.arch-year`, /arhiva) = ACELAȘI titlu de secțiune — plin, condensat, cu
   firul dedesubt și contorul pe violetul de identitate. `.arch-year` își ține geometria lipicioasă în `base-layout.css`. */
.cl-section { display: flex; flex-direction: column; gap: .9rem; }
.cl-section__h, .arch-year {
    display: flex; align-items: center; gap: .6rem; margin-block: 2rem 1rem; padding-block: .5rem;
    font-family: var(--font-display); font-weight: 900; font-stretch: var(--ar-wdth); text-transform: uppercase; letter-spacing: -.005em;
    font-size: var(--ar-fs-section); line-height: .9; color: var(--ui-ink); border-bottom: 1px solid var(--ui-hair);
}
.cl-section__h { margin-inline: 0; }
.cl-section__n, .arch-year__n {
    padding: .3rem .5rem; border-radius: var(--radius-control, 0); background: var(--ui-accent-fill); color: var(--ui-on-accent-fill);
    font-family: var(--font-display); font-size: var(--font-base); font-weight: 400; font-stretch: 100%; line-height: 1;
}

/* PROXIMITATEA: între concursuri mai mult aer decât între plăcile aceluiași concurs (care se ating, fir de 1px). */
.cl-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: clamp(1rem, 2.5cqi, 1.75rem); }

/* ── Concursul = AFIȘUL ──────────────────────────────────────────────────────────────────────────────────────────────
   `overflow: hidden` taie coperta și plăcile pe colțurile cardului (nimic dinăuntru nu se mai lipește). Dunga laterală = un `::before`
   peste tot concursul; culoarea ei e un token de COMPONENTĂ (un concurs o poate redeclara) = CERNEALA (B234 runda 2, ownerul: violetul
   „nu e bun" — albă pe închis, neagră pe deschis; violetul rămâne al acțiunii principale și al stării active).
   Suprafața: concursul stă pe tonul RIDICAT (rolul `--ui-flat` redeclarat în context, ca `--ui-quiet` pe `.cl-cat`, B228) — cardul,
   degradeul copertei și plăcile urcă împreună: pe închis `#141416` → `#1f1f23` (1.08 → 1.21 față de pagină; ownerul: „încă un pas
   de deschidere a cardului pe tema închisă"); pe deschis ridicat = plat = alb, deci nimic nu se mișcă. */
.cl-contest {
    --ar-rail-color: var(--ui-ink);
    --ui-flat: var(--ui-raised);
    position: relative; container-type: inline-size; display: grid; grid-template-columns: minmax(0, 1fr); overflow: hidden;
    background: var(--ui-flat); border-radius: var(--radius-card, 0); box-shadow: var(--ui-shadow-float);
}
.cl-contest::before { content: ""; position: absolute; inset-block: 0; inset-inline-start: 0; z-index: 3; inline-size: var(--ar-rail); background: var(--ar-rail-color); }
.cl-contest__main { min-width: 0; }
/* Antetul = coperta: afișul e fundalul lui (`z-index: -2`, în contextul izolat al antetului), degradeul `::after` îl stinge spre placă
   ca data și numele să se citească; fără afiș antetul se strânge pe conținut. Afișul rămâne butonul care îl mărește
   (`poster-lightbox.js`): degradeul nu prinde clicul, iar inelul de focus se desenează pe antet — pe afiș ar sta sub degrade. */
.cl-contest__head {
    position: relative; isolation: isolate; display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: end;
    gap: .4rem clamp(.75rem, 3cqi, 1.75rem); min-block-size: var(--ar-cover-min);
    padding: clamp(.9rem, 3cqi, 1.75rem) clamp(.9rem, 3cqi, 1.75rem) clamp(.9rem, 3cqi, 1.5rem) calc(var(--ar-rail) + clamp(.9rem, 3cqi, 1.75rem));
}
.cl-contest__head::after {
    content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
    background: linear-gradient(180deg, color-mix(in srgb, var(--ui-flat) 20%, transparent) 0%, color-mix(in srgb, var(--ui-flat) 72%, transparent) 55%, var(--ui-flat) 100%);
}
.cl-contest__head:not(:has(.crow__poster)) { min-block-size: 0; padding-block-start: clamp(1rem, 3cqi, 1.5rem); }
.cl-contest__head:has(.crow__poster:focus-visible) { outline: 2px solid var(--ui-focus); outline-offset: -2px; }
.cl-contest__head .crow__poster { position: absolute; inset: 0; z-index: -2; inline-size: 100%; block-size: 100%; aspect-ratio: auto; margin: 0; border-radius: 0; }
.cl-contest__head .crow__poster img { filter: grayscale(1) contrast(1.1); opacity: .55; transition: filter .4s, opacity .4s; }
@media (hover: hover) { .cl-contest:hover .cl-contest__head .crow__poster img { filter: none; opacity: .7; } }
@media (prefers-reduced-motion: reduce) { .cl-contest__head .crow__poster img { transition: none; } }
/* Fără afiș, pe rândul compact (prima pagină): o lumină în nuanța primului stil, fără text — numele e deja scris mare peste ea. */
.cl-contest__head .crow__poster--ph { background: radial-gradient(120% 90% at 85% 10%, hsl(var(--style-h, 280) 70% 45% / .45), transparent 60%), var(--ui-subtle); }
.cl-contest__head .crow__poster--ph > * { display: none; }
/* Data pe copertă: ziua uriașă, condensată; luna pe violet, ziua săptămânii stinsă. */
.cl-contest__head .crow__date { gap: .15rem; color: var(--ui-ink); }
.cl-contest__head .crow__day { margin: 0; font-weight: 900; font-stretch: var(--ar-wdth); font-size: var(--ar-fs-day); line-height: .8; color: var(--ui-ink); }
.cl-contest__head .crow__mon { font-family: var(--font-display); font-weight: 800; letter-spacing: .1em; text-transform: uppercase; font-size: var(--font-md); color: var(--ui-accent); }
.cl-contest__head .crow__dow { font-weight: 700; letter-spacing: .08em; text-transform: uppercase; font-size: var(--font-sm); color: var(--ui-ink-muted); }
.cl-contest__titles { min-width: 0; display: flex; flex-direction: column; gap: .3rem; }
/* Îngust: titlul ia tot rândul, data trece deasupra lui, pe un rând (lună · zi · ziua săptămânii). */
@container (max-width: 34rem) {
    .cl-contest__head { grid-template-columns: minmax(0, 1fr); }
    .cl-contest__head .crow__date { flex-direction: row; align-items: baseline; gap: .5rem; }
}
/* Plăcile categoriilor: egale pe lățime (o categorie → tot rândul; n → se împart), despărțite de un fir de 1px (fundalul grilei),
   lipite de dunga laterală. */
.cl-contest__cats {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr)); gap: 1px;
    padding: 0 0 0 var(--ar-rail); background: var(--ui-hair); border-top: 1px solid var(--ui-hair);
}

/* Blocul de dată = vedeta (Ticketmaster: luna peste zi; cast-ui §2: cifra-cheie pe violet). Regula de bază e a primei pagini (arhiva din
   teaser, concursul scos în față); pe copertă o rescriu regulile `.cl-contest__head` de mai sus. */
.crow__date { display: flex; flex-direction: column; align-items: center; line-height: 1; text-align: center; }
.crow__mon { font-family: var(--font-mono); font-size: var(--font-xs); font-weight: 700; letter-spacing: .08em; color: var(--ui-ink-muted); }
.crow__day { margin-block: .2rem .25rem; font-size: clamp(1.75rem, 4.6cqi, 2.25rem); font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; color: var(--ui-accent); white-space: nowrap; }
.crow__day--range { font-size: clamp(1rem, 3cqi, 1.45rem); }
.crow__dow { font-size: var(--font-xs); color: var(--ui-ink-muted); }
/* Numele concursului = titlu de AFIȘ (rolul `title`: 900, majuscule), cât îi dă containerul. */
.crow__title {
    margin: 0; font-family: var(--font-display); font-weight: var(--type-title-weight, 800); font-stretch: var(--ar-wdth);
    text-transform: var(--type-title-case, none); letter-spacing: var(--type-title-tracking, 0);
    font-size: var(--ar-fs-contest); line-height: .9; overflow-wrap: anywhere; text-wrap: balance;
}
.crow__title a { color: var(--ui-ink); text-decoration: none; }
@media (hover: hover) { .crow__title a:hover { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: .16em; } }
.crow__meta { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .9rem; margin: .5rem 0 0; font-size: var(--font-md); font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--ui-ink); }
.crow__meta i { margin-right: .3rem; }
.crow__rel { font-weight: 700; color: var(--ui-ink); }
.crow__own { display: inline-flex; align-items: center; min-height: var(--tap-aa); font-weight: 700; color: var(--ui-ink); text-decoration: underline; text-underline-offset: .18em; }
/* Afișul = butonul care îl mărește (`poster-lightbox.js`): învelitoarea e ținta, imaginea o umple. În antetul concursului e coperta
   (regulile `.cl-contest__head` de mai sus); pe prima pagină, concursul scos în față îl arată întreg (`--feat`). */
.crow__poster { display: block; aspect-ratio: 3 / 4; overflow: hidden; cursor: zoom-in; border-radius: var(--radius-row, 0); background: var(--ui-sunken); }
.crow__poster img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* B214 — prima pagină: afișul concursului scos în față e ÎNTREG și MARE (3:4), cu textul ALĂTURI, niciodată peste.
   Fără afiș → plăcuța în nuanța primului stil, pe perechea umplere / cerneală a pastilei de stil (conținut, nu o placă gri), cu
   NUMELE concursului scris mare (prototipul aprobat: `.ph b`) — stilul e deja în pastila de lângă; stilul stă mic deasupra numelui.
   Numele se taie la 3 rânduri: `overflow: hidden` + `align-content: end` ar tăia altfel pe SUS un nume lung. */
.crow__poster--feat { width: 100%; max-width: 17rem; }
.crow__poster--ph {
    display: grid; align-content: end; gap: .25rem; padding: .45rem; cursor: default; overflow-wrap: anywhere;
    background: hsl(var(--style-h) var(--style-s) var(--style-l-bg)); color: hsl(var(--style-h) var(--style-s) var(--style-l-fg));
    font-family: var(--font-mono); font-weight: 700; font-size: var(--font-2xs); line-height: 1.15;
    text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .04em);
}
.crow__poster--ph b { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; font-family: var(--font-display); font-weight: 900; font-size: var(--font-xs); line-height: 1.05; letter-spacing: 0; }
.crow__poster--feat.crow__poster--ph { padding: .9rem; gap: .4rem; font-size: var(--font-md); }
.crow__poster--feat.crow__poster--ph b { font-size: var(--font-2xl); }
/* Categoriile ca pastile pe un rând — rândul COMPACT de pe prima pagină (pe /concursuri categoriile au plăcile lor). */
.crow__styles { display: flex; flex-wrap: wrap; gap: .3rem; margin: .15rem 0 0; }

/* ── Rândul COMPACT (prima pagină, B214): TOT rândul duce la concurs — linkul titlului se întinde peste antet (modelul
   `.home-list__cat::after`); antetul e acum coperta (B234), deci și ea e sub link. Deasupra lui rămâne DOAR „Editează" al
   organizatorului; afișul se mărește de pe pagina concursului (de la tastatură, butonul de lightbox rămâne în ordinea de focus).
   Hover-ul vine singur: `::after` e al linkului, deci `.crow__title a:hover` se declanșează pe tot rândul. ── */
.cl-contest--compact { position: relative; }
.cl-contest--compact .crow__title a::after { content: ""; position: absolute; inset: 0; }
.cl-contest--compact .crow__own { position: relative; z-index: 1; }
/* Proximitatea din prototip: 14px de la concursul scos în față la rânduri (lista ține aerul de pe /concursuri). Scopat pe `.home-open`. */
.home-open { gap: .85rem; }

/* ── PLACA de CATEGORIE (B234) ───────────────────────────────────────────────────────────────────────────────────────
   Pe suprafața concursului, cu dunga STILULUI sus (nuanța lui — pastila, înscrișii și dunga o moștenesc de pe placă). Placa e
   container: oamenii, formatul și butonul se așază după lățimea ei, nu a ecranului. Structura e aceeași în fiecare; butonul stă jos,
   aliniat pe un rând de plăci. Avatarul neutru, insignele și pastilele de înscriși stau pe `--ui-quiet`, ca peste tot (B228.2): pe
   deschis placa e albă, deci o treaptă DEASUPRA ei nu există — gri pe alb (1.55); pe închis `#2c2c31` pe placa `#1f1f23` (1.18). */
.cl-cat {
    position: relative; container-type: inline-size; display: flex; flex-direction: column; gap: .8rem; min-width: 0; margin: 0;
    padding: clamp(.9rem, 4cqi, 1.4rem); border: 0; border-radius: 0;
    background: var(--ui-flat); box-shadow: inset 0 3px 0 hsl(var(--style-h, 280) 70% 55%); }
/* Numele: pe rândul lui, deasupra oamenilor; pastila de stil = plăcuță (colț de control), formatul condensat lângă ea. */
.cl-cat__name { display: block; margin-block-end: .9rem; }
.cl-cat__name .style-pill { border-radius: var(--radius-control, 0); }
.cl-cat__fmt { display: block; font-weight: 900; font-stretch: var(--ar-wdth); text-transform: uppercase; font-size: var(--ar-fs-format); line-height: 1; color: var(--ui-ink); overflow-wrap: anywhere; }
/* CARDUL = LINK spre categorie (P1 v5.1; Inclusive Components „Cards"): linkul stă pe NUMELE categoriei (pastila + formatul —
   un nume care se citește) și se întinde peste toată placa (`::after`, ancorat de `position: relative` de pe `.cl-cat`). Pe tabul
   live linkul întins e chiar „Urmărește" (un singur link spre aceeași pagină, nu două). Controalele dinăuntru stau DEASUPRA lui. */
.cl-cat__link { display: inline-flex; align-items: center; gap: .5rem; color: inherit; text-decoration: none; }
/* NUMELE PE UN RÂND (B224, ownerul pe live: „1 vs 1 — ultimul 1 coboară pe al doilea rând"): formatul nu se mai rupe ÎN el; dacă un
   nume viitor tot n-ar încăpea, `flex-wrap` lasă pastila și formatul să cadă pe două rânduri ÎNTREGI — niciodată o rupere în mijlocul
   formatului. Aceleași două reguli și pe plăcile concursului scos în față de pe prima pagină (`.home-feat__cat`, B224 — ownerul,
   2026-10-12: „7 TO” / „SMOKE” se rupeau acolo la unele lățimi, când grila trecea la o placă în plus pe rând). */
.cl-contest__cats .cl-cat__link,
.home-feat__cat .cl-cat__link { display: flex; flex-wrap: wrap; gap: .35rem .6rem; }
.cl-contest__cats .cl-cat__fmt,
.home-feat__cat .cl-cat__fmt { white-space: nowrap; }
.cl-cat__stretch::after,
.home-door__go::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
/* B216.2: linkul ÎNTINS face tot cardul țintă, deci inelul de focus stă pe TOT cardul, nu pe controlul mic din interior (cel de pe
   control se stinge în `base-layout.css`, `@layer base`, lângă inelul global). Același semn ca afișul din antet
   (`.cl-contest__head:has(.crow__poster:focus-visible)`); offset negativ ca să nu-l taie un strămoș cu `overflow`. */
.cl-cat:has(.cl-cat__stretch:focus-visible),
.home-door:has(.home-door__go:focus-visible),
.cl-contest--compact:has(.crow__title a:focus-visible),
.home-list__row:has(.home-list__cat:focus-visible) { outline: 2px solid var(--ui-focus); outline-offset: -2px; }
.cl-cat__foot, .cl-cat .e-chip--team, .cl-cat a.person-card { position: relative; z-index: 1; }
@media (hover: hover) {
    .cl-cat__link.cl-cat__stretch:hover .cl-cat__fmt, a.cl-cat--link:hover .cl-cat__fmt { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: .16em; }
    a.cl-cat--link:hover { background: var(--ui-hover); }
}
/* Arhiva: placa ÎNTREAGĂ e `<a>` (n-are nimic înăuntru de apăsat), doar numele. */
a.cl-cat--link { color: inherit; text-decoration: none; }
/* DIVIZIUNILE (cipuri `.cat-disc`, primele) și PREMIUL — fiecare pe rândul lui sub nume (B219, ownerul: „UNDER și Feminin sunt
   subcategoria, lasă loc pentru ele primele"). Sloturile se randează mereu, goale când n-au nimic: un slot gol nu ocupă nimic…
   …DECÂT dacă vreo placă a CONCURSULUI are diviziuni / premiu: atunci TOATE plăcile lui rezervă rândul (înălțimea unui cip / a unei
   linii), deci juriul, înscrișii și butonul cad la aceeași înălțime în tot rândul („să aliniem și celelalte, dar doar dacă există").
   `:has()` pe grila concursului = rezervarea „doar dacă există" fără JS și fără o cifră pe fiecare placă; `:empty` cere sloturi
   FĂRĂ spații (template-ul le dă prin `|trim`). Specificitatea lui `:has()` e a argumentului, deci (0,4,0) bate `:empty` (0,2,0). */
.cl-cat__divs, .cl-cat__prize { flex-basis: 100%; display: flex; flex-wrap: wrap; gap: .3rem; }
.cl-cat__divs:empty, .cl-cat__prize:empty { display: none; }
/* Podeaua se pune pe TOATE sloturile concursului (pline sau goale), nu doar pe cele goale: așa rândul are aceeași înălțime peste
   tot (un premiu randat are 17px, rezervarea 20 — fără podea comună juriul vecinului cobora cu 3px; măsurat). */
.cl-contest__cats:has(.cl-cat__divs .cat-disc) .cl-cat__divs { display: flex; min-block-size: calc(var(--font-sm) * 1.3 + .3rem); }
.cl-contest__cats:has(.cl-cat__prize .prize-line) .cl-cat__prize { display: flex; min-block-size: 1.25em; }
.cl-cat .now-tag { font-size: var(--font-xs); }
.cl-cat__none { font-size: var(--font-sm); color: var(--ui-ink-muted); }
/* Grupul de oameni = cel al paginii categoriei (`.people__grp` / `__lbl` / `__row`). JURIUL (al doilea copil al plăcii): câte 3 pe
   rând, pe coloane egale — un nume lung se taie cu „…", nu împinge placa; pe o placă sub 15rem, 2 pe rând. Line-up-ul și înscrișii
   curg pe coloane de 10rem. */
.cl-cat .people__grp { gap: .45rem; }
.cl-cat .people__lbl { letter-spacing: .1em; }
.cl-cat .people__row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .5rem .75rem; }
.cl-cat .people__grp:not(:nth-child(2)) .people__row { grid-template-columns: repeat(auto-fill, minmax(min(100%, 10rem), 1fr)); }
.cl-cat .person-card, .cl-cat .person-card__who { min-width: 0; }
.cl-cat .person-card__nm, .cl-cat .person-card__sub { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@container (max-width: 15rem) { .cl-cat .people__row { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Punctul head coach-ului: inelul în culoarea SUPRAFEȚEI pe care stă (placa) și tonul de TEXT al violetului —
   umplerea `--identity-fill` dădea 2.83:1 pe card pe dark (sub 3:1, iar pe telefon punctul e singurul semn de head coach). */
.cl-cat .avatar--head::after { box-shadow: 0 0 0 2px var(--ui-flat); background: var(--ui-accent); }
/* Înscrișii: lista REALĂ (ținta Turbo Stream-ului), CEI MAI NOI PRIMII, pe UN rând și pe telefon, ca pastile cu colț de control
   (aceeași regulă ca pe pagina categoriei, mai jos: „.cat-entries-row .e-chip, .cl-cat .e-chip”; nuanța vine de pe `.cl-cat`) —
   pliați cu „+N" care se deschide pe loc. Contorul = cifra condensată, pe violet; ținta lui `update` (gol la 0 → ascuns). */
.cl-cat__n { margin-inline-start: .2rem; font-weight: 900; font-stretch: var(--ar-wdth); font-size: var(--font-2xl); line-height: 1; color: var(--ui-accent); font-variant-numeric: tabular-nums; }
.cl-cat__n:empty { display: none; }
.cl-cat .e-chip-list { min-width: 0; }
/* Virgula de dinainte (`::before` pe chipul URMĂTOR) pica la început de rând când lista se rupea, cu spațiu dublu după ea; numele
   se citeau greu unul de altul → pastile (ownerul, 2026-10-02, ADR 0058 am.2). Textul rămâne la mărimea plăcii (14px), nu 11px. */
.cl-cat .e-chip { font-size: var(--font-base); }
.cl-cat .e-chip, .cl-cat .e-chip__body { border-radius: var(--radius-control, 0); }
.cl-cat .e-city { font-size: var(--font-sm); }
/* „+N" e scurt → fără lățime minimă ieșea 19×24px, sub minimul WCAG 2.5.8 (24×24) — prins de `ui-probe tap` (2026-10-02). */
.cl-cat .chips-more-btn { position: relative; z-index: 1; display: inline-flex; align-items: center; justify-content: center; min-height: var(--tap-aa); min-width: var(--tap-aa); }
.cl-cat__ents:not(:has(.e-chip)) .e-chip-list { display: none; }
/* ── Placa ÎNGUSTĂ (sub 36rem — telefonul, sau mai multe plăci pe rând): oamenii mai mici, fără linia de sub nume (head coach-ul
   rămâne marcat de punctul violet). Înscrișii rămân VIZIBILI, pe un rând (P1 v5.1: după înscriere omul trebuie să-și vadă numele,
   primul în listă — nu ascuns după un link spre altă pagină). ── */
@container (max-width: 35.98rem) {
    .cl-cat { gap: .65rem; }
    .cl-cat .people__grp { gap: .35rem; }
    .cl-cat .person-card--flat { --av-size: 1.5rem; gap: .35rem; min-width: 0; font-size: var(--font-md); }
    .cl-cat .person-card__nm { line-height: 1.15; }
    /* Linia mică ascunsă DOAR vizual: „Head" rămâne pentru cititorul de ecran (avatarul e decor). */
    .cl-cat .person-card__sub { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}
/* Butonul = un click spre modalul de azi; pe toată lățimea, jos. Acțiunile organizatorului — sub el, mai mici. */
.cl-cat__foot { margin-top: auto; display: flex; flex-direction: column; gap: .4rem; }
/* „Urmărește" / „Rezultate" (categoria pornită, tabul live) e copil DIRECT al plăcii, nu în `__foot` — o învelitoare `__foot`
   (`position: relative; z-index: 1`) ar strânge linkul întins `::after` pe subsol. Același `margin-top: auto`: butonul stă pe FUNDUL
   plăcii, deci în rândul de plăci egale butoanele se aliniază și când un nume are premiu sau diviziuni (B219, raportul ownerului). */
.cl-cat > .cl-cat__btn { margin-top: auto; }
.cl-cat__btn { width: 100%; justify-content: center; }
.cl-cat__act { width: 100%; justify-content: center; }
/* B234: acțiunea principală a plăcii = butonul PLIN (`.btn-ink`, umplerea de identitate), mare și condensat. Specificitatea (0,2,0):
   familia `.btn-ink` stă în `base-layout.css`, care se încarcă DUPĂ foaia asta (aceeași specificitate ar pierde). */
.btn-ink.cl-cat__btn {
    min-block-size: 3rem; border-radius: var(--radius-control, 0);
    font-family: var(--font-display); font-weight: 900; font-stretch: var(--ar-wdth); text-transform: uppercase; letter-spacing: .02em; font-size: var(--font-lg);
}

/* ═══ ARENA (B234): BANDA MARQUEE + fundalul eroului primei pagini ═══
   Banda (`templates/_marquee.html.twig`): violetul de identitate cu cerneala lui, înclinată, puțin mai lată decât containerul
   (104%) — marginile ies din pagină, iar `overflow-x: clip` le taie fără să facă containere de derulare (`hidden` ar opri bara
   lipicioasă și antetele de an). Pe `html` ȘI pe `body`: singur pe `body`, `clip` se PROPAGĂ la viewport (unde devine `hidden`,
   container de derulare — documentul tot măsura 368px la 360, prins de `probe.py overflow`); cu o valoare proprie pe `html`,
   `body` își păstrează tăierea pentru banda de deasupra subsolului. `.app-wrap` taie eroul și banda mare la marginea conținutului,
   ca în machetă. Pista curge cu −50% (două jumătăți identice), se oprește la `prefers-reduced-motion`, sub cursor și la butonul ⏸
   (B235, WCAG 2.2.2). Pe proiector nu apare. */
html, body, .app-wrap { overflow-x: clip; }
.ar-mq {
    position: relative; z-index: 2; overflow: hidden; white-space: nowrap; inline-size: 104%; margin-inline: -2%; margin-block: 1.5rem;
    transform: rotate(-1.2deg); background: var(--ui-accent-fill); color: var(--ui-on-accent-fill);
}
.ar-mq__track {
    display: inline-flex; animation: ar-mq 45s linear infinite;
    font-family: var(--font-display); font-weight: 900; font-stretch: var(--ar-wdth); text-transform: uppercase; line-height: 1;
}
.ar-mq__i { display: inline-flex; align-items: center; gap: var(--ar-gap); padding-inline-end: var(--ar-gap); }
.ar-mq__dot { display: inline-block; inline-size: .16em; block-size: .16em; border-radius: 50%; background: currentColor; }
.ar-mq--lg { padding-block: clamp(.8rem, .5rem + 1cqi, 1.25rem); }
.ar-mq--lg .ar-mq__track { font-size: clamp(2.25rem, 1rem + 4cqi, 4.5rem); --ar-gap: clamp(1rem, .5rem + 1.5cqi, 2.25rem); }
.ar-mq--sm { padding-block: .6rem; }
.ar-mq--sm .ar-mq__track { font-size: clamp(1.5rem, 1rem + 1.6cqi, 2.4rem); --ar-gap: 1.25rem; }
.ar-mq--conc { margin-block: .5rem 2rem; }
@keyframes ar-mq { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (hover: hover) { .ar-mq:hover .ar-mq__track { animation-play-state: paused; } }
/* B235: pauza — starea stă în `aria-pressed` (marquee_controller.js), CSS-ul o citește. Butonul plutește la capătul din dreapta, pe
   umplerea benzii, cu ținta minimă AA (WCAG 2.5.8); glifa arată acțiunea următoare (⏸ cât curge, ▶ cât stă). */
.ar-mq:has(> .ar-mq__pause[aria-pressed="true"]) .ar-mq__track { animation-play-state: paused; }
.ar-mq__pause {
    position: absolute; inset-block: 0; inset-inline-end: 3%; margin-block: auto; block-size: var(--tap-aa); min-inline-size: var(--tap-aa);
    display: inline-flex; align-items: center; justify-content: center; padding: 0 .35rem;
    appearance: none; border: 0; background: var(--ui-accent-fill); color: var(--ui-on-accent-fill); cursor: pointer;
    font-size: var(--font-md); line-height: 1;
}
.ar-mq__pause[aria-pressed="true"] .ar-mq__ico--pause,
.ar-mq__pause:not([aria-pressed="true"]) .ar-mq__ico--play { display: none; }
@media (prefers-reduced-motion: reduce) { .ar-mq__track { animation: none; } .ar-mq__pause { display: none; } }
.live-projector .ar-mq { display: none; }
/* Banda de deasupra subsolului stă în containerul paginii (`.app-foot-band`, base.html.twig), nu pe toată fereastra: la zoom mic
   (25%) se întindea pe 7680px, departe de conținut (runda 2). Gutterul = al lui `.app-wrap`; `clip` taie cele 2% care ies. Gol pe
   paginile fără bandă. Lipită de subsol: marginea lui de sus ar dubla aerul de sub bandă — (0,2,0) bate regula din `base-layout.css`. */
.app-foot-band { max-width: var(--container-max); margin-inline: auto; padding-inline: clamp(.5rem, 2.5vw, 1rem); overflow-x: clip; }
.app-foot-band:empty { display: none; }
.app-foot-band + .app-footer { margin-top: 0; }
/* Eroul primei pagini (geometria în `base-layout.css` §17): imaginea (`<img class="home-hero__bg">` — afișul concursului scos în față
   sau o poză de scenă) alb-negru în fundal, stinsă spre pagină; conținutul stă deasupra (contextul izolat al eroului). */
.home-hero__bg {
    position: absolute; inset: 0; z-index: -2; inline-size: 100%; block-size: 100%; object-fit: cover;
    filter: grayscale(1) contrast(1.15); opacity: .5;
}
.home-hero::after {
    content: ""; position: absolute; inset: 0; z-index: -1;
    background: linear-gradient(180deg, color-mix(in srgb, var(--ui-page) 35%, transparent) 0%, color-mix(in srgb, var(--ui-page) 55%, transparent) 55%, var(--ui-page) 100%);
}

/* „Ale mele" (mine-filter.js ascunde rândurile străine din CSS): lista fără niciun concurs al tău nu-și lasă filtrele și antetele în urmă.
   O secțiune al cărei singur concurs „al meu" e ascuns de filtrul de stil / oraș își ascunde și antetul. */
body[data-mine-only] .cl:not(:has([data-mine="1"])) { display: none; }
body[data-mine-only] .cl-section:not(:has([data-mine="1"]:not([hidden]))) { display: none; }

/* `.ccard` / `_contest_hero` (cardul de concurs cu afișul în bandă 16:9 și titlul PESTE el) au plecat la B214: ultimul lor
   consumator, prima pagină, arată acum afișul ÎNTREG cu textul alături (`.crow__poster--feat`). */

/* ── Notă de organizator care poartă o ACȚIUNE (bannerul „loc liber", `.owner-note--act`) ──
   Butonul stătea INLINE în paragraf, cu `ms-1`: nu se alinia cu textul pe nicio lățime, iar la
   îngustare fraza îl împingea oriunde (raportat de owner). Aici grupurile stau unul-lângă-altul,
   aliniate la stânga, cu gap FLUID, și pică pe rând UNUL CÂTE UNUL — fără `@media` dur care le
   prăbușește pe toate deodată (UI_RULES „Aranjament FLUID").
   `--full` = rândul care începe MEREU pe linie nouă (lista de retrași), în locul unui `<br>`. */
.owner-note--act {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: clamp(.2rem, 1.1vw, .55rem);
}
.owner-note__full { flex: 1 0 100%; }

/* ══ 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(--ui-ink);
    --tline-ink-muted: var(--ui-ink-muted);
    /* Linia CU SENS (`--ui-line`), nu firul de card: hairline-ul (1.43:1) e invizibil, iar aici linia E componenta. */
    --tline-line: var(--ui-line);
}
[data-theme="dark"] .tline { --tline-s: 55%; --tline-l: 66%; }
/* Mecanica de derulare vine din `.rail` (§5c) — pusă în markup. Aici rămâne doar ce e al liniei
   de timp. Linia de timp NU primește `.rail-fade`: n-are controller, deci n-ar primi niciodată
   `data-ov`, iar o mască inactivă tot ar costa (stacking context + text pe antialiasing grayscale). */
.tline__rail {
    display: flex; align-items: flex-start;
    margin: 0; padding: 0; list-style: none;
    /* 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);
}

/* 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: var(--type-label-weight, 900);
    text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .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: var(--type-number-tracking, .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: var(--type-number-tracking, .01em);
    line-height: 1.4; white-space: nowrap;
    padding-inline: .15rem;
    color: var(--tline-ink);
}
.tline__label {
    font-family: var(--font-display); font-weight: var(--type-label-weight, 900);
    text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .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. */
/* `gap` ERA AICI si era INERTA cat timp `.style-pill` statea in `@layer components` (kf-skin), care
   batea `@layer app`: spatiul dintre nume si format venea de la pastila (.25rem = 4px), nu de aici.
   Mutarea pastilei in `@layer app` (B159 L10) ar fi trezit-o pe tacute - masurat, 4px -> 2.88px.
   Declaratia moarta se sterge; nu ne bazam pe ordinea liniilor ca sa decidem cine castiga. */
.tline__cat { max-width: 100%; min-width: 0; }
.tline__catname { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tline__catfmt { flex: none; font-weight: 400; }

/* Modal de ÎNSCRIERE (_enroll_modal.html.twig) — chrome-ul vine din .brand-modal (base-layout,
   CHROME PARTAJAT); aici doar ce e specific. Formularul înlocuiește collapse-ul inline `.ccat-form`
   din 2026-08-21: desfăcut în pagină împingea rândurile de categorii și userul își pierdea reperul.
   Lățime: cât ține ecranul, plafonat — rândurile fluide ale formularului (.enf-row) câștigă din
   lățime, dar peste ~1100px un rând de câmpuri devine prea lung ca să-l urmărești cu ochiul.
   `92vw` ține fundalul VIZIBIL de jur împrejur pe orice mărime (cerință user): niciodată fullscreen,
   nici măcar pe telefon — o cutie lipită de muchii se citește ca altă pagină, nu ca un strat peste
   lista de categorii, și userul pierde exact reperul pentru care am făcut modalul.
   `margin-inline: auto` e OBLIGATORIU, nu decorativ: sub 576px Bootstrap pune `margin: .5rem` pe
   `.modal-dialog` (stânga/dreapta FIXE), deci cu un `max-width` mai mic decât ecranul cutia ar sta
   lipită la stânga, cu tot aerul adunat în dreapta. */
.enroll-modal__dialog { max-width: min(1100px, 92vw); margin-inline: auto; }
/* Titlul poartă și identitatea categoriei (pastila de stil + formatul): rândul de categorie nu se
   mai vede cât modalul e deschis. Wrap PROGRESIV — pastilele pică sub titlu una câte una, nu toate
   deodată la un breakpoint. */
.enroll-modal .modal-title { display: flex; flex-wrap: wrap; align-items: center; gap: .2rem clamp(.35rem, 1.5vw, .6rem); }

/* 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: var(--type-status-weight, 900); text-transform: var(--type-status-case, uppercase); letter-spacing: var(--type-status-tracking, .04em);
    font-size: var(--font-sm); color: var(--ui-win-ink); 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(--ui-overlay); box-shadow: var(--shadow-hard); }
.lightbox__close { position: absolute; top: 1rem; right: 1.2rem; width: 40px; height: 40px; background: var(--ui-overlay); color: var(--ui-on-color); border: 2px solid var(--ui-on-color); 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(--ui-inverse); border-color: var(--ui-inverse); }



/* 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. */
/* Marcaj `layer-shadow-ok` STERS la B159 L10 F1 ca ORFAN: justifica o umbra data de `body.kf`,
   iar regula kf a coborat in acelasi layer. Paginile citate (admin-*) sunt azi `?tab=` pe
   admin/dashboard, care poarta `kf admin`. */
.dancer-lbl  { font-family: var(--font-display); font-size: var(--font-2xs); font-weight: var(--type-label-weight, 700); text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .08em); color: var(--ui-ink-muted); margin-bottom: 1px; display: block; }
/* `.pc-form-title` ștearsă 2026-08-21: era titlul formularului inline de înscriere; în modal titlul
   e `.modal-title`, skinat o singură dată prin `.brand-modal` (base-layout, CHROME PARTAJAT). */

/* Competitor chip simplu */
.e-chip     { white-space: nowrap; line-height: 1.7; vertical-align: middle; }

/* ---- Cipuri: venite din kf-skin.css la B159 L10 (F1) ------------------------------------
   Stau DUPA regulile de baza de mai sus: neprefixate, au aceeasi specificitate, deci
   decide ordinea in text — exact precedenta pe care o dadea layerul inainte. */
  /* juriu / staff / înscriși → fill plat pătrat (fără border) */
  /* `border-radius` nu e aici: skinul da `--sm-r-row` tuturor cipurilor (decizia de forma B172,
     „o forma, un sens"). Era mort si in kf — `@layer skin` batea `@layer components`. */
  .e-chip {
    border: 0;
    background: var(--ui-subtle); color: var(--ui-ink);
    font-size: var(--font-xs); padding: .2rem .55rem; display: inline-flex; align-items: center; gap: .3rem;
  border-radius: var(--sm-r-row); }
  .e-city { color: var(--ui-ink-muted); font-family: var(--kf-font-mono); font-size: var(--font-xs); }
  .e-chip-list { display: inline-flex; flex-wrap: wrap; gap: .3rem; }

  /* Cipurile de ÎNSCRIȘI iau culoarea categoriei — zona pe care publicul o caută vizual („cine
     s-a înscris") era gri-pe-alb și se pierdea. Fill DESATURAT (`--style-s-chip`) la aceeași
     luminozitate ca pastila: aceeași familie cromatică, rang vizibil mai jos, deci pastila
     stilului rămâne unicul element cu hue plin + text colorat.
     Șina de 2px NU e decor: pe dark un fill în hue e practic invizibil (`hsl(240 30% 22%)` pe
     `--kf-surface-bright` #1a1c17 = 1.21:1, sub cipul gri de azi) — pastila însăși se vede pe
     dark doar prin muchia colorată. Fără șină, „cipuri în culoarea categoriei" n-ar exista pe
     dark pentru hue-urile reci, adică pentru majoritatea stilurilor.
     Aceeași pastilă și pe cardul de categorie de pe /concursuri (`.cl-cat`, ADR 0058 am.2) — o regulă, două locuri.
     Tenta se MOȘTENEȘTE din strămoș (`--style-h` pe rând / pe card), nu se pune pe cip → cipurile
     adăugate prin Turbo Stream (_register.stream) sunt colorate fără cod în partial.
     ⚠️ B226 (2026-10-07): umplerea în hue a plecat. Pe pagina coborâtă tenta stătea la 1.01 pe pagină și 1.00 pe cutia s2, pentru
     cea mai slabă nuanță — o tentă trece 1.2 doar dacă e practic albă. Cipul e acum o treaptă DEASUPRA zonei gri
     (`--sm-chip-surface`: alb pe light, 1.33 cutie / 1.21 pagină; s3 pe dark, 1.41 / 1.67), iar culoarea categoriei e DOAR
     dunga — aceeași regulă în ambele locuri (ownerul: „SSOT, aceeași culoare, că doar e același fundal").
     Text: `--kf-text` 18.07 light / 9.84 dark · `.e-city` 7.38 / 6.41 · dunga, cel mai rău hue, 1.88 pe alb / 2.92 pe s3.
     ⚠️ B228.2 (după Arena): placa a devenit ALBĂ pe deschis, iar „treapta deasupra” (`--ui-lifted`) e tot alb → cipul ieșea alb pe
     alb (1.00). Cipul stă acum pe `--ui-quiet`, griul avatarului și al insignei: deschis `#d0d0cb` (1.55 pe placă, 1.31 pe pagină;
     cerneala 12.78, orașul 5.67), închis neschimbat (`#2c2c31` = vechiul `--ui-lifted`). */
  .cat-entries-row .e-chip,
  .cl-cat .e-chip {
    background: var(--ui-quiet);
    border-left: 2px solid hsl(var(--style-h, 0) var(--style-s, 70%) var(--style-l-accent, 45%));
    color: var(--ui-ink);
    padding-left: .42rem;
    /* Două rânduri (B204): pastila de 30px pe un rând ajunge ~33px pe două, nu 37 — rezerva verticală se strânge. */
    padding-block: .1rem;
  }

/* PASTILA DE ÎNSCRIS PE DOUĂ RÂNDURI (B204, ADR 0058 am.3) — numele sus, crew-ul unui solo / membrii unei echipe dedesubt: lățimea
   pastilei o dă cel mai lung dintre ele, nu suma lor (măsurat pe dev: 132 → ~98px în medie). Layoutul stă pe CORPUL randat de
   `_entry_chip` (`.e-chip__body`), NU pe `.e-chip`: calificarea are markupul ei de `.e-chip` și rămâne pe un rând.
   `line-height: 1.15` = cel al cardului de persoană (`.person-card__nm`) — mai strâns, Î / Ș de pe rânduri vecine se ating. Rândul 2
   e mereu randat și rezervă o linie (`1lh`) → pastilele de pe un rând au aceeași înălțime, cu sau fără crew. Fără podea `--tap-*`:
   bula e o țintă secundară, anulabilă dintr-o atingere, iar pastila trece singură de 24px (UI_RULES „Ținte touch"). */
.e-chip__body { display: grid; flex: 1 1 auto; min-width: 0; line-height: 1.15; }
.e-chip__body > .e-city { display: block; min-height: 1lh; }
/* Echipa: membrii NU lărgesc pastila — `contain: inline-size` le anulează lățimea proprie (aceeași mișcare ca în `scoreboard.css`
   la numele din bracket), deci o dă numele echipei, cu o podea de ~10 caractere („TNT" ar fi arătat „Ana…"). Lista întreagă e în
   bulă. Crew-ul unui solo NU se taie: n-ar avea unde să reapară. */
.e-chip--team { position: relative; min-width: 10ch; }
.e-chip--team .e-city { contain: inline-size; overflow: hidden; text-overflow: ellipsis; }
/* Corpul echipei e BUTONUL bulei: doar longhanduri (un `font: inherit` ar bate mărimea pastilei de pe pagina categoriei — reboot-ul
   Bootstrap moștenește deja familia și mărimea), iar `::after` întinde ținta pe toată pastila, inclusiv pe rama ei. */
button.e-chip__body {
    appearance: none; margin: 0; padding: 0; border: 0; background: none;
    color: inherit; text-align: start; cursor: pointer;
}
button.e-chip__body::after { content: ""; position: absolute; inset: 0; }
@media (hover: hover) {
    .e-chip--team:not(.e-chip--out):hover .e-chip__name { text-decoration: underline; text-underline-offset: .15em; }
}
/* BULA cu membrii (Popover API: se deschide la atingere / click, se închide la Esc și la o atingere în afară; hover-ul îl adaugă
   `toggletip_controller.js`). Stă în stratul de deasupra paginii (top layer), deci nu o taie nici cardul, nici containerul listei.
   Aspectul e al explicației ⓘ (`.fhint__box, .e-members`, mai sus). Ascunsă și unde Popover API lipsește; `:popover-open` stă în
   regula LUI — un browser care nu-l înțelege ar arunca toată lista de selectori. */
.e-members {
    display: none; max-width: min(20rem, 80vw); padding: .35rem .5rem;
    font-size: var(--font-sm); white-space: normal; text-align: start; cursor: auto;
}
.e-members:popover-open { display: block; }
/* Ancorată SUB pastila ei (ancora = corpul, numele vine din `--em-anchor`, unic per înscriere, pus pe pastilă în Twig); întoarsă
   deasupra / spre stânga când nu încape. Fără ancorare CSS, bula rămâne centrată de browser — tot citibilă. */
@supports (position-area: block-end) {
    .e-chip--team > .e-chip__body { anchor-name: var(--em-anchor); }
    .e-members {
        position-anchor: var(--em-anchor); position-area: block-end span-inline-end;
        position-try-fallbacks: flip-block, flip-inline; inset: auto; margin: .25rem 0 0;
    }
}

/* 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: var(--type-control-case, uppercase); letter-spacing: var(--type-control-tracking, .03em); color: var(--ui-inverse);
    text-decoration: underline; text-underline-offset: 2px;
}
.chips-more-btn:hover { color: var(--ui-ink); }

/* ROSTER-ul organizatorului (B225, ADR 0058 am.5) — lista de înscriși a unei categorii DRAFT / OPEN, doar pentru organizator.
   Înlocuiește pastilele `.e-chip-del`: la ✓ pastila se lățea și lista se reașeza. Un înscris = UN RÂND pe coloane FIXE
   `[✓] [nume + rândul 2] [★] [×]` (NN/g: o înregistrare cu mai multe câmpuri = rând, nu chip — UI_RULES „O listă de ÎNREGISTRĂRI");
   nimic nu se mișcă la schimbarea stării: căsuța, ★ și × au lățimi fixe, slotul spinnerului e rezervat. Prototipul ales de owner
   (2026-10-06): „✓ pe căsuța lui" + „câte încap" pe lat (≥ 18rem; pe telefon o coloană). Zebră, fără rame (cast-ui §3); prezent = tenta
   de azi (`--sm-sage-fill`, perechea auditată), invitat = ★ pe umplerea de identitate (stare selectată), retras = tăiat. */
.roster { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 18rem), 1fr)); column-gap: 1rem; margin-top: .25rem; }
.roster__row {
    display: grid; grid-template-columns: 2.5rem minmax(0, 1fr) 2.5rem 2.5rem; align-items: center; gap: 0 .35rem;
    padding: .15rem .25rem .15rem 0; border-radius: var(--radius-row, 0);
    color: var(--ui-ink);
}
.roster__row:nth-child(even) { background: var(--ui-zebra); }
.roster__row--in,
.roster__row--in:nth-child(even) { background: var(--ui-present); color: var(--ui-on-present); }
.roster__row--out .roster__name { text-decoration: line-through; opacity: .75; }
/* Formularele nu desenează nimic: butonul lor e celula grilei. */
.roster__form { display: contents; }
/* Cele trei controale. ✓: ținta = celula întreagă (2.5rem; 44px pe telefon, base-layout.css), desenul = căsuța din ea. ★ / ×: cercuri
   de 2rem (44px pe telefon), centrate în celula lor. */
.roster__present, .roster__inv, .roster__del {
    appearance: none; display: inline-flex; align-items: center; justify-content: center;
    border: 0; background: transparent; color: var(--ui-ink-muted); cursor: pointer; padding: 0;
}
/* Înălțimea rândului o dă căsuța (2.5rem) — podeaua stă pe CONTROL, nu pe rând (SitePaletteCssScopeTest). */
.roster__present { justify-self: stretch; align-self: stretch; min-height: 2.5rem; }
.roster__inv, .roster__del { justify-self: center; inline-size: 2rem; block-size: 2rem; border-radius: 50%; }
/* ✓ prezent = căsuța rotundă, goală / plină (linia unui control de formular e permisă — WCAG 1.4.11). */
.roster__box {
    display: inline-flex; align-items: center; justify-content: center; inline-size: 1.75rem; block-size: 1.75rem;
    border-radius: 50%; border: 2px solid var(--ui-ink-muted); color: transparent; font-size: var(--font-md);
}
.roster__row--in .roster__box { background: var(--ui-ok); border-color: var(--ui-ok); color: var(--ui-page); }
.roster__who { min-width: 0; display: flex; align-items: center; gap: .4rem; }
.roster__txt { min-width: 0; display: flex; flex-direction: column; line-height: 1.2; }
.roster__name { font-weight: 700; font-size: var(--font-md); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.roster__sub { font-size: var(--font-sm); color: var(--ui-ink-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-block-size: 1.2em; }
.roster__row--in .roster__sub { color: inherit; opacity: .8; }
/* ★ pornit = umplerea de identitate (stare selectată); × roșu doar la hover (ireversibil). */
.roster__inv, .roster__del { font-size: var(--font-md); line-height: 1; }
.roster__del { font-size: var(--font-lg); }
.roster__inv--on { background: var(--ui-accent-fill); color: var(--ui-on-accent-fill); }
@media (hover: hover) {
    .roster__inv:hover { background: var(--ui-quiet); color: var(--ui-ink); }
    .roster__inv--on:hover { background: var(--ui-accent-fill); color: var(--ui-on-accent-fill); }
    .roster__del:hover { background: var(--ui-danger); color: var(--on-danger); }
}
/* Spinnerul: slotul e MEREU acolo (lățime fixă), vizibil doar pe `.is-busy`; cât procesează, al doilea tap pe rând e ignorat. */
.roster__spin { flex: none; inline-size: 1rem; block-size: 1rem; }
.roster__row.is-busy { opacity: .65; }
.roster__row.is-busy .roster__spin { border: 2px solid var(--ui-hair); border-top-color: var(--ui-accent); border-radius: 50%; animation: roster-spin .6s linear infinite; }
.roster__row.is-busy button { pointer-events: none; }
@keyframes roster-spin { to { transform: rotate(360deg); } }

/* --- 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: var(--type-status-tracking, .04em); text-transform: var(--type-status-case, uppercase);
    padding: 0 3px; border-radius: var(--radius-sm);
    background: var(--ui-inverse); color: var(--ui-on-inverse); vertical-align: middle;
}
/* --- Retras / Neprezentat (ADR 0039) — statusul spune adevărul, nu note de 0 --- */
/* Frate cu .e-chip__inv (aceeași anatomie de micro-badge), dar NEUTRU: retragerea e informație,
   nu accent. Numele retrasului se taie discret — încă lizibil (istoria rămâne pe ecran).
   `--font-xs` (11px), nu `--font-2xs` (9.6px): eticheta se citește, nu se ghicește (B158.b). În bracket are mărimea ei, din
   container (`scoreboard.css`, `.bk-entry .e-chip__out`). */
.e-chip__out {
    font-size: var(--font-xs); font-weight: 700; letter-spacing: var(--type-status-tracking, .04em); text-transform: var(--type-status-case, uppercase);
    padding: 0 3px; border-radius: var(--radius-sm);
    background: var(--ui-ink-muted); color: var(--ui-flat); vertical-align: middle;
}
.e-chip--out { text-decoration: line-through; opacity: .75; }
.bgc__row--out .bgc__name { text-decoration: line-through; opacity: 1; }
.bgc__dot--out { background: var(--ui-ink-muted); }
/* Corecțiile „la obiect" (ADR 0039, iter. 2) — declanșator mic pe rândurile cu nume (grupă /
   calificați / necalificați) + modalul de corecții. Dropdown-ul a fost ÎNLOCUIT cu modal:
   overlay fix = zero clipping (.bgc/.bk-battle au overflow:hidden).
   ⚠️ Protecția față de morph NU e garda de poll (ea se evaluează la începutul vizitei, deci un tick
   deja în zbor tot ateriza peste modal — bugul din iter. 2m): stă în `modal-morph-guard.js`, care
   sare peste `.modal.show` la `turbo:before-morph-element`. */
.cm-trigger {
    appearance: none; border: 0; background: transparent; cursor: pointer;
    /* Culoare EXPLICITĂ de temă, nu inherit (iter. 2c): rândurile colorate (activ/gata) își
       vopsesc numele, iar pe tema închisă moștenirea făcea creionul invizibil. */
    /* ⚠️ Opacitate PLINĂ și culoarea de text, nu `--fg2` la 70%: pe rândurile calificaților
       (`.qual-2col--in`, fundal `--success-soft`) ieșea verde-pe-verde și se vedea DOAR la hover
       — raportat de owner 2026-08-31. Un declanșator care nu se vede e un buton care nu există. */
    color: var(--ui-ink);
    padding: 0 4px; font-size: var(--font-sm); line-height: 1; opacity: 1;
}
.cm-trigger:hover { background: var(--ui-quiet); color: var(--ui-ink); }
.cm-body .cm-lbl { font-weight: var(--type-label-weight, 700); font-size: var(--font-sm); text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .04em); }
.cm-body .cm-warn { font-size: var(--font-xs); color: var(--warning-ink, var(--ui-ink)); background: var(--ui-warning-soft); padding: .3rem .5rem; border-radius: var(--radius-sm); }
.cm-sep { margin: .75rem 0; border-color: var(--ui-hair); opacity: 1; }


/* 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; }


/* (.dancer-lbl = definită mai sus, în secțiunea form; dup scos. `.pc-form-title` a fost ștearsă
   2026-08-21 odată cu formularul inline de înscriere.) */

/* Autocomplete dancer name */
.ac-wrap { position: relative; }
/* `.email-typo` = sugestia „Ai vrut gmail.com?" (B184, email_typo_controller.js): aceeași casetă plutitoare, alt conținut. */
.ac-dropdown,
.email-typo {
    display: none; position: absolute; top: 100%; left: 0; right: 0;
    background: var(--ui-flat); border: 2px solid var(--ui-line);
    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,
.email-typo.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(--ui-hair); line-height: 1.45;
    background: var(--ui-flat);
}
.ac-item:last-child { border-bottom: none; }
/* Rândurile sugestiei sunt BUTOANE (alegeri reale, cu tastatura): doar longhanduri, ca `.ac-item` să-și păstreze mărimea, umplerea
   și linia de jos; restul ramei de buton dispare. */
button.email-typo__opt {
    appearance: none; display: block; width: 100%; margin: 0;
    border-width: 0 0 1px; color: inherit; font-family: inherit; text-align: start;
}
.ac-item:hover, .ac-item.ac-item--hover { background: var(--ui-quiet); color: var(--ui-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(--ui-hair); border-radius: var(--radius-sm); color: var(--ui-ink-muted);
}
.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(--ui-subtle); border-radius: var(--radius-sm); color: var(--ui-inverse); background: var(--ui-subtle);
}
.ac-item:hover .ac-role, .ac-item.ac-item--hover .ac-role { color: inherit; border-color: currentColor; background: transparent; }
.ac-hint { margin-top: 2px; margin-bottom: 4px; text-wrap: pretty; }

/* ---- BUTONUL DE TRIMITERE AL FORMULARULUI: venit din kf-skin.css la B159 L10 (F1) ----
   Neprefixat, aceeasi specificitate ca regulile de baza → decide ordinea in text, exact
   precedenta pe care o dadea layerul inainte. */
  /* Ramase AICI la B159 L10 (F1), cand restul formularului a plecat in components.css: selectorul
     atarna de familia `.btn-ink`, inca in `@layer components`. Mutate, ar fi fost umbrite pe toate
     cele 12 declaratii — adica moarte. Pleaca odata cu butoanele. */
  .entry-form .btn-ink {
    border: 0; border-color: var(--ui-accent-fill); border-radius: var(--radius-control, 0);
    font-family: var(--kf-font-mono); font-weight: 700; padding: .65rem 1.5rem;
    text-transform: var(--type-control-case, uppercase); letter-spacing: var(--type-control-tracking, .06em);
    transition: none;
  }


/* ---- FORMULAR DE INSCRIERE: venit din kf-skin.css la B159 L10 (F1) ----
   Neprefixat, aceeasi specificitate ca regulile de baza → decide ordinea in text, exact
   precedenta pe care o dadea layerul inainte. */
  /* ---- Formular înscriere inline (flat) ----
     Cutia `.ccat-form` a dispărut 2026-08-21 (formularul s-a mutat în modal — chrome-ul îl dă
     `.brand-modal` din base-layout). Ce era scopat pe ea și ține de FORMULAR, nu de cutie, a
     coborât pe `.entry-form` — singurul ancoraj corect, fiindcă el e pe `<form>`. */
  .ac-hint, .dancer-lbl {
    font-family: var(--kf-font-mono); font-size: var(--font-xs); text-transform: var(--type-label-case, uppercase);
    letter-spacing: var(--type-label-tracking, .04em); color: var(--ui-ink-muted);
  }

  /* Formular înscriere — strip „left-strip" DASHED pe stânga + colțuri rotunjite (nu cutie completă).
     Bordura e doar pe stânga; border-radius rotunjește boxul (fundal + capetele strip-ului) = look cool.
     SSOT prin clasa .entry-form pe <form> (_entry_form.html.twig) → identic pe ambele suprafețe
     publice, fiindcă amândouă randează acum ACELAȘI modal (_enroll_modal.html.twig).
     background-color, NU background: nu șterge săgeata select-ului. */
  .entry-form .form-control,
  .entry-form .form-select {
    border: 0; border-color: var(--ui-line); border-left: var(--entry-strip) dashed transparent;
    background-color: var(--ui-flat);
    color: var(--ui-ink); font-family: var(--kf-font-mono); font-size: var(--font-md);
    transition: border-left-color .12s;
  box-shadow: inset 0 0 0 1px var(--ui-line); border-left-color: transparent; }
  .entry-form .form-control::placeholder { color: var(--ui-line); }
  .entry-form .dob-row select { font-family: var(--kf-font-mono); }
  /* Regula de `:focus` a disparut intreaga: amandoua declaratiile ei (`border-left-color`,
     `box-shadow`) erau umbrite de skin, care da focusul prin conturul lui + inelul `:focus-visible`. */

  /* Starea câmpului = derivată din DOM, ZERO JS (UI_RULES „starea în CSS, nu în JS"). Standardul UX
     „reward early, punish late" (Baymard/Smashing): un câmp gol NEATINS nu e o eroare, deci nu e roșu.
     GOL = stripul punctat de mai sus (calm) · COMPLETAT = strip SOLID accent (confirmare pozitivă)
     · GREȘIT = roșu, dar numai după interacțiune/submit (`:user-invalid`, niciodată la încărcare).
     Grosimea nu se schimbă între stări (`--entry-strip`) → zero salt de layout la tastare.
     Select-ul n-are `:placeholder-shown` → „gol" = opțiunea fără valoare e cea bifată.
     Ordinea contează (specificitate egală): completat, apoi eroarea care îl bate. */
  .entry-form .form-control:not(:placeholder-shown),
  .entry-form .form-select:not(:has(option[value=""]:checked)) {
    border-left-style: solid;   /* `border-left-color` sters: skinul da culoarea fasiei */
  box-shadow: inset 0 0 0 1px var(--ui-ink); }
  .entry-form .form-control:user-invalid,
  
  /* submit → olive solid plat, hover invert instant. Scopat pe `.entry-form` (era pe `.ccat-form`):
     acum e ACELAȘI formular pe ambele suprafețe, deci și submitul arată la fel — înainte, pe pagina
     categoriei, butonul rămânea `.btn-ink` implicit. */
  /* `.entry-form .btn-ink` si `:hover` au coborat incoace odata cu familia `.btn-ink` (B159 L10, F3).
     Cat timp familia statea in `@layer components`, o regula de aici le-ar fi umbrit TOATE cele 12
     declaratii — de-aia au plecat impreuna, nu pe rand. */
  .entry-form .btn-outline-secondary {
      color: var(--ui-ink-muted);
    font-family: var(--kf-font-mono); text-transform: var(--type-control-case, uppercase); font-size: var(--font-xs);
  box-shadow: inset 0 0 0 1px var(--ui-danger); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.btn-outline-secondary { --bs-btn-color: var(--ui-ink); --bs-btn-bg: var(--ui-quiet); --bs-btn-border-color: var(--ui-line); --bs-btn-hover-color: var(--ui-ink); --bs-btn-hover-bg: color-mix(in srgb, var(--ui-ink) 12%, var(--ui-quiet)); --bs-btn-hover-border-color: var(--ui-line); --bs-btn-active-color: var(--ui-on-pressed); --bs-btn-active-bg: var(--ui-pressed); --bs-btn-active-border-color: var(--ui-pressed-edge); --bs-btn-disabled-color: var(--ui-ink-muted); --bs-btn-disabled-bg: transparent; --bs-btn-disabled-border-color: var(--ui-edge); }


/* Tabel categorii în card */
.pub-cat-table { font-size: var(--font-md); width: 100%; border-collapse: collapse; }
.pub-cat-table td { vertical-align: top; border: none; }
/* Fără fire între rânduri (B192 G2): zebra (`.kf-catrow--odd`) face despărțirea — „dacă ai zebră, nu-ți trebuie
   fire" (cast-ui regula 3). Singurul consumator e tabul Calificare. */

/* ---- VOCABULARUL DE SCOREBOARD (mono + majuscule): venit din kf-skin.css la B159 L10 (F1) ----
   Neprefixat, aceeasi specificitate ca regulile de baza → decide ordinea in text, exact
   precedenta pe care o dadea layerul inainte. */
  /* MONO pe label-uri/taguri care erau sans/display (semnal kf — nu vine din token) */
  /* `.cat-tabs .nav-link` a IEȘIT din lista asta 2026-08-15: familia lui o deține acum rolul de
     ETICHETĂ (components.css § 18b). Regula de aici, fiind în @layer components, ar fi bătut rolul
     indiferent de specificitate — adică rolul n-ar fi făcut nimic, tăcut. */
  .bk-col-label,
  .bgc__hdr, .tbl-th, .stat-value, .sc-totals__v,
  .sc-round__hd, .sc-totals__lbl, .sc-jt__jr,
  .bk-col-count,
  .tab-now,
  .adj-chip, .sc-jt__eq,
  /* Coloana juratului (nume + pastile) trece INTEGRAL pe mono — al treilea canal care o desparte de
     numele concurenților (2026-08-27, „ori alt font ori altă culoare"). Mărimea și `--fg3` fac
     diferența de ierarhie, mono o face de VOCE: jurații mono, concurenții Archivo 900. Fără font nou
     — Space Mono e deja încărcat și deja pe pastile.
     ⚠️ Ținta e SPANUL, nu celula: `.sc-jg__judge > span` își declară propriul `font-family` în
     `@layer app`, iar o declarație proprie bate MOȘTENIREA indiferent de layer (layerele arbitrează
     doar între declarații pe ACELAȘI element). Pe celulă regula ar fi fost inertă — capcana B105. */
  .sc-jg__pill, .sc-jg__judge > span,
  .bgc__ord, .bgc__state, .bgc__crew { font-family: var(--kf-font-mono); }
/* Scorul de calificare: cerneală 800 în ambele blocuri (B234, `.qual-col .stat-value` în scoreboard.css); un retras calificat se
   stinge. */
.qual-2col--in .kf-catrow:has(.e-chip--out) .stat-value { color: var(--ui-ink-muted); font-weight: 600; }

  /* UPPERCASE scoreboard pe nume (fontul rămâne) — și capul grilei jurat × rundă (B115) */
  .bk-entry__name, .sc-jt__jn { text-transform: var(--type-title-case, uppercase); letter-spacing: var(--type-title-tracking, .02em); }
  /* `letter-spacing` sters de aici: il da intreg rolul de ETICHETA, mai jos in acelasi bloc.
     Ramane majuscula — capul grilei e ETICHETA, numele e TITLU (L0.8b). */
  .sc-jg__judge { text-transform: var(--type-label-case, uppercase); }


/* ---- TABEL DE CALIFICARE: venit din kf-skin.css la B159 L10 (F1) ----
   Neprefixat, aceeasi specificitate ca regulile de baza → decide ordinea in text, exact
   precedenta pe care o dadea layerul inainte. */
  /* Tabel categorii (folosit de _qualification_section) */
  .pub-cat-table td { padding: .4rem .5rem; }
  /* ⚠️ Rezultatul calificării (iter. 2o) trebuie SCRIS AICI, nu în `@layer app`. Regulile de mai sus
     stau în `@layer components`, care bate `@layer app` prin ORDINEA layerelor, indiferent de
     specificitate — deci un `font-size`/`padding` pus pe `.qual-col .e-chip` în scoreboard.css ar fi
     fost INERT și ar fi trecut toate gate-urile (exact cazul B51 din UI_RULES, și cauza D1 a acestei
     iterații). Userul a cerut litere MARI și margini mici: pe proiector numele trebuie citit din
     fundul sălii, iar aerul dintre rânduri e spațiu furat de la nume. */
  .qual-col .pub-cat-table td { padding: clamp(.12rem, 1.1cqi, .5rem) clamp(.2rem, 1.4cqi, .6rem); }
  /* B234 (Arena): RÂNDURILE aerisite (se citesc din sală și de pe telefon), centrate pe verticală — capul de tabel își ține
     paddingul strâns (proba de paritate: pus pe toate celulele, capul creștea de la 20 la 31px). Numele = text pe cerneală. */
  .qual-col .kf-catrow td { padding-block: .55rem; vertical-align: middle; }
  .qual-col .e-chip {
    font-size: clamp(var(--font-xs), 3.8cqi, var(--font-3xl));
    padding: 0; background: none; font-weight: 700; color: var(--ui-ink);
    line-height: 1.35;
  }
/* Necalificații: numele rămân pe cerneală (B234), doar mai subțiri — tenta lipsă spune „n-au trecut". */
.qual-row--out .qual-name-cell .e-chip { color: var(--ui-ink); font-weight: 600; }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.qual-2col--in .qual-name-cell .e-chip--out { color: var(--ui-ink-muted); font-weight: 400; }


/* Rândul de entries */
.cat-entries-row { display: flex; flex-wrap: wrap; align-items: center; gap: 2px; margin-top: 3px; }

/* Badge format battle (1v1, 2v2) */
/* ⚠️ INSIGNELE DE PE RÂNDUL DE CATEGORIE (`.ccat__l1` pe /concursuri, până la B204) 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ă.
   ⚠️ CORECȚIE 2026-08-18: alinierea de mai sus era INERTĂ pe /concursuri. Insignele aveau atunci
   reguli `body.kf` în @layer components (kf-skin.css), care băteau orice de aici, din @layer app,
   indiferent de specificitate — deci pe pagina pentru care s-a făcut auditul rămăseseră .05 / .03.
   De la B159 L10 (F1) totul stă în fișierul ăsta, într-un singur layer. Istoric păstrat fiindcă
   explică de ce valorile arată așa; orice atingere viitoare de tracking se face în AMBELE
   locuri, altfel schimbi doar suprafețele legacy. */
.badge-battle-fmt { white-space: nowrap; }
/* Capul de panou de categorie: tracking-ul, venit din kf la B159 L10 (F1). */
.cat-panel-hdr { letter-spacing: var(--type-label-tracking, .04em); }
/* Coborata din `@layer skin` la B159 L10 (F2).
   ⚠️ PREFIXUL `.qual-tab ` A FOST SCOS pe 2026-09-28 (owner: „randul de inscrisi nu arata ca celelalte
   randuri"). Regula era scopata pe `.qual-tab`, care exista intr-un SINGUR loc
   (`_qualification_section.html.twig:29`) — dar componenta se randeaza in CINCI, iar doua sunt in
   afara lui: „Inscrisi" (`public/category.html.twig`, ramura de dinainte de start, unde `.qual-tab`
   nici nu exista pe pagina) si „Program" (modalul de detalii, plasat dinadins in afara oricarui
   container). Alea doua au ramas pe infatisarea legacy: 11.2px/600 pe fundal PLIN, fata de
   22.52px/800 transparent la fratii lor. Acelasi component, doua registre.
   ✅ Largirea e sigura pe MARIME fiindca `--sm-fs-title` e `clamp(…, 0.97rem + 0.7vw, …)` — `vw`, nu
   `cqi`, deci se rezolva identic inauntrul si in afara containerului. Daca era `cqi`, valoarea ar fi
   sarit afara din `.qual-tab` (capcana „o regula scopata mutata isi schimba rezultatul"). */
.cat-panel-hdr { align-items: baseline; padding: .6rem .9rem; background: transparent; color: var(--ui-accent); border-top: 0; border-bottom: 1px solid var(--ui-hair); border-left-color: transparent; font-size: var(--sm-fs-title); font-weight: 800; letter-spacing: .02em; }
/* B234 (Arena): numele panoului (Calificați / Necalificați / Înscriși) = titlu de afiș pe violetul de identitate, peste fir. */
.cat-panel-hdr > span:first-child { font-family: var(--font-display); font-weight: 900; font-stretch: var(--ar-wdth); text-transform: uppercase; letter-spacing: -.005em; font-size: clamp(1.35rem, 1rem + 1.2cqi, 2rem); line-height: .95; color: var(--ui-accent); }

/* ---- Accente, hover-uri si tab-uri de stare: venite din kf-skin.css la B159 L10 (F1) ----
   Destinatia e components.css, nu scoreboard.css: aceea se incarca INAINTE, deci regulile
   de aici pastreaza precedenta pe care le-o dadea layerul. */
  /* Accente lime PUNCTUALE (legacy folosea alt token → nu vin din remap) */
  /* Categoria activă = clar evidențiată: bordură accent groasă + bold + bulină lime (e clar pe ce categorie ești) */
  /* DOAR umplerea. Fostul `border: 2px solid` era un SHORTHAND: reseta și muchia colorată cu hue-ul
     stilului, și marcajul aprins de jos (UI_RULES, capcana „shorthand reset"). `font-weight: 700`
     a ieșit și el — greutatea o deține rolul de SUBTITLU (900).
     Bulina pulsantă `::after` = ȘTEARSĂ: pulsul înseamnă LIVE în restul aplicației
     (`.page-state__dot`), nu „selectat" — pe un concurs arhivat tabul activ pulsa degeaba. Tabul are
     deja trei indicatori de selecție, al patrulea era zgomot. */
  /* Toate trei regulile de aici erau MOARTE si au plecat: tabul de categorie activ, bulina LIVE si
     totalul evidentiat isi luau culorile din skin, care le rescria integral — iar regulile ALEA au
     coborat in fisierul asta la F2. Notele de deasupra raman: explica de ce umplerea e scrisa
     singura, fara scurtatura `border`. */

  /* Arheologie: aici stăteau override-urile kf pentru barele de magnitudine din celulele de scor.
     Barele au căzut pe 2026-09-01 odată cu `--sc-fill`/`--sc-edge` (arătau net/max lângă o cifră
     raw/max). `is-fav`/`is-tie` sunt acum MUCHII care iau `--success`/`--warning`, deja remapate kf
     în tokens.css — deci nu mai e nevoie de niciun override aici. */

  /* WINNER = lime: vine acum din tokenul global --winner-* (legacy :root + remap kf),
     citit de TOATE regulile is-win/winner (bk-entry, sc-hd__sub/__nm, bracket-entry).
     Zero override per-clasă aici → fără spoturi ratate. */

  /* Hover left-strip: `box-shadow` sters de aici — umbra vine intreaga de pe `.bk-battle`, a carei
     regula de skin a coborat in fisierul asta la F2. */
  .sc-jt__row:hover { background: var(--ui-subtle); }

  /* Chip-ul „ce e acum": fundalul lime remapat dădea text olive-pe-lime (mohorât, ilizibil).
     → text near-black pe lime = contrast brutalist curat. */
  .tab-now { color: var(--ui-ink); }

  /* Butoanele de acțiune: olive-solid avea text olive (on-primary, gândit pt LIME) →
     olive-pe-olive ilizibil. → text alb (on-solid) pe olive-solid = contrast clar.
     Scopate pe `.tab-actions` din iter. 2n (bara volt separată a dispărut). */
  .tab-actions .btn-warning, .tab-actions .btn-warning:hover {
    background: var(--ui-accent-fill); border-color: var(--ui-accent-fill); color: var(--ui-on-accent-fill);   /* G1b: rolul butonului plin */
    text-transform: var(--type-control-case, uppercase); border-radius: var(--radius-control, 0);
  }
  .tab-actions .btn-warning:hover { background: var(--ui-accent-fill-hover); border-color: var(--ui-accent-fill-hover); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.btn-warning { --bs-btn-color: var(--ui-on-accent-fill); --bs-btn-bg: var(--ui-accent-fill); --bs-btn-border-color: var(--ui-accent-fill); --bs-btn-hover-color: var(--ui-on-accent-fill); --bs-btn-hover-bg: var(--ui-accent-fill-hover); --bs-btn-hover-border-color: var(--ui-accent-fill-hover); --bs-btn-active-color: var(--ui-on-accent-fill); --bs-btn-active-bg: var(--ui-accent-fill-hover); --bs-btn-active-border-color: var(--ui-accent-fill-hover); --bs-btn-disabled-color: var(--ui-ink-muted); --bs-btn-disabled-bg: var(--ui-subtle); --bs-btn-disabled-border-color: var(--ui-subtle); }
  .tab-actions .btn-success, .tab-actions .btn-success:hover { text-transform: var(--type-control-case, uppercase); border-radius: var(--radius-control, 0); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.btn-success { --bs-btn-color: var(--ui-on-accent-fill); --bs-btn-bg: var(--ui-accent-fill); --bs-btn-border-color: var(--ui-accent-fill); --bs-btn-hover-color: var(--ui-on-accent-fill); --bs-btn-hover-bg: var(--ui-accent-fill-hover); --bs-btn-hover-border-color: var(--ui-accent-fill-hover); --bs-btn-active-color: var(--ui-on-accent-fill); --bs-btn-active-bg: var(--ui-accent-fill-hover); --bs-btn-active-border-color: var(--ui-accent-fill-hover); --bs-btn-disabled-color: var(--ui-ink-muted); --bs-btn-disabled-bg: var(--ui-subtle); --bs-btn-disabled-border-color: var(--ui-subtle); }


/* ---- INSIGNE DE FORMAT / TOP-N / DISCRIMINATOR: venit din kf-skin.css la B159 L10 (F1) ----
   Neprefixat, aceeasi specificitate ca regulile de baza → decide ordinea in text, exact
   precedenta pe care o dadea layerul inainte. */
  /* Aceeași pastilă pe linia de timp a programului, strânsă la lățimea unei coloane de stop.
     Declarată AICI, nu lângă restul lui `.tline` din components.css: regula de mai sus e în
     @layer components, deci ar bate orice variantă din @layer app pe `display`/`font-size`,
     indiferent de specificitate (UI_RULES, „capcana la variante/modifiere"). */
  .tline__cat {
    font-size: var(--font-2xs);
    border-left-width: 3px;
    padding: .1rem .34rem .1rem .26rem;
    letter-spacing: var(--type-label-tracking, .02em);
  }
  /* Tracking .04em (era .05): B51 aliniase grupul meta la o singură valoare, dar scrisese în
     @layer app — iar regulile de aici, din @layer components, îl băteau. Livrarea era inertă exact
     pe /concursuri, pagina pentru care fusese făcută. Cu titlul la .02em, o a patra valoare pe
     același rând ar fi readus fix problema pe care B51 o închidea. */
  .badge-battle-fmt {
    border: 0; border-radius: var(--radius-chip, 0);
    background: var(--ui-quiet); color: var(--ui-ink-muted);
    font-family: var(--kf-font-mono); font-weight: 700; font-size: var(--font-xs);
    padding: .2rem .5rem; text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .04em);
  }


/* Discriminatorii categoriei (U18, Feminin) — `_discriminators.html.twig`, aceeași insignă oriunde
   apare o categorie: pastilele paginii de concurs (rândul 2), cardul de pe /concursuri, titlul modalului
   de înscriere. Ele sunt exact diferența dintre două categorii cu același nume, deci trebuie să sară în
   ochi mai tare decât formatul.
   B219 (decizia ownerului, 2026-10-05): cipul e PLIN, „pe negativ" = perechea CTA neutru a paletei
   (cerneală pe hârtie pe light, hârtie pe cerneală pe dark), 12px, fără chenar / inel — rețeta componentei,
   aceeași în toate locurile (SSOT), nu una pe pastilă și alta pe card. Până la B219 era 9.6px, conturat,
   gri: pe card „nu se vedea că e Feminin" și omul se putea înscrie la categoria greșită. */
.cat-disc {
    font-family: var(--font-mono);
    font-size: var(--font-sm); font-weight: 700; line-height: 1.3; text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .04em);
    color: var(--ui-on-inverse); background: var(--ui-inverse);
    border: 0; border-radius: var(--radius-status, 999px);
    padding: .15rem .55rem; 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; }

/* Label număr dansator */

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


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

/* ×-ul stă în ANTETUL rândului (.category-row__hdr), nu absolut în colț. Varianta absolută cerea o
   rezervă de padding-right cât ținta de atingere, altfel câmpurile din flex-wrap ajungeau SUB buton
   și un tap pe „Vârstă" ștergea toată categoria. Cu antet, pericolul dispare din construcție. */
.category-row { border-radius: var(--radius-md); margin-bottom: 0.5rem; position: relative; padding: 8px 10px; border: 2px solid var(--ui-line); border-color: var(--ui-frame); }
/* Antetul rândului: identitatea categoriei, completată din selecturile de stil/format pe măsură ce
   omul le alege (category-builder.js). Fără el, la patru categorii deschise nu știi pe care ești. */
.category-row__hdr { display: flex; align-items: center; justify-content: space-between; gap: .5rem; margin-bottom: .35rem; }
/* Cerneala e fixă (--c-kf-on-var), ca tot textul de pe pastelurile rândului: pastelurile sunt
   deschise în AMBELE teme, deci un token tematic ar da text deschis pe fundal deschis pe dark. */
.category-row__title {
    font-family: var(--font-display); font-weight: var(--type-title-weight, 900); text-transform: var(--type-title-case, uppercase); letter-spacing: var(--type-title-tracking, .03em);
    font-size: var(--font-sm); color: var(--c-kf-on-var);
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.category-row--0 {  border-inline-start: 3px solid color-mix(in srgb, var(--style3-bg) 60%, var(--ui-ink)); }
.category-row--1 {  border-inline-start: 3px solid color-mix(in srgb, var(--style1-bg) 60%, var(--ui-ink)); }
.category-row--2 {  border-inline-start: 3px solid color-mix(in srgb, var(--style2-bg) 60%, var(--ui-ink)); }
.category-row--3 {  border-inline-start: 3px solid color-mix(in srgb, var(--style4-bg) 60%, var(--ui-ink)); }
.category-row--4 {  border-inline-start: 3px solid color-mix(in srgb, var(--style5-bg) 60%, var(--ui-ink)); }
.category-row--5 {  border-inline-start: 3px solid color-mix(in srgb, var(--style0-bg) 60%, var(--ui-ink)); }

/* 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 .jgrid__h,
.category-row .exhint,
.category-row .frow-gloss,
.category-row .judges-section__label { color: var(--ui-ink-muted); }
/* ✂️ SPART din lista de deasupra la B159 L10 (F2): cutia de explicație e singura din grup care ia
   cerneala TARE — e conținut la cerere, nu etichetă. Restul rețetei rămâne moștenit. */
.category-row .fhint__box { color: var(--ui-ink); }
/* Utilitarele Bootstrap au `!important` în layer(vendor), deci un `!important` de aici PIERDEA (reguli inerte
   de la ADR 0023: pe dark `.text-muted` ieșea 1.5:1 pe pastel). Se schimbă prin variabilele lor, moștenite. */
.category-row { --bs-secondary-color: var(--ui-ink-muted); --bs-danger-rgb: var(--c-kf-error-rgb); background: var(--ui-subtle); }
.category-row .exhint--ok   { color: var(--ui-ok); }
.category-row .exhint--warn { color: var(--ui-warning); }
.category-row .exhint--err  { color: var(--ui-danger); }
/* Pickerul de copiere stă tot pe pastel → aceeași cerneală fixă; hover = ink și mai închis
   (fostul --fg1 era alb pe dark → ilizibil pe pastel). */
.category-row .copy-picker > summary,
.category-row .copy-picker__pick,
.category-row .copy-picker__note { color: var(--ui-ink-muted); }
.category-row .copy-picker > summary:hover { color: var(--ui-ink); }
[data-theme="dark"] .category-row .btn-close {  }  /* X-ul alb (dark) dispărea pe pastel */

.judges-section { border-top: 1px solid var(--ui-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(--ui-ink-muted); }

/* 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; }
/* Lista de 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. */
.staff-list { display: flex; flex-wrap: wrap; gap: .5rem .75rem; align-items: flex-end; }
.staff-list > .staff-inline-row { flex: 0 1 auto; }
/* MOMENTELE DE PROGRAM se citesc ca ÎNREGISTRĂRI SEPARATE, nu ca o listă de chipsuri: regula de mai
   sus le punea două pe același rând când era loc, iar câmpurile fiecăreia se rupeau între ele —
   „se întind una după alta, nu văd unde începe următorul" (owner). Un moment = un rând întreg, cu
   hairline deasupra. Separatorul e pe FIECARE rând, nu pe `+ .staff-inline-row`: pe /edit momentele
   stau în DOUĂ containere (salvate + noi), iar cusătura dintre ele e exact locul care se pierdea.
   Prima linie a primului container și-l scoate — n-are ce despărți. */
.staff-list--stacked > .staff-inline-row { flex: 1 1 100%; border-top: 1px solid var(--ui-hair); padding-top: .4rem; }
.form-panel__body > .staff-list--stacked:first-of-type > .staff-inline-row:first-child { border-top: 0; padding-top: 0; }
@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 / .staff-grp / .staff-grp__lbl șterse 2026-08-17 — gruparea pe rol a DJ/Host a
   fost înlocuită de grila .jgrid, cu rolul pe coloană; ultimul consumator era edit.html.twig.) */

/* === 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: 96px !important; }    /* opțiuni „2/grup" + eticheta „Format calif." (it. 5) */
.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: 72px !important; }
/* Rândul „Diviziune" (B218): nivelul („Intermediar"), numele (≤ 24 de caractere), iar regula ia restul rândului — e o propoziție. */
.input-w-level    { width: 104px !important; }
.input-w-division { width: 150px !important; }
.input-w-rule     { flex: 1 1 16rem; min-width: 0; }
/* Momentul de program: ORA și ZIUA, nu un `datetime-local`. Fostul `.input-w-when` cerea 168px
   (`zz.ll.aaaa --:--` încape fix), iar panoul stă într-o coloană de ~350px — rândul se rupea mereu. */
.input-w-hour     { width: 88px !important; }   /* `<input type="time">`: „--:--" + iconița nativă */
.input-w-day      { width: 96px !important; }   /* „Zi 2 · 02.06"; ascuns la concursul de o zi */
.input-w-schedcat { width: 108px !important; }  /* categoria momentului: se taie nativ, nu lățește rândul */
.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 ==================================== */

/* Coloana de rang + mini bar-ul bilanțului (`.stat-pct-value` / `.pct-*` au murit cu cardurile top 3, B214: ultimul consumator). */
.lb-col-rank    { width: 26px; }

/* `display: flex` (B219, bug raportat de owner: „bara de bilanț nu arată nimic"): umplerea `.bar-fill` e un `<span>` INLINE, deci
   `width: var(--w)` / `height: 100%` de mai jos nu i se aplicau — bara era goală din 2026-09-29 (B189). Ca item flex, cutia lui există. */
.stat-pct-bar   { display: flex; height: 3px; 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%; width: var(--w, 0%); }

/* Δ ELO (evoluția la ultimul concurs) + formă (ultimele 5 battle-uri, V/Î) — /clasament */
.lb-delta       { font-variant-numeric: tabular-nums; font-size: var(--font-sm); font-weight: 700; white-space: nowrap; }
.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; }


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


.entity-name { font-size: var(--font-md); }


/* Banda de tab-uri — dashboardul de admin (secțiuni) și clasamentul (stiluri de dans).
   E un RAIL (poartă `.rail` în markup): la 360px cele patru etichete de admin cer ~546px din 342
   disponibili, iar clasamentul are un tab per stil de dans, deci nemărginit.

   ⚠️ RIGLA E FUNDAL, nu `border-bottom` pe bandă + `margin-bottom: -2px` pe tab. Într-un container
   care scrollează, marja negativă iese din cutia de padding și e TĂIATĂ de `overflow` — exact
   capcana din UI_RULES. Fundalul unui container care scrollează NU se derulează
   (`background-attachment: scroll` ≠ `local`), deci tab-urile alunecă peste o linie fixă, iar
   muchia lor de jos cade exact peste ea: inactivele o lasă să se vadă prin borderul lor
   TRANSPARENT, activul o acoperă cu al lui. Aceiași pixeli ca înainte, fără marjă negativă. */
/* Cele patru marcaje `layer-shadow-ok` de aici au fost STERSE la B159 L10 F1, ca MARCAJE ORFANE:
   justificau o umbra data de `body.kf`, iar regula kf a coborat in acelasi layer — umbra nu mai exista.
   Motivul lor era oricum stins: „paginile fara kf (admin-*)" sunt azi `?tab=` pe admin/dashboard, care
   poarta `kf admin`. Singurele trei template-uri fara clasa sunt contest/edit, contest/new si
   _confirm_page, si niciunul n-are tab-uri de rol. */
.role-tabs {
    display: flex; gap: 0; margin-bottom: 1rem;
    background: linear-gradient(to top, var(--ui-line) 2px, transparent 2px);
}
.role-tab {
    padding: 0.35rem 0.9rem; font-family: var(--font-display); font-size: var(--font-md); font-weight: 700;
    text-transform: var(--type-tab-case, uppercase); letter-spacing: var(--type-tab-tracking, 0.06em);
    color: var(--ui-ink-muted); border-bottom: 3px solid transparent;
    text-decoration: none; white-space: nowrap;
    scroll-snap-align: start;
    transition: color .1s, border-color .1s;
}
.role-tab:hover  { color: var(--ui-inverse); }
.role-tab.active { color: var(--ui-ink); border-bottom-color: var(--ui-inverse); }

/* ---- TAB-URI DE ROL (admin, clasament): venit din kf-skin.css la B159 L10 (F1) ----
   Neprefixat, aceeasi specificitate ca regulile de baza → decide ordinea in text, exact
   precedenta pe care o dadea layerul inainte. */
  .role-tabs {
    border-bottom: 0; gap: 0;
    background: linear-gradient(to top, var(--ui-hair) 1px, transparent 1px);
  }
  /* B234 (Arena): tabul de rol (/clasament, adminul) = titlu condensat, 900; cazul și tracking-ul vin din rolul `tab`. */
  .role-tab {
    font-family: var(--kf-font-mono); text-transform: var(--type-tab-case, uppercase);
    letter-spacing: var(--type-tab-tracking, .04em); font-size: var(--font-xs); color: var(--ui-ink-muted);
    font-weight: 900; font-stretch: var(--ar-wdth);
    border-bottom: 2px solid transparent;
  }
  .role-tab:hover { color: var(--ui-ink); background: var(--ui-subtle); }
  .role-tab.active {
    color: var(--ui-ink); border-bottom-color: var(--ui-accent-fill);   /* ADR 0057: sublinierea activă = tonul de UMPLERE (semn grafic) */
  }


/* .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; }
/* Fără fire între rânduri (L2, ADR 0026 am.8): toți consumatorii — clasamentul, finalul Smoke, jurnalul de
   corecții — își despart rândurile prin ZEBRĂ („dacă ai zebră, firele nu mai trebuie", cast-ui §3). Fără hover
   de rând pe bază: rândurile nu fac nimic la click; clasamentul își are hover-ul lui, pe rândul apăsabil. */
.tier-table td   { padding: 0.3rem 0.5rem; vertical-align: middle; }
/* Jurnalul de corecții în panoul paginii lui (`.form-panel`): zebră pe rânduri. Specificitate (0,2,x) — nu
   depinde de ordinea față de `.tier-table td`. */
.tier-table.corrections-log { margin: 0; }
.tier-table.corrections-log tbody tr:nth-child(even) td { background: var(--ui-zebra); }
/* Jurnalul de corectii (`/cont/{id}/edit`): DOUA coloane care nu se rup — data completa si numele
   autorului — impuneau impreuna un minim mai mare decat ecranul. Tabelul iesea la 389px pe un ecran
   de 320 (B173, masurat: 389/320 · 390/360 · 391/390 · exact 414/414, adica la limita).
   ⚠️ Nowrap-ul sta AICI, nu pe utilitarul `.text-nowrap`: acela are `!important` in `@layer vendor`,
   iar la `!important` ordinea layerelor se INVERSEAZA — vendorul bate `@layer app`, deci utilitarul
   nu se poate retrage din CSS-ul nostru. Singura cale e sa nu fie pus in markup.
   Sub pragul de telefon al casei (640px) se retrage: data se rupe intre zi si ora, numele intre
   cuvinte. `normal` nu FORTEAZA ruperea, o permite — deci pe ecranele unde incape, nimic nu se misca. */
.tier-table .tt-when,
.tier-table .tt-who { white-space: nowrap; }
@media (max-width: 640px) {
    .tier-table .tt-when,
    .tier-table .tt-who { white-space: normal; }
}

/* ---- Clasament: venit din kf-skin.css la B159 L10 (F1) --------------------------------
   Neprefixat, aceeasi specificitate ca regulile de baza de mai sus → decide ordinea in text,
   exact precedenta pe care o dadea layerul inainte. */
  /* Panou leaderboard. B189 (varianta B validată de owner): FĂRĂ ramă — panoul se desprinde de pagină
     prin treapta tonală + umbră (Refactoring UI „use fewer borders", Material 3 „tonal surfaces",
     `kinetic_flow` „line-less"). Rama de 1px `--sm-card-edge` a fost ultima „linie fără sens" de aici. */
  .lb-panel { border: 0; border-radius: var(--radius-card, 0); }
  /* B189: capul e TITLU (numește exact conținutul căutat — ADR 0054 D7), pe violetul de identitate
     (ADR 0057). Rigla de sub el a plecat odată cu rama panoului. */
  .lb-panel__head {
    font-family: var(--kf-font-display); font-weight: var(--type-title-weight, 800); font-stretch: var(--ar-wdth);
    text-transform: var(--type-title-case, none); letter-spacing: var(--type-title-tracking, 0);
    color: var(--ui-accent);
  }
  /* Contorul = pastilă retrasă lângă titlu, nu al doilea titlu. */
  .lb-panel__head .lb-panel__count {
    font-family: var(--kf-font-mono); color: var(--ui-ink-muted);
    background: var(--ui-sunken); border-radius: var(--radius-status, 0); padding: .05rem .5rem;
  }

  /* Tabel ELO — fără fire (zebra separă intrările, `.tier-table td` nu mai desenează nimic), header mono.
     B189: doar rândul PRINCIPAL al intrării — detaliile nu sunt apăsabile. Umbrită de regula din blocul
     de hover de la coada fișierului (același selector, mai jos), ca și înainte. */
  .lb-panel .tier-table tbody.lb-entry > tr.lb-row:hover td {
    background: var(--ui-subtle); color: var(--ui-ink);
  }
  .lb-panel .tier-table tbody.lb-entry > tr.lb-row:hover td:first-child {
    box-shadow: var(--shadow-hover-strip, inset 4px 0 0 var(--ui-ink));
  }
  /* ⚠️ `background` OBLIGATORIU aici. Regula de bază (@layer app) pune
     `background: var(--surface-inverse)` = bandă neagră cu text alb. Override-ul ăsta schimba DOAR
     `color`, la un gri de text-variant → gri închis pe negru în light (1.83:1) și gri deschis pe
     alb în dark (1.70:1), fiindcă `--surface-inverse` se întoarce cu tema. Jumătate de pereche
     rescrisă = cel mai ușor bug de scăpat: ambele valori sunt „corecte", dar nu una lângă alta. */
  .tier-table-header th {
    font-family: var(--kf-font-mono); text-transform: var(--type-label-case, uppercase);
    letter-spacing: var(--type-label-tracking, .04em); font-size: var(--font-xs);
    background: var(--ui-quiet); color: var(--ui-ink-muted);
    border-bottom: 1px solid var(--ui-hair);
  }

  .entity-name {
    font-family: var(--kf-font-display); font-weight: var(--type-title-weight, 900);
    letter-spacing: var(--type-title-tracking, .01em); color: var(--ui-ink);
  }
  /* ELO = cifra-vedetă, pe violetul de identitate (B189, ADR 0057) — și pe rândurile top 3 de pe home. Aceeași regulă
     dă cifra-cheie a finalului Smoke (victoriile, `.smoke-standings__key` — L2, ADR 0026 am.8). */
  .lb-elo, .smoke-standings__key {
    font-family: var(--kf-font-display); font-weight: var(--type-number-weight, 900); color: var(--ui-accent);
  }
  .lb-meta { color: var(--ui-ink-muted); }
  .lb-meta__cc { font-family: var(--kf-font-mono); color: var(--ui-ink); }
  .lb-empty { font-family: var(--kf-font-mono); color: var(--ui-ink-muted); }

  /* Δ + formă pe skin kf */
  .lb-delta { font-family: var(--kf-font-mono); color: var(--ui-ink-muted); }
  /* B189 — mișcarea ratingului COLORATĂ, convenția ATP / lichess / bursă: sus = olive/lime (sensul
     „a câștigat" din ADR 0054), jos = roșul de pericol. ADR 0054 D3a le ținuse neutre; ownerul a cerut
     culoarea înapoi, pe prototip (amendament în ADR 0057). */
  .lb-delta--up { color: var(--ui-win-ink); }
  .lb-delta--down { color: var(--ui-danger); }
  /* Forma = PASTILE PLINE cu literă (Premier League / FotMob): victoria pe umplerea lime, înfrângerea pe
     umplerea de învins — exact vocabularul bracketului. Litera rămâne: culoarea nu e singurul canal.
     Perechi măsurate: on-accent / lime 15.28, text-mid / loser-fill 4.75 light · 5.44 dark. */
  .form-pip--w { background: var(--ui-win-fill); color: var(--ui-on-win-fill); }
  .form-pip--l { background: var(--ui-lose); color: var(--ui-on-lose); }
  /* Bara de bilanț în DOUĂ culori (op.gg): pista = înfrângerile, umplerea = victoriile. */
  .stat-pct-bar { background: var(--ui-lose); border-radius: var(--radius-chip, 0); }
  .stat-pct-bar .bar-fill, .bar-win {
    background: var(--ui-win-mark); border-radius: var(--radius-chip, 0);
  }

.tier-table-header th {
    font-weight: var(--type-label-weight, 900); padding: 0.25rem 0.5rem; 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(--ui-ink-muted); }

/* 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(--ui-rank-gold-ink);   font-weight: 900; }
.rank-2 { color: var(--ui-rank-silver-ink); font-weight: 900; }
.rank-3 { color: var(--ui-rank-bronze-ink); font-weight: 900; }
/* B234 (Arena): în coloana de loc a tabelelor de clasament (/clasament — dansatori + crew-uri — și finala Smoke) medalia e un DISC:
   umplerea de rang + cerneala ei, cifra centrată (perechile „podium: ink pe gold / silver / bronze”, deja măsurate). */
.col-rank-small .rank-1, .col-rank-small .rank-2, .col-rank-small .rank-3 {
    display: inline-grid; place-items: center; inline-size: 2rem; block-size: 2rem; border-radius: 50%; color: var(--ui-on-rank); font-weight: 900;
}
.col-rank-small .rank-1 { background: var(--ui-rank-gold); }
.col-rank-small .rank-2 { background: var(--ui-rank-silver); }
.col-rank-small .rank-3 { background: var(--ui-rank-bronze); }

/* -- Panoul de leaderboard (`/clasament`) ---------------------------------------------------
   MUTAT AICI din base-layout.css S17 pe 2026-08-23 (ADR 0023: S14 RANKING = components.css).
   Familia `.lb-*` era despicata intre doua fisiere - `.lb-col-rank`/`.lb-delta`/`.lb-form` aici,
   `.lb-panel`/`.lb-elo`/`.lb-meta` dincolo - deci cine cauta „stilurile de clasament” pe harta
   nu le gasea pe toate si risca sa scrie un duplicat.

   ⚠ ORDINEA in fisier e parte din contract, nu cosmetica: `@media` de la coada blocului trebuie sa
   ramana dupa `.lb-panel .tier-table td` - aceeasi specificitate (0,2,1), decide ordinea. Restul
   suprascrierilor din media sunt (0,2,0) peste (0,1,0), deci sunt sigure indiferent de pozitie.
   (Perechea `.lb-rate` / `.stat-pct-value`, care impunea si ea ordinea, a murit cu cardurile top 3 — B214.) -- */
/* Leaderboard (clasament) — panou înrămat scoreboard, rânduri dense pe o linie */
/* `container-type` (B189): pastilele, numele și ELO-ul se dimensionează din lățimea PANOULUI, iar sub
   25rem Bilanțul coboară sub formă (vezi „Rândul de clasament" mai jos). Panoul își ia lățimea din
   coloana grilei, deci nu e o gazdă dimensionată de conținut. */
.lb-panel { overflow: hidden; box-shadow: var(--ui-shadow-float); background: var(--ui-raised); container-type: inline-size; }
/* B234 (Arena): capul panoului = titlu de afiș, cât îl lasă PANOUL (container). Panta trece prin punctele machetei: 25.6px pe
   panoul de telefon (342px), 38.4px pe jumătatea de pagină la 1280 (616px) — măsurate de proba de paritate. */
.lb-panel__head {
    display: flex; align-items: center; gap: .45rem; padding: .8rem .75rem .55rem;
    font-size: clamp(1.6rem, .6rem + 4.7cqi, 2.4rem);
}
/* Culoarea și fontul contorului vin din regula `.lb-panel__head .lb-panel__count` de mai sus în
   fișier (coborâtă din kf la B159 L10, F1). Regula de contrast rămâne: accentul temei, NU `--volt`
   ca text pe suprafața light (~1.1:1). Vezi UI_RULES, blocul de contrast, punctul 8. */
.lb-panel__head .lb-panel__count { margin-left: auto; font-size: var(--font-xs); }

/* --- Primii 3 ca RÂNDURI (ranking/_top3.html.twig, B214 / ADR 0053 it. 6) — DOAR pe pagina de start (pe /clasament locurile 1-3
   stau în tabel). Forma din prototipul aprobat: un rând = card mic pe pagină (treaptă tonală + umbră, fără ramă — cast-ui §3), cu
   dunga de medalie pe toată înălțimea | avatarul | numele + meta | ELO peste formă. Trei unul sub altul la ORICE lățime (cardurile
   vechi făceau 2 + 1 la 414-600 și 1024px). Dunga = umplerea de rang --rank-* (theme-independent) cu cerneala --on-rank, perechi
   acoperite de contrast-audit la nivel de token (podium / on-medal); numărul locului e scris pe ea — culoarea nu e singurul canal.
   `--home-row-min` vine de pe `.home-two` (base-layout §17): rândul de top 3 și rândul arhivei de alături au aceeași înălțime. --- */
.lb-top3 { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .5rem; }
.lb-top3__row {
    display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto; align-items: center; gap: .75rem; padding-inline-end: .85rem; min-width: 0;
    min-block-size: var(--home-row-min, 0);
    background: var(--ui-raised); border-radius: var(--radius-card, 0); box-shadow: var(--ui-shadow-float);
    --av-size: 2rem; --_medal: var(--ui-rank-gold);
}
.lb-top3__row--2 { --_medal: var(--ui-rank-silver); }
.lb-top3__row--3 { --_medal: var(--ui-rank-bronze); }
.lb-top3__medal {
    align-self: stretch; display: grid; place-items: center; min-inline-size: 1.75rem; padding-inline: .25rem;
    /* Colțurile din stânga = ale cardului, fără `overflow: hidden` pe rând (ar tăia orice iese din el). Forma `border-radius` cu
       `var(--radius-*)` e cea pe care o acceptă TypeRoleTokensTest. */
    border-radius: var(--radius-card, 0) 0 0 var(--radius-card, 0);
    background: var(--_medal); color: var(--ui-on-rank);
    font-family: var(--font-display); font-weight: 900; font-stretch: var(--ar-wdth); letter-spacing: -.005em; font-size: var(--font-lg); font-variant-numeric: tabular-nums;
}
.lb-top3__txt { display: flex; flex-direction: column; gap: .1rem; min-width: 0; padding-block: .65rem; }
/* B234 (Arena): numele din top 3 = titlu de afiș (condensat, majuscule) — doar aici, nu în tabelul /clasament. */
.lb-top3 .entity-name { font-size: var(--font-lg); line-height: 1.15; overflow-wrap: anywhere; font-stretch: var(--ar-wdth); text-transform: var(--type-title-case, uppercase); }
.lb-top3__nums { display: flex; flex-direction: column; align-items: flex-end; gap: .3rem; }
.lb-top3__nums .lb-elo { font-size: var(--font-xl); }
/* Pastilele lipite ca în tabel: cu 5 rezultate + ELO, coloana din dreapta nu mănâncă numele la 320px. */
.lb-top3 .lb-form { gap: 2px; }

/* ── PODIUMUL CATEGORIEI (B223, ADR 0062) = aceleași rânduri, cu modificatorul `--podium`: campionul pe linia lui (numele CENTRAT pe pagină,
   trofeu), locurile următoare ca trei tile-uri pe a doua linie, la ORICE lățime (set fix 1 + 3 → fără orfani, ca la contoarele de pe prima
   pagină). Medalii COLORATE după locul real (aur / argint / bronz, locul 4 neutru — decizia revizuită a ownerului pe pagina reală: „prea șters
   fără nimic; un podium să fie citit dintr-o privire") și FĂRĂ avatar (decizia lui pe prototip: „culorile numelor + steagurile + restul paginii =
   prea încărcat"). A înlocuit bara CAMPION pe aur +
   pâlnia 2 / 3 / 4 din scoreboard.css (B190 / B190b): −21…−35 px pe telefon la bracket (măsurat). Consumatori: `_bracket_section`,
   `_smoke_section`, prin partialul `contest/category/_podium`. Pragul „tile îngust" vine din CONTAINER (`.bk-layout`, `.smoke-tab` au
   `container-type`), nu din @media. Prima pagină (`_top3` cu medalii colorate) NU e atinsă: totul e scopat pe `--podium`. ── */
/* Rândurile podiumului au ACEEAȘI înălțime (`grid-auto-rows: 1fr` = toate cât cel mai înalt): campionul nu e nici mai mare, nici mai
   mic decât locurile de sub el, oricâte linii are fiecare (B234 r2, ownerul: „la fel de înalt ca celelalte"). */
/* B223.2 (ownerul, 2026-10-13): pe desktop blocul are o lățime maximă și stă centrat — tile-urile de ~411px despărțeau cifra de nume
   (proximitate). Pe telefon limita nu se atinge; pe proiector se scoate (mai jos: acolo mărimile vin din `cqi`). */
.lb-top3--podium { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-rows: 1fr; gap: .5rem; margin: .5rem auto .75rem; max-inline-size: 48rem; }
.lb-top3--podium .lb-top3__row { grid-template-columns: auto minmax(0, 1fr) auto; gap: .5rem; padding-inline-end: .5rem; }
/* Medalia urmează LOCUL REAL (`--rank-N`, pus de partial), nu poziția din grilă: la Smoke rangurile se împart (1, 1, 3, 3) și un loc 1 de pe al
   doilea rând rămâne pe aur. Ownerul a încercat întâi varianta neutră și s-a răzgândit pe pagina reală (2026-10-06): „prea șters; un podium să fie
   citit dintr-o privire". Perechile: „podium: ink pe gold / silver / bronze"; locul 4 = „text-hi / s3". Specificitatea (0,2,0) bate `--2` / `--3` de bază. */
.lb-top3--podium .lb-top3__row--rank-1 { --_medal: var(--ui-rank-gold); }
.lb-top3--podium .lb-top3__row--rank-2 { --_medal: var(--ui-rank-silver); }
.lb-top3--podium .lb-top3__row--rank-3 { --_medal: var(--ui-rank-bronze); }
.lb-top3--podium .lb-top3__row--rank-4 { --_medal: var(--ui-quiet); }
.lb-top3--podium .lb-top3__row--rank-4 .lb-top3__medal { color: var(--ui-ink); }
.lb-top3--podium .lb-top3__txt { padding-block: .5rem; }
.lb-top3--podium .entity-name { font-size: var(--font-base); }
/* Linia secundară (crew / componenți) = UN rând, tăiat cu „…" (cast-ui §4); `title` poartă tot textul. Scopat: `.lb-meta` din tabel NU are nowrap. */
.lb-top3--podium .lb-meta { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-inline-size: 100%; }
/* Rândul campionului: coloanele laterale EGALE (`1fr auto 1fr`) → dunga la stânga, cifrele la dreapta, numele exact la mijlocul rândului
   (abatere 0 px, măsurat pe prototip la 360 și 1280). */
/* B234 (Arena): rândul campionului e AURUL întreg (umplerea de rang + cerneala ei); dunga medaliei se topește în el. Aceeași înălțime
   ca locurile de sub el (runda 2, ownerul: „prea mare, nu e nevoie să fie diferit"). */
.lb-top3--podium .lb-top3__row--1 { grid-column: 1 / -1; grid-template-columns: 1fr auto 1fr; padding-inline-end: 0; background: var(--ui-rank-gold); color: var(--ui-on-rank); }
.lb-top3--podium .lb-top3__row--1 .entity-name, .lb-top3--podium .lb-top3__row--1 .lb-meta, .lb-top3--podium .lb-top3__row--1 .lb-top3__trophy, .lb-top3--podium .lb-top3__row--1 .lb-top3__medal { color: var(--ui-on-rank); background: transparent; }
.lb-top3--podium .lb-top3__row--1 .lb-top3__medal { justify-self: start; }
.lb-top3--podium .lb-top3__row--1 .lb-top3__txt { text-align: center; align-items: center; }
.lb-top3--podium .lb-top3__row--1 .lb-top3__nums { justify-self: end; padding-inline-end: .5rem; }
.lb-top3--podium .lb-top3__row--1 .entity-name { font-size: var(--font-xl); }
.lb-top3--podium .lb-top3__row--1 .lb-meta { max-inline-size: min(100%, 60ch); }
.lb-top3--podium .lb-top3__row:not(.lb-top3__row--1) .lb-top3__medal { min-inline-size: 1.5rem; font-size: var(--font-base); }
/* Trofeul = singurul semn în afara cifrei (cu medalii neutre, el spune „campion" dintr-o privire); în cerneală, ca restul rândului. */
.lb-top3__trophy { color: currentColor; font-size: .8em; margin-inline-end: .35rem; vertical-align: 0; }
/* Cifrele (Smoke): V–Î ca vedetă (display, tabular), seria sub ea, retrasă — aceeași limbă ca tabelul de sub podium. */
.lb-top3--podium .lb-top3__nums { gap: .1rem; }
.lb-top3__rec { font-family: var(--font-display); font-weight: var(--type-number-weight, 900); font-size: var(--font-lg); line-height: 1.1; font-variant-numeric: tabular-nums; white-space: nowrap; }
.lb-top3__sub { font-size: var(--font-xs); color: var(--ui-ink-muted); white-space: nowrap; }
.lb-top3--podium .lb-top3__row:not(.lb-top3__row--1) .lb-top3__rec { font-size: var(--font-base); }
/* Sub 3 tile-uri (locul 3 încă de jucat, semifinale cu BYE): un tile → pe toată lățimea, două → jumătăți; fără găuri în grilă. */
.lb-top3--podium:has(> :nth-child(2):last-child) > :last-child { grid-column: 1 / -1; }
.lb-top3--podium:has(> :nth-child(3):last-child) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Tile-ul îngust (telefon: ~104px la 360): numele cu o treaptă mai mic, linia secundară la 2xs, cifrele SUB nume (nu lângă el), seria pleacă. */
@container (max-width: 40rem) {
    .lb-top3--podium .lb-top3__row:not(.lb-top3__row--1) { gap: .35rem; padding-inline-end: .4rem; }
    .lb-top3--podium .lb-top3__row:not(.lb-top3__row--1) .entity-name { font-size: var(--font-sm); }
    .lb-top3--podium .lb-top3__row:not(.lb-top3__row--1) .lb-meta { font-size: var(--font-2xs); }
    .lb-top3--podium .lb-top3__row:not(.lb-top3__row--1) .lb-top3__txt { padding-block: .45rem; }
    .lb-top3--podium .lb-top3__row:not(.lb-top3__row--1) .lb-top3__sub { display: none; }
    .lb-top3--podium .lb-top3__row:not(.lb-top3__row--1):has(.lb-top3__nums) { grid-template-columns: auto minmax(0, 1fr); grid-template-rows: auto auto; row-gap: 0; }
    .lb-top3--podium .lb-top3__row:not(.lb-top3__row--1):has(.lb-top3__nums) .lb-top3__medal { grid-row: 1 / 3; }
    .lb-top3--podium .lb-top3__row:not(.lb-top3__row--1):has(.lb-top3__nums) .lb-top3__txt { grid-row: 1; padding-block-end: 0; }
    .lb-top3--podium .lb-top3__row:not(.lb-top3__row--1):has(.lb-top3__nums) .lb-top3__nums { grid-row: 2; grid-column: 2; justify-self: start; align-items: flex-start; padding-block-end: .4rem; }
}
/* SALA: scara din container (`cqi` = `.bk-layout` / `.smoke-tab`) cu plafonul `--scale-cap`, ca rândurile vechi de campion / podium.
   Fără limita de lățime de pe pagină (B223.2): o limită fixă ar înghesui numele crescute de `cqi`. */
.live-projector .lb-top3--podium { max-inline-size: none; }
.live-projector .lb-top3--podium .lb-top3__row--1 .entity-name { font-size: clamp(var(--font-xl), 4cqi, calc(var(--font-xl) * var(--scale-cap, 1))); }
.live-projector .lb-top3--podium .lb-top3__row:not(.lb-top3__row--1) .entity-name { font-size: clamp(var(--font-base), 2.2cqi, calc(var(--font-base) * var(--scale-cap, 1))); }
.live-projector .lb-top3--podium .lb-top3__medal { font-size: clamp(var(--font-lg), 2.6cqi, calc(var(--font-lg) * var(--scale-cap, 1))); }
.live-projector .lb-top3--podium .lb-meta { font-size: clamp(var(--font-xs), 1.6cqi, calc(var(--font-xs) * var(--scale-cap, 1))); }
.live-projector .lb-top3--podium .lb-top3__rec { font-size: clamp(var(--font-lg), 2.6cqi, calc(var(--font-lg) * var(--scale-cap, 1))); }
/* Tile-urile: regulile lor de mărime de mai sus sunt (0,4,0) cu `:not(--1)`, deci scara de sală le scrie la aceeași specificitate + 1 — altfel pe
   sală ar scala doar campionul (revizia adversarială B223). */
.live-projector .lb-top3--podium .lb-top3__row:not(.lb-top3__row--1) .lb-top3__medal { font-size: clamp(var(--font-base), 2.2cqi, calc(var(--font-base) * var(--scale-cap, 1))); }
.live-projector .lb-top3--podium .lb-top3__row:not(.lb-top3__row--1) .lb-top3__rec { font-size: clamp(var(--font-base), 2.2cqi, calc(var(--font-base) * var(--scale-cap, 1))); }

.lb-panel .tier-table { margin: 0; }
.lb-panel .tier-table td { padding: .3rem .55rem; }
/* ELO = numărul-vedetă (fontul display și culoarea vin din regula `.lb-elo` de mai sus în fișier) */
.lb-elo { font-size: var(--font-lg); line-height: 1; }
/* meta (crew · oraș · țară) SUB nume, pe rândul ei — ownerul, B189: „să punem crewul, orașul și țara
   sub numele principal". Stivuirea o face `.lb-toggle__txt` (coloană), nu un `display` de aici.
   ⚠️ FĂRĂ `white-space: nowrap`: pe telefon el ținea min-content-ul coloanei de identitate la
   lungimea ÎNTREGULUI șir („Street Kids Crew · București · RO" ≈ 190px), deci tabelul nu se putea
   strânge deloc și restul coloanelor ieșeau din panou. Separatorii au spații în jur (` · `), deci
   ruperea cade natural între grupuri, nu în mijlocul unui nume.
   (`.lb-meta--sub` — a doua linie, „N concursuri · ultima: …" — a plecat în rândul de detalii, B189.) */
.lb-meta { font-size: var(--font-xs); }
.lb-meta__cc { white-space: nowrap; }
.lb-empty { padding: 1rem .65rem; font-size: var(--font-sm); }

/* ── Coloanele de cifre ale clasamentului (2026-08-23) ──────────────────────────────────────
   Redesign de ARHITECTURĂ A INFORMAȚIEI, nu doar de încadrare: erau 7 coloane pentru 5 fapte.
   ELO și Δ sunt aceeași cifră plus mișcarea ei (pattern ATP/FIFA), iar V–Î + Win% + bara sunt
   același record (pattern op.gg, referința declarată a esteticii dense a proiectului). Contopite,
   tabelul ajunge la 5 coloane și ÎNCAPE la 360px — la 7 coloane min-content-ul era ~480px într-un
   panou de ~340px, iar `overflow: hidden` de pe `.lb-panel` tăia ultimele două coloane FĂRĂ
   scrollbar: informație pierdută tăcut, nu derulabilă.

   Lățimile sunt PREFERINȚE în `rem` (urmează treapta de tipografie), una singură pentru ambele
   mărimi de ecran: în layout automat conținutul poate depăși preferința, deci pe desktop celula
   crește singură când cifra e mai mare. Fără prag dur = fără salt de aranjament.
   B189 (2026-09-29): a doua etapă a aceleiași idei — din 5 coloane au rămas TREI (# · nume · ELO).
   Formă, V–Î și Membri au plecat în rândul de detalii, cu etichete întregi; clasele lor de coloană
   (`.lb-col-form/-rec/-mem`) au plecat odată cu ele. */
/* Varianta B (2026-09-29): cele cinci coloane s-au întors, cu IERARHIE — cifrele CENTRATE în coloanele
   lor (cererea ownerului), ELO mai lat și mai mare decât vecinele. */
.lb-col-elo, .lb-col-form, .lb-col-rec, .lb-col-mem { text-align: center; white-space: nowrap; }
.lb-col-elo  { width: 4rem; }
.lb-col-form { width: 6.25rem; }
.lb-col-rec  { width: 3.75rem; }
.lb-col-mem  { width: 2.6rem; }

/* NU `display: flex` pe `td` — asta îl scoate din algoritmul de tabel și browserul îi fabrică o celulă
   anonimă în jur (lățimile de coloană devin sugestii ignorate). Copiii devin blocuri; alinierea rămâne
   treaba `text-align` de pe celulă. */
.lb-col-elo > * { display: block; }

/* ── Intrarea care se deschide (B189, owner 2026-09-29) ─────────────────────────────────────
   Numele e un BUTON (pattern APG disclosure; Roselli „Table with Expando Rows": comutatorul la
   începutul rândului). Bootstrap collapse ține `aria-expanded` și clasa `.show` pe rândul de detalii;
   fără `data-bs-parent`, oricâte stau deschise. Acțiunea principală a rândului → `--tap-min`. */
.lb-toggle {
    display: flex; align-items: center; gap: .4rem; width: 100%; min-height: var(--tap-min);
    margin: 0; padding: 0; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.lb-toggle__txt { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.lb-toggle__chev { flex: 0 0 auto; font-size: var(--font-xs); color: var(--ui-ink-muted); transition: transform .15s; }
.lb-toggle[aria-expanded="true"] .lb-toggle__chev { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
    .lb-toggle__chev { transition: none; }
}
/* `?` lipit de cifră = rating provizoriu (convenția lichess). Aceeași greutate ca cifra, culoarea
   retrasă: se citește ca o rezervă asupra numărului, nu ca un al doilea număr. */
.lb-prov { color: var(--ui-ink-muted); margin-left: .05em; }

/* ── Rândul de clasament — varianta B (B189, validată de owner pe prototip 2026-09-29) ─────────────
   Prima încercare (fișă cu „etichetă sus / valoare jos" sub nume) a fost respinsă: 9 linii pe telefon,
   etichete lungi, text mic la stânga. Regulile care au rămas sunt în UI_RULES „Tabel de clasament". */
.lb-row { cursor: pointer; }
/* Iconul unui drum spre LIVE poartă semnul de live (ADR 0054 §5), pe un buton care rămâne secundar. */
.live-ico { color: var(--ui-live-mark); }
.lb-table .entity-name { font-size: clamp(var(--font-base), 4.2cqi, var(--font-lg)); line-height: 1.2; overflow-wrap: anywhere; }
.lb-table .lb-elo, .lb-table .smoke-standings__key { font-size: clamp(var(--font-lg), 5cqi, var(--font-2xl)); line-height: 1.05; }
.lb-table .col-rank-small { font-size: var(--font-md); }
/* Crew-ul se distinge de loc (ownerul: „numele de crew nu e distinct de oraș") — cerneală plină, 600. */
.lb-meta__crew { color: var(--ui-ink); font-weight: 600; }
.lb-toggle[aria-expanded="true"] .lb-toggle__chev { color: var(--ui-accent); }
.lb-panel .tier-table-header th { background: transparent; }
.lb-panel .tier-table-header th:nth-child(n+3) { text-align: center; }

/* Pastila de formă: pătrat plin, mărimea din lățimea CONTAINERULUI cel mai apropiat — panoul pe /clasament, `.home` pe prima pagină
   (rândurile top 3: 14.7px la 360, 18px pe desktop; plafonul ține la 18px). Raza e PROPORȚIONALĂ cu pastila:
   la 8px (raza casei) un pătrat de 16px devine cerc. */
.form-pip {
    --_pip: clamp(14px, 4.3cqi, 18px);
    display: inline-grid; place-items: center; inline-size: var(--_pip); block-size: var(--_pip);
    border-radius: calc(var(--_pip) * .25); font-size: calc(var(--_pip) * .56); font-weight: 800;
}
.lb-table .lb-form { gap: 2px; justify-content: center; }

/* Bilanțul: cifrele deasupra, bara dedesubt. */
.lb-rec { display: inline-flex; flex-direction: column; align-items: center; gap: .25rem; }
.lb-rec__n { font-size: var(--font-md); font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ui-ink); }
.lb-rec .stat-pct-bar { inline-size: 2.5rem; block-size: 4px; margin: 0; }
.lb-mem { font-weight: 700; color: var(--ui-ink-muted); font-variant-numeric: tabular-nums; }
/* Panou ÎNGUST: coloana Bilanț se retrage și bilanțul coboară SUB pastile, în aceeași celulă — nicio
   informație ascunsă (NN/g „Mobile Tables": 2-3 coloane non-negociabile pe telefon). Doar la
   dansatori: la crew-uri Bilanțul e a patra coloană din cinci și încape. */
.lb-rec--inform { display: none; }
@container (max-width: 25rem) {
    .lb-table--dancers .lb-col-rec { display: none; }
    /* `flex`, NU `inline-flex` (B219, ownerul: „nu se stivuiau informațiile de pe Formă"): ca bloc, bilanțul coboară pe rândul LUI,
       sub pastilele de formă, în loc să stea lângă ele și să lățească coloana. `flex-direction: row` e scris explicit — `.lb-rec`
       de bază e `column`, iar fără el numărul ar urca peste bară. */
    .lb-rec--inform { display: flex; flex-direction: row; justify-content: center; gap: .35rem; margin-top: .3rem; }
    .lb-rec--inform .stat-pct-bar { inline-size: 1.9rem; }
    /* Lățimea fixă (6.25rem) era pentru cinci pastile + bilanț pe UN rând; stivuite, coloana ia cât are nevoie. */
    .lb-table--dancers .lb-col-form { width: auto; }
}

/* Rândul de detalii: UN rând, centrat, cu icon în loc de etichete lungi. `inline-size: 0` +
   `min-inline-size: 100%`: tabelul are layout AUTOMAT, iar un conținut `nowrap` i-ar fi impus
   lățimea minimă și l-ar fi lățit pe telefon — așa banda umple celula fără s-o împingă. Numele
   concursului se taie cu „…" când nu încape. */
.lb-panel .tier-table .lb-detail > td { padding-top: .1rem; padding-bottom: .6rem; }
.lb-strip {
    display: flex; align-items: center; justify-content: space-evenly; gap: .3rem 1rem;
    inline-size: 0; min-inline-size: 100%; white-space: nowrap;
    font-size: var(--font-sm); color: var(--ui-ink-muted);
}
.lb-strip__i { display: inline-flex; align-items: center; gap: .3rem; min-width: 0; }
.lb-strip__i .bi { color: var(--ui-accent); }
.lb-strip__i b { color: var(--ui-ink); font-weight: 700; }
.lb-strip__i--name { flex: 0 1 auto; overflow: hidden; }
.lb-strip__link { min-width: 0; overflow: hidden; text-overflow: ellipsis; color: inherit; text-decoration: none; }
a.lb-strip__link:hover { color: var(--ui-ink); text-decoration: underline; }

/* Crew-urile: ARBORE pe aceleași coloane. Membrii sunt rânduri-copil, cu conector desenat din pseudo-
   elemente (UI_RULES „Linie decorativă → pseudo-element"). */
.lb-panel .tier-table .lb-kid > td { padding-top: 0; padding-bottom: 0; }
/* Fără padding vertical pe rândul-copil: numele îi dă înălțimea, iar conectorul (fără offset negativ) umple
   tot rândul — liniile se leagă de la un membru la următorul. */
.lb-kid__name {
    position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 0 .4rem;
    min-block-size: 2.25rem; padding-inline-start: 1.1rem; font-size: var(--font-md); font-weight: 500;
}
.lb-kid__name::before {
    content: ""; position: absolute; inset-inline-start: .25rem; inset-block: 0 50%; inline-size: .55rem;
    border-inline-start: 1.5px solid var(--ui-line); border-block-end: 1.5px solid var(--ui-line);
    border-end-start-radius: var(--radius-sm);
}
.lb-kid:not(.lb-kid--last) .lb-kid__name::after {
    content: ""; position: absolute; inset-inline-start: .25rem; inset-block: 50% 0;
    border-inline-start: 1.5px solid var(--ui-line);
}
.lb-kid__elo { font-size: var(--font-base); font-weight: 700; color: var(--ui-ink); font-variant-numeric: tabular-nums; }
.lb-kid--out .lb-kid__name, .lb-kid--out .lb-kid__elo, .lb-kid--out .lb-rec__n { color: var(--ui-ink-muted); font-weight: 500; }
.lb-kid__avg { color: var(--ui-accent); }
.lb-panel .tier-table .lb-grp th { padding: .9rem .75rem .35rem; text-align: left; color: var(--ui-ink-muted); background: none; }
/* ── „STRÂNGE apoi TRAGE" pe telefon (UI_RULES, decizie user 2026-08-17) ───────────────────
   Pasul 1 (strânge): o treaptă de tipografie mai jos DIN TOKENI + padding de celulă redus.
   `@media` e legitim aici — e comutatorul de DENSITATE, nu o prăbușire de aranjament.

   ⚠️ Podeaua stă DOAR pe coloana de identitate. Regula generală („`th { min-width: 3.5rem }`")
   există fiindcă `overflow-wrap: anywhere` coboară min-content-ul până la o literă, deci fără podea
   tabelul ar încăpea MEREU, pulverizat. Aici numai `.col-entity` are proză și numai ea primește
   `anywhere`; celelalte patru sunt `nowrap` cu lățime proprie, deci nu se pot pulveriza. O podea de
   3.5rem pe ELE ar fi adăugat ~90px inutili și ar fi reintrodus tragerea laterală pe care contopirea
   tocmai a eliminat-o.
   Pasul 2 (trage) e în template: `.table-responsive.rail-fade` + `data-controller="rail"` pe panou —
   plasa de siguranță pentru 320px și numele foarte lungi. */
@media (max-width: 640px) {
    .lb-table { font-size: var(--font-sm); }
    .lb-panel .lb-table td { padding: .25rem .3rem; }
    /* Doar paddingul: restul tipografiei de antet vine din `.tier-table-header th`. */
    .lb-panel .lb-table th { padding: .25rem .3rem; }
    .lb-table .col-entity { min-width: 7rem; overflow-wrap: anywhere; }
    /* B189: ELO NU mai coboară la --font-md pe telefon — e cifra-vedetă și pe ecran mic (clamp din
       container), iar pastilele de formă își iau mărimea tot din container. */
}

/* -- Antet de tabel LIPICIOS: incercat 2026-08-23, RESPINS. Nu-l reincerca. ----------------
   Ideea era `position: sticky` pe `.lb-table thead th`, cu blocantele desfacute prin
   `overflow: clip` (care clipeaza fara sa creeze container de derulare) pe `.lb-panel` si
   `overflow-y: clip` pe `.table-responsive`.

   REZULTAT MASURAT, nu presupus (raport user): antetul chiar s-a lipit - dar de capul cutiei
   `.table-responsive`, nu de ecran. Adica statea impins cu exact `--nav-h` in jos PESTE primele
   randuri, iar locul lui din tabel ramanea gol. Ambele panouri, dansatori si crew-uri.

   CONCLUZIA, care e regula generala, nu un detaliu al paginii asteia: un element cu
   `overflow-x: auto` ramane scrollportul si pentru axa Y chiar daca ii dai explicit
   `overflow-y: clip` - deci `sticky` pe verticala se rezolva fata de EL, nu fata de viewport.
   `overflow: clip` desface blocantul doar cand e pe AMBELE axe.

   Prin urmare antetul lipicios si tragerea laterala se exclud reciproc aici. Tragerea ramane:
   ea impiedica pierderea TACUTA de coloane (bugul original al lui B86), pe cand antetul e confort.
   Singura varianta care le-ar impaca e `max-height` pe container, adica o zona de derulare
   imbricata - pe telefon inseamna capcana de scroll sub deget, deci nu.

   Daca cineva chiar il vrea candva: scoate `.table-responsive` din lant si accepta ca la 320px cu
   nume foarte lungi coloanele din dreapta se pierd iar. Nu merita. */

/* === 14b. SEMNUL DE BRAND ================================== */
/* Markup-ul (_brand_logo.html.twig) randează toate variantele; cascada alege UNA. Comutarea nu se
   poate face cu <picture media="(prefers-color-scheme: dark)"> fiindcă aplicația are comutator
   MANUAL de temă ([data-theme] pe <html>): cine alege dark pe un OS light ar primi logo-ul ink pe
   bară întunecată. Varianta o alege deci DOAR [data-theme] (pus de theme_boot() în <head>, înainte de primul paint); fără JS
   pagina și semnul rămân pe deschis, împreună (B206).
   Dimensiunea vine din --brand-logo-h, setat de containerul care folosește semnul. */
.brand-logo { display: inline-flex; align-items: center; line-height: 0; }

/* AXA 1 — mărimea, decisă pe `__set`. Sub 420px lockup-ul (broască + wordmark) devine ilizibil,
   deci rămâne doar wordmarkul. Doar bara cere asta; pe login și în subsol e spațiu. */
.brand-logo__set { display: inline-flex; }
.brand-logo__set--wordmark { display: none; }
@media (max-width: 420px) {
    .brand-logo--responsive .brand-logo__set--lockup { display: none; }
    .brand-logo--responsive .brand-logo__set--wordmark { display: inline-flex; }
}

/* AXA 2 — tema, decisă pe `__img`, independent de axa 1: DOAR [data-theme="dark"]. Fără variantă de sistem (B206): fără JS
   pagina rămâne pe deschis (`site-palette.css`, „TEMA ÎNCHISĂ”), iar semnul „hârtie” pe o pagină deschisă aproape dispărea.
   Înălțimea vine din --brand-logo-h, setat de containerul care folosește semnul. */
.brand-logo__img { display: block; height: var(--brand-logo-h, 32px); width: auto; }
.brand-logo__img--dark { display: none; }
[data-theme="dark"] .brand-logo__img { display: none; }
[data-theme="dark"] .brand-logo__img--dark { display: block; }
/* În BARĂ semnul urmează BANDA, nu tema (B188): banda e închisă pe ambele teme, deci varianta „hârtie" mereu. Stă DUPĂ
   regulile de temă — aceeași specificitate (0,2,0), ordinea decide. NU în modul de contrast ridicat: acolo banda devine
   fundalul sistemului (alb pe tema deschisă), iar semnul alb ar dispărea. */
@media not (forced-colors: active) {
    .app-nav .brand-logo__img { display: none; }
    .app-nav .brand-logo__img--dark { display: block; }
}

/* === 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ă. */
/* `--page-bg` (fundalul PAGINII) cu `--paper` ca fallback: regula din `html, body` nu ajunge aici, clasa de
   pagina are specificitate mai mare. Fallbackul tine documentele care nu incarca paleta. Vezi
   `tokens.css` (`html, body`) si `site-palette.css` (blocul de tokeni). */
.login-page { background: var(--ui-page, var(--ui-flat)); font-family: var(--font-sans); }
/* Brandul de pe login e imagine (ca în bară), deci nu mai are tipografie — doar mărimea semnului. */
.login-brand { --brand-logo-h: 52px; }

/* ── STAREA GOALĂ (B192 L3, ADR 0057; prototip aprobat de owner 2026-10-15) — `_empty_state.html.twig` ───────────────────────
   Un singur limbaj pentru toate golurile: --page (broasca + titlu + text + ieșiri), --filter (fără broască), --inline (golul din tab /
   panou / rând: o propoziție, aceeași treaptă peste tot). Culori: cerneală pe titlu, cerneală retrasă pe text; fără accent (golul nu e
   titlu de zonă), fără rame (treapta tonală o dă pagina). Broasca: mărimea „medie” aleasă de owner, ușor estompată (`opacity`) — e
   decor, nu conținut, deci nu cere contrast. NU pe ecranul de sală (D6 = A, `mark: false` în template). */
.empty-state { display: flex; flex-direction: column; align-items: center; text-align: center; gap: .45rem; padding: clamp(2rem, 7vw, 3.5rem) 1rem; }
.empty-state__mark { --brand-logo-h: clamp(56px, 14vw, 82px); margin-bottom: .6rem; opacity: .6; }
.empty-state__title { margin: 0; font-family: var(--font-display); font-weight: var(--type-title-weight, 800); font-size: var(--font-xl); line-height: 1.2; color: var(--ui-ink); text-wrap: balance; }
.empty-state__text { margin: 0; max-width: 46ch; font-size: var(--font-base); color: var(--ui-ink-muted); text-wrap: pretty; }
.empty-state__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: .5rem; margin-top: .8rem; }
.empty-state--filter { padding-block: clamp(1.5rem, 5vw, 2.5rem); }
.empty-state--filter .empty-state__title { font-size: var(--font-lg); }
/* În rând: fără broască, fără centrare, fără umplere — o propoziție pe cerneala retrasă, la treapta textului secundar. */
.empty-state--inline { display: block; text-align: start; padding: .5rem 0; margin: 0; font-size: var(--font-sm); color: var(--ui-ink-muted); }
.login-sub { font-size: var(--font-sm); color: var(--ui-ink-muted); text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .1em); font-family: var(--font-mono); }
.login-error { font-size: var(--font-md); border-radius: var(--radius-sm); border: 2px solid var(--ui-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ă. */
/* Umbra dura `6px 6px 0 0 var(--primary)` era ultimul idiom brutalist ramas pe o pagina publica;
   sub skin `--primary` e text-hi, deci ar fi iesit o lespede aproape neagra langa card. Chenarul se
   subtiaza la 1px ca la orice card (uniform pe toate laturile, n-are latura cu rol).
   Contopita din `@layer skin` la B159 L10 (F2). */
.login-card { background: var(--ui-raised); border: 1px solid var(--ui-frame); border-radius: var(--radius-sm); box-shadow: var(--ui-shadow-raised); }
.login-card .form-label { font-family: var(--font-display); font-size: var(--font-xs); font-weight: var(--type-label-weight, 900); text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .1em); color: var(--ui-ink-muted); }
/* Cutia cu pictograma din fata campului: `--paper` o facea alba pe card alb. Pe s2 ramane o cutie,
   nu o pata. `border-right: none` e cusatura grupului — se scriu doar laturile care se recoloreaza. */
.login-card .input-group-text { background: var(--ui-subtle); border: 2px solid var(--ui-line); border-right: none; color: var(--ui-ink-muted); }
/* ⚠️ `border-left` se scrie in LONGHAND-uri, nu ca prescurtarea `border-left: none`: prescurtarea
   reseteaza si CULOAREA la `currentColor`, iar pana la B159 L10 culoarea laturii venea de la regula
   generica a skinului (`.form-control { border-color }`), care batea prin layer. Dupa fold regula
   generica e mai putin specifica decat asta, deci latura si-ar fi pierdut culoarea — cusatura dintre
   cutia cu pictograma si camp s-ar fi vazut altfel. A treia oara aceeasi capcana (vezi
   `.bk-entry:last-of-type` si `.folder-tab:last-child`). Prins de sonda pe `/login`.
   `--border-strong` se remapeaza sub skin la `--sm-line`, deci valoarea ramane a ROLULUI. */
.login-card .form-control { border: 2px solid var(--ui-line); border-left-style: none; border-left-width: 0; font-family: var(--font-sans); }
.login-card .form-control:focus { box-shadow: none; border-color: var(--ui-inverse); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.entry-form .form-control:focus { box-shadow: inset 0 0 0 1px var(--ui-ink); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.btn-login { font-family: var(--font-display); font-weight: var(--type-control-weight, 900); text-transform: var(--type-control-case, uppercase); letter-spacing: var(--type-control-tracking, .08em); background: var(--ui-accent-fill); color: var(--ui-on-accent-fill); border: 2px solid var(--ui-accent-fill); box-shadow: none; border-radius: var(--radius-control, var(--radius-sm)); padding: .6rem 1rem; transition: background .1s, color .1s; }
/* Contopite din `@layer skin` la B159 L10 (F2). */
.btn-login:hover { background: var(--ui-accent-fill-hover); border-color: var(--ui-accent-fill-hover); color: var(--ui-on-accent-fill); }
.btn-login:disabled { background: var(--ui-disabled); color: var(--ui-on-disabled); border-color: var(--ui-disabled); }
/* Blocul de sub cardul de login. Pagina e standalone (fără bară, fără subsol), deci și linkurile
   legale trăiesc aici. Prima frază e cea care taie confuzia raportată („nu îmi este clar cum îmi fac
   cont"): răspunsul corect e că cei mai mulți vizitatori NU au nevoie de unul — de aceea e scoasă în
   evidență față de restul. */
.login-help { margin-top: 1.25rem; text-align: center; }
.login-help p { margin: 0 0 .5rem; font-size: var(--font-sm); color: var(--ui-ink-muted); line-height: 1.5; }
.login-help__lead { color: var(--ui-ink-muted); }
.login-help a { color: var(--ui-ink); }
.login-help__legal { display: flex; justify-content: center; gap: clamp(.5rem, 3vw, 1.25rem); margin-top: 1rem; font-family: var(--font-mono); font-size: var(--font-2xs); text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .12em); }
/* Podea de țintă (B170, WCAG 2.2 SC 2.5.8 AA): linkurile măsurau 18px înălțime pe 390px — sub cele
   24px sub care nu se coboară. Cutia crește, TEXTUL nu: `--font-2xs` e alegerea de densitate a
   subsolului, nu un defect. `inline-flex` + centrare verticală ține glifa pe linia ei, iar surplusul
   se împarte egal sus/jos. Pe un rând cu `gap`, lățimea nu se atinge: linkurile au deja 49-133px. */
.login-help__legal a { color: var(--ui-ink-muted); text-decoration: none; }
.login-help__legal a { display: inline-flex; align-items: center; min-height: var(--tap-aa); }

.login-help__legal a:hover { color: var(--ui-ink); text-decoration: underline; }

/* Pagini de eroare (error403/404) — scoped pe .error-page, NU pe `body` global. */
.error-page { background: var(--ui-page, var(--ui-flat)); font-family: var(--font-sans); }
.err-code { font-size: var(--font-10xl); font-weight: var(--type-display-weight, 900); color: var(--ui-ink); line-height: 1; text-transform: var(--type-display-case, uppercase); letter-spacing: var(--type-display-tracking, -.04em); }
.err-code--alert { color: var(--ui-danger); }
.err-title { font-weight: var(--type-display-weight, 900); font-stretch: var(--ar-wdth); font-size: var(--font-2xl); text-transform: var(--type-display-case, uppercase); letter-spacing: var(--type-display-tracking, .04em); color: var(--ui-ink); }
.err-msg { color: var(--ui-ink-muted); 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(--ui-danger); border-inline-start: 4px solid var(--ui-danger); }
.confirm-page__lines { margin: .75rem 0 0; padding-left: 1.1rem; font-size: var(--font-sm); }
.confirm-page__lines li { margin-bottom: .25rem; text-wrap: pretty; }
.confirm-page__warn { font-weight: 700; color: var(--ui-danger); font-size: var(--font-sm); margin: .5rem 0 1rem; }
.confirm-page__actions { display: flex; gap: .6rem; align-items: center; }

/* .brand-modal* (chrome-ul comun al modalelor) a VENIT INAPOI in fisierul asta la B159 L10 (F2) —
   vezi blocul de la coada. Nota de mai jos e istorica (amendament
   ADR 0023), împreună cu .btn-ink*. Aici stă doar ce e specific modalului de înscriere (.enroll-modal). */

/* === Pagina de gestionare a înscrierii (B70, public/entry_manage.html.twig) ==================
   Aceeași familie cu .confirm-page: pagină utilitară, card centrat, citită o singură dată de un
   om care a venit dintr-un email. Fiecare acțiune = un bloc cu titlu, hint SCURT și butonul ei,
   ca omul să știe ce pățește ÎNAINTE să apese. Spațierea e fluidă (clamp), fără @media dur. */
.manage-page { display: flex; justify-content: center; padding: clamp(1rem, 3vw, 2rem) clamp(.75rem, 3vw, 1rem); }
.manage-page__card { max-width: 42rem; width: 100%; padding: clamp(1rem, 3.5vw, 1.75rem); }
.manage-page__lead { font-size: var(--font-sm); margin: .5rem 0 0; }
.manage-sec { margin-top: clamp(1.25rem, 3vw, 1.75rem); }
.manage-sec__h { font-family: var(--font-display); font-size: var(--font-xs); text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .1em); color: var(--ui-ink-muted); margin: 0 0 .4rem; }
.manage-hint { font-size: var(--font-xs); color: var(--ui-ink-muted); margin: .35rem 0 0; text-wrap: pretty; }
.manage-state { font-size: var(--font-sm); margin: 0 0 .5rem; }
/* Blocul unei PERSOANE — tot ce o privește (email, numele pe site, ștergerea datelor) într-un
   singur loc, delimitat de o linie subțire. Nivelurile se disting prin MECANISM (spațiere + o
   hairline), nu prin rame groase suprapuse. */
.manage-person { margin-top: clamp(1.25rem, 3vw, 1.75rem); padding-top: clamp(.75rem, 2vw, 1rem); border-top: 1px solid var(--ui-hair); }
.manage-person__name { font-family: var(--font-display); font-size: var(--font-md); text-transform: var(--type-title-case, uppercase); letter-spacing: var(--type-title-tracking, .04em); margin: 0 0 .6rem; }

/* Acțiunile persoanei stau pe UN RÂND și pică UNA CÂTE UNA la îngustare (aranjament FLUID, nu
   @media dur). Fiecare acțiune e o coloană îngustă: butonul sus, explicația SUB el — omul citește
   „ce fac" și „ce pățesc" în aceeași privire, fără să caute textul în altă parte a paginii. */
.manage-acts { display: flex; flex-wrap: wrap; gap: clamp(.6rem, 2vw, 1rem); align-items: start; }
.manage-act { flex: 1 1 13rem; min-width: 0; display: flex; flex-direction: column; gap: .35rem; }
/* „Fișa ta" (B241): toate datele omului pe o grilă FLUIDĂ (auto-fit: 2-3 pe rând pe desktop, unul sub altul pe
   telefon), fiecare cu eticheta DEASUPRA (`.form-field`). O valoare blocată (data nașterii, genul, odată salvate)
   e tot o „celulă" cu eticheta deasupra — `.manage-fact` copiază tipografia lui `.form-field` ca rândurile să se
   alinieze; `column-reverse` ca la `.form-field`: valoarea întâi în DOM, eticheta deasupra pe ecran. */
.manage-fisa { display: flex; flex-direction: column; gap: .5rem; margin-bottom: clamp(.75rem, 2vw, 1rem); }
.manage-fisa__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); gap: .5rem .75rem; align-items: end; }
.manage-fact { display: flex; flex-direction: column-reverse; gap: 3px; margin: 0; min-width: 0; }
.manage-fact__k { font-family: var(--font-sans); font-weight: 600; font-size: var(--font-sm); color: var(--ui-ink-muted); line-height: 1.15; }
.manage-fact__v { font-size: var(--font-md); line-height: 1.3; min-height: 1.95rem; padding: .32rem 0; }
/* Butonul umple coloana → pe telefon devine țintă de atingere pe toată lățimea, gratis. */
.manage-act > .btn-ink { width: 100%; }
.manage-act__hint { font-size: var(--font-xs); color: var(--ui-ink-muted); margin: 0; text-wrap: pretty; }

/* Cele două acțiuni cu consecințe stau JOS, în ordinea gravității, și se disting prin MECANISME
   DIFERITE (regula „Gruparea vizuală" pct. 1 și 5): retragerea = spațiu + hairline, ca `.manage-person`;
   ștergerea datelor = bara roșie, SINGURA de pe pagină.

   ⚠️ NU pune bară roșie și pe retragere. Accentul e o resursă limitată: două linii din aceeași
   familie de culoare, la niveluri diferite, se citesc ca ACELAȘI nivel — exact ierarhia pe care
   blocul ăsta o construiește. Retragerea e recuperabilă (te înscrii din nou cât înscrierile sunt
   deschise); ștergerea nu se poate anula. Ordinea corectă a fost cerută de owner după testul real,
   când cea ireversibilă era prezentată mai ușor decât cea recuperabilă. */
.manage-exit { margin-top: clamp(1.5rem, 4vw, 2.25rem); padding-top: clamp(.75rem, 2vw, 1rem); border-top: 1px solid var(--ui-hair); }
.manage-danger { margin-top: clamp(1.25rem, 3vw, 1.75rem); padding: clamp(.75rem, 2vw, 1rem) clamp(.75rem, 2vw, 1.1rem); border-left: 4px solid var(--ui-danger); background: var(--ui-sunken); }
.manage-danger__what { font-size: var(--font-sm); margin: 0 0 .6rem; }


/* --- „7 to Smoke" (ADR 0026, layout v4) — vederea publică a sesiunii de coadă (_smoke_section) ---
   În limbajul CAST de la B192 G2 L1 (prototipul aprobat pe date reale, 2026-09-30; cast-ui, ADR 0057): ringul e un CARD cu
   starea pe muchie ca nodul de bracket, verdictul curge până la mijloc ca la capul scorecardului, jurații stau într-o BANDĂ
   PROPRIE sub ring (rândul scorecardului, refolosit întocmai). Ecranul e gândit pentru proiector (/ecran): tot ce crește pe
   sală vine din `clamp(min, Ncqi, calc(max * var(--scale-cap, 1)))` pe gazda `.smoke-tab`, fără @media dur. Stările sunt 100%
   server-randate — zero JS de stare. */

/* Gazda de container a tabului (ca `.qual-tab`), dar FĂRĂ plafonul de 1500px de pe sală: acolo ține o grilă DENSĂ de carduri,
   aici ar strânge latura ringului 776 → 566px și numele ar ieși mai mici decât înainte de L1. */
.smoke-tab { container-type: inline-size; }

/* Ringul = CARD, ca nodul de bracket și cardul de grupă: suprafață + umbră, fără ramă; loc deasupra pentru etichetă.
   Coloana din mijloc crește cu tabul și are o podea cât „EGALITATE" la mărimea minimă (7.5rem) — `minmax(7rem, 16rem)` lăsa
   laturile de ~25px pe telefon și scotea cuvântul din coloană.
   ⚠️ `cqi` din `--smoke-dot` se rezolvă pe PUNCT (proprietate neînregistrată → substituită la consumator), deci față de
   `.smoke-vs__side` (container), nu de tab: coeficientul e pe scara laturii. Fără `@property` — ar anula fallback-ul `.7em` al
   punctelor din coadă. */
.smoke-vs {
    --smoke-dot: clamp(.8rem, 5cqi, calc(1.3rem * var(--scale-cap, 1)));
    --state-tag-fs: clamp(var(--font-2xs), 1.6cqi, calc(var(--font-xs) * var(--scale-cap, 1)));
    position: relative; display: grid; grid-template-columns: minmax(0, 1fr) minmax(7.5rem, 23cqi) minmax(0, 1fr);
    align-items: center; gap: .5rem clamp(.5rem, 3cqi, 2rem); margin: 1.25rem 0 0;
    padding: clamp(.6rem, 2cqi, 1.4rem) clamp(.5rem, 2cqi, 1.5rem); text-align: center;
    border-radius: var(--radius-lg); background: var(--ui-raised); box-shadow: var(--ui-shadow-raised);
}
/* Stările — aceleași muchii ca `.bk-battle--active / --next / --golden` și `.bgc--*` (muchiile CU etichetă: umplerea violet).
   LIVE pe ring e DOAR linia roșie de sus, FĂRĂ tenta de fundal (cererea ownerului: „roșul total arată ciudat"). Nodurile de
   bracket și cardurile de grupă își păstrează tenta — diferența e de SUPRAFAȚĂ: pe un nod mic tenta e un semnal, pe un ring cât
   ecranul e o alarmă. `--golden` stă DUPĂ `--live`: pe runda extra stau împreună, cu aceeași specificitate. */
.smoke-vs--live { box-shadow: inset 0 3px 0 var(--ui-live-mark), var(--ui-shadow-raised); }
.smoke-vs--next { box-shadow: inset 0 3px 0 var(--ui-accent-fill), var(--ui-shadow-raised); }
.smoke-vs--golden { box-shadow: inset 0 3px 0 var(--ui-warning), var(--ui-shadow-raised); }
/* Departajarea (ADR 0026 am.9): muchia chihlimbar (rețeta „departajare" din cast-ui), peste orice mod al ringului. */
.smoke-vs--tiebreak { box-shadow: inset 0 3px 0 var(--ui-warning), var(--ui-shadow-raised); }
/* EGALITATEA (clipirea) pe fundalul egalității — cererea ownerului. */
.smoke-vs--tie { background: var(--ui-warning-soft); box-shadow: inset 0 3px 0 var(--ui-warning), var(--ui-shadow-raised); }

/* VERDICTUL până la mijloc, ca la capul scorecardului (`.sc-hd__nm.is-win` + `.sc-hd__mid--w1/--w2`): coloanele se ating, mijlocul
   e pe jumătăți (verde spre câștigător, gri spre cel care pleacă), colțurile rotunjite doar la exterior. */
.smoke-vs--verdict { column-gap: 0; }
.smoke-vs--verdict > :is(.smoke-vs__side, .smoke-vs__mid) { align-self: stretch; }
.smoke-vs--verdict .smoke-vs__side:has(+ .smoke-vs__mid) { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.smoke-vs--verdict .smoke-vs__mid + .smoke-vs__side { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
.smoke-vs__mid--w1 { background: linear-gradient(90deg, var(--ui-win) 0 50%, var(--ui-lose) 50% 100%); }
.smoke-vs__mid--w2 { background: linear-gradient(90deg, var(--ui-lose) 0 50%, var(--ui-win) 50% 100%); }

/* Laturile — `container-type`: numele (COPIL) se mărește din lățimea coloanei (cqi), nu din viewport. Fără inele pe perimetru
   (ADR 0057). --win urmează CÂȘTIGĂTORUL: la verdict pe latura votată, la predare pe King (ADR 0026 am.4). --in = challengerul
   proaspăt intrat: muchia violet FĂRĂ etichetă → tonul de TEXT al identității (`--identity`), fiindcă umplerea pe tema
   întunecată ieșea 2.3:1, sub pragul grafic de 3:1. --out = cel care pleacă: pulsează DOAR muchia de sus, de 3 ori, sincron cu
   challengerul din coadă (aceeași animație de .9s) — fără opacitate (la .6 textul cădea la 2.2:1). */
.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; }
.smoke-vs__side--win { background: var(--ui-win); color: var(--ui-on-win); box-shadow: none; }
.smoke-vs__side--win .smoke-dots__dot { background: var(--ui-on-win); }
.smoke-vs__side--in { background: transparent; box-shadow: inset 0 3px 0 var(--ui-accent); }
@keyframes smoke-leave-pulse { 50% { box-shadow: inset 0 3px 0 var(--ui-ink-muted); } }
.smoke-vs__side--out { background: var(--ui-lose); color: var(--ui-ink-muted); box-shadow: none; animation: smoke-leave-pulse .9s ease-in-out 3; }
/* Numele: mecanismul scorecardului — bucket-ul de LUNGIME prin `--nm-k` (`.sc-nm--m/--l`, scoreboard.css), plafonul NEînmulțit
   cu k (ca `.sc-hd__nm`). Coeficientul pe lungimea reală a literelor: Archivo în majuscule ≈ 0.76em/caracter, deci 10 caractere ×
   10.5cqi ≈ 80% din latură (15cqi dădea 114% → numele se rupeau în cuvânt pe sală). Podeaua 1.1rem: sub ~200px de conținut 10
   caractere se rup oricum; `overflow-wrap` rămâne plasa de siguranță. */
.smoke-vs__name { font-family: var(--font-display); font-weight: var(--type-name-weight, 900); text-transform: var(--type-name-case, uppercase); line-height: 1.02; font-size: clamp(1.1rem, calc(10.5cqi * var(--nm-k, 1)), calc(5rem * var(--scale-cap, 1))); overflow-wrap: break-word; max-width: 100%; }
/* Tag-ul se randează MEREU (min-height rezervă rândul) → numele celor două laturi stau la aceeași înălțime. Singurul lui copil e
   pastila KING, care își declară singură culoarea / greutatea / rărirea — aici rămân doar mărimea (moștenită de pastilă) și rândul. */
.smoke-vs__tag { font-size: clamp(var(--font-2xs), 6cqi, calc(var(--font-md) * var(--scale-cap, 1))); min-height: 1.3em; }
/* KING = pastilă NEUTRĂ (bugetul violetului). Numele clasei e al pastilei juratului (`judge.css`), altă foaie, altă lume de randare. */
.smoke-king {
    display: inline-block; padding: 0 .55em; border-radius: var(--radius-status, 999px);
    background: var(--ui-quiet); color: var(--ui-ink); font-weight: 800; letter-spacing: .07em; line-height: 1.5;
}

/* Mijlocul — verdict: scorul pe jumătăți; tie: EGALITATE / RUNDĂ EXTRA; live: eticheta rundei extra când e cazul; next: VS.
   Ceasul de SESIUNE stă MIC aici, în toate modurile (ADR 0026 am.4 — cronometrul de rundă e cel MARE, sub ring). */
.smoke-vs__mid { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .3rem; min-width: 0; }
.smoke-vs__x { font-size: clamp(.9rem, 4cqi, calc(2rem * var(--scale-cap, 1))); }
/* ── VS — B196, ales de owner pe prototip (2026-10-15): #055 „Sliced Text Effect” (TajShireen, codepen ExLWgGb, MIT). VS-ul tăiat pe
   diagonală, jumătatea de sus decalată spre stânga și cea de jos spre dreapta, tot VS-ul rotit −10° (dinamism). Static (pe proiector
   mișcarea se pierde, decizia ownerului din 13 oct), în cerneală (ADR 0057). O SINGURĂ regulă pentru ambele locuri: capul scorecardului
   (`.sc-hd__vs`, mărimea în scoreboard.css) și ringul Smoke (`.smoke-vs__x`, mărimea mai sus); toate deplasările sunt în `em`, deci cresc
   cu VS-ul pe sală. Textul elementului e transparent — cititorul de ecran citește „VS” o dată; cele două jumătăți sunt pseudo-elemente.
   ⚠️ `content: "VS";` stă ÎNAINTEA formei `"VS" / ""` (text alternativ gol, ca jumătățile să nu fie citite încă o dată): un browser care
   nu știe forma a doua o aruncă și rămâne cu prima — fără rezervă, VS-ul ar dispărea de tot. Pin: `VsSlicedCssTest`. */
.sc-hd__vs, .smoke-vs__x {
    position: relative; display: inline-block; color: transparent; transform: rotate(-10deg);
    font-family: var(--font-display); font-weight: 900; line-height: 1; letter-spacing: .03em;
}
.sc-hd__vs::before, .sc-hd__vs::after, .smoke-vs__x::before, .smoke-vs__x::after {
    content: "VS"; content: "VS" / ""; position: absolute; inset: 0; color: var(--ui-ink);
}
.sc-hd__vs::before, .smoke-vs__x::before { clip-path: polygon(0 0, 100% 0, 100% 36%, 0 64%); transform: translate(-.07em, -.04em); }
.sc-hd__vs::after, .smoke-vs__x::after { clip-path: polygon(0 64%, 100% 36%, 100% 100%, 0 100%); transform: translate(.07em, .04em); }
/* Scorul = două cifre fără liniuță, fiecare pe jumătatea ei (ca `.sc-hd__n`); apare doar la verdict. */
.smoke-vs__tally { display: grid; grid-template-columns: 1fr 1fr; justify-items: center; width: 100%; font-family: var(--font-display); font-weight: 900; font-size: clamp(1.4rem, 5cqi, calc(3.5rem * var(--scale-cap, 1))); line-height: 1; font-variant-numeric: tabular-nums; }
.smoke-vs__n.is-win { color: var(--ui-on-win); }
.smoke-vs__n.is-out { color: var(--ui-ink-muted); }
/* EGALITATE apare doar pe ringul de egalitate (fundalul chihlimbar) → cerneala lui (8.05 light / 11.34 dark). */
.smoke-vs__eq { font-family: var(--font-display); font-weight: 900; font-size: clamp(1.2rem, 3.6cqi, calc(2.6rem * var(--scale-cap, 1))); line-height: 1.05; color: var(--ui-on-warning-soft); }
.smoke-vs__eq-sub { font-size: clamp(var(--font-sm), 1.8cqi, calc(var(--font-lg) * var(--scale-cap, 1))); font-weight: 900; letter-spacing: .06em; color: var(--ui-on-warning-soft); }
/* „RUNDĂ EXTRA": O SINGURĂ pastilă, pe ring cât ține runda și în desfășurător (L2) — nu badge, nu a doua copie. */
.smoke-vs__extra,
.smoke-log__tie {
    font-size: clamp(var(--font-2xs), 1.4cqi, calc(var(--font-sm) * var(--scale-cap, 1))); font-weight: 900; letter-spacing: .05em;
    color: var(--ui-on-warning-soft); background: var(--ui-warning-soft); border-radius: var(--radius-status, 4px); padding: 0 .45em;
}
/* Ceasul de SESIUNE (mic, în mijloc): fără ramă și fără umbră dură. */
.smoke-vs .battle-timer--round { border-color: transparent; box-shadow: none; border-radius: var(--radius-sm); }
.smoke-vs .battle-timer--round .battle-timer__val { font-size: clamp(1.1rem, 2.4cqi, calc(2rem * var(--scale-cap, 1))); }

/* Bilele = victoriile din sesiune, sub nume oriunde apare omul (`role="img"` + etichetă: culoarea nu e singurul canal).
   Containerul se randează MEREU (spațiu rezervat) ca itemele vecine să rămână aliniate; î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(--ui-win-mark); }

/* BANDA DE JURAȚI — cererea ownerului pe prototip: „să îl lăsăm puțin mai jos, să se vadă ca o entitate diferită, dar concurenții
   principalii mari". Rândul scorecardului (`.sc-jg`, refolosit întocmai) pe un card PROPRIU, cu aceeași rețetă ca ringul
   (suprafață + umbră — regiune comună, nu ramă), MAI ÎNGUST și centrat, sub ring. Lățime EXPLICITĂ, nu `fit-content`:
   `.sc-jg__body` e gazdă de container, iar o gazdă dimensionată după conținut se strânge la 0. Înăuntru: fără fundalul rail-ului,
   avatarul cu plafon — banda e DETALIUL. Pastilele „·" NU se estompează: scorecardul le stinge pe rândurile care nu sunt în
   curs, dar aici rândul e unul singur. */
.smoke-jury {
    width: min(100%, calc(28rem * var(--scale-cap, 1)));
    margin: clamp(.75rem, 2cqi, calc(1.25rem * var(--scale-cap, 1))) auto 0;
    border-radius: var(--radius-lg); background: var(--ui-raised); box-shadow: var(--ui-shadow-raised);
}
.smoke-jury .sc-jg__rail { background: transparent; padding-top: calc(.4rem * var(--scale-cap, 1)); }
.smoke-jury .sc-jg__judge > .avatar { --av-size: clamp(1.35rem, 28cqi, calc(1.6rem * var(--scale-cap, 1))); }
.smoke-jury .sc-jg__row:not(.is-current) .sc-jg__pill.is-down:not(.is-on) { opacity: 1; }

/* Cronometrul de RUNDĂ, sub ring și sub banda de jurați = varianta MARE a ringului (ADR 0026 am.4). */
.battle-timer--ring { width: fit-content; margin: .75rem auto 0; padding: .3rem 1.2rem; border-color: transparent; box-shadow: none; border-radius: var(--radius-lg); }
.battle-timer--ring .battle-timer__val { font-size: clamp(2.5rem, 7cqi, calc(6rem * var(--scale-cap, 1))); }

/* TELEFONUL: sub ~34rem de tab ringul se așază pe VERTICALĂ (latura 1 · mijloc · latura 2) — la 360px o latură de ~80px nu ține
   10 caractere la nicio mărime lizibilă. Container query pe `.smoke-tab`, nu `@media`; mijlocul își întoarce gradientul.
   La verdict: fără spațiu între rânduri (bucățile verde / gri se ating), iar mijlocul = TREI rânduri — cifra de sus · ceasul de
   sesiune · cifra de jos (scorul „desfăcut"). Rândurile cifrelor sunt egale, deci linia de 50% trece prin mijlocul ceasului și
   fiecare cifră stă pe jumătatea ei. */
@container (max-width: 34rem) {
    .smoke-vs { grid-template-columns: minmax(0, 1fr); }
    .smoke-vs--verdict { row-gap: 0; }
    .smoke-vs--verdict .smoke-vs__side:has(+ .smoke-vs__mid) { border-radius: var(--radius-sm) var(--radius-sm) 0 0; }
    .smoke-vs--verdict .smoke-vs__mid + .smoke-vs__side { border-radius: 0 0 var(--radius-sm) var(--radius-sm); }
    .smoke-vs__mid--w1 { background: linear-gradient(180deg, var(--ui-win) 0 50%, var(--ui-lose) 50% 100%); }
    .smoke-vs__mid--w2 { background: linear-gradient(180deg, var(--ui-lose) 0 50%, var(--ui-win) 50% 100%); }
    .smoke-vs--verdict .smoke-vs__mid { display: grid; grid-template-rows: 1fr auto 1fr; align-items: center; justify-items: center; gap: .25rem; }
    .smoke-vs--verdict .smoke-vs__tally { display: contents; }
    .smoke-vs--verdict .smoke-vs__tally > .smoke-vs__n:first-child { grid-row: 1; }
    .smoke-vs--verdict .smoke-vs__tally > .smoke-vs__n:last-child { grid-row: 3; }
    .smoke-vs--verdict .smoke-vs__mid > .battle-timer--round { grid-row: 2; margin: 0; }
}

/* Coada — SUS, centrată; ordinea e informația-cheie: primul (URMEAZĂ, muchia violet) intră următorul. Jetoane pe suprafață +
   umbră. Muchia jetonului URMEAZĂ e pe tonul de TEXT al identității: n-are etichetă, iar umplerea ieșea 2.37:1 pe tema
   întunecată. Challengerul care TOCMAI intră (faza „verdict") pulsează de 3 ori, nu la infinit. Un jeton = UN rând, peste tot:
   `min-width: 0` + `max-width: 100%` îl țin în lățimea rândului, iar un nume mai lung decât rândul primește „…" (eticheta unui
   chip se trunchiază, nu se rupe — Material 3); fără ele, pe telefon un nume de ~35 de caractere împingea pagina lateral. */
.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: clamp(var(--font-2xs), 1.2cqi, calc(var(--font-xs) * var(--scale-cap, 1))); font-weight: 700; text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .06em); color: var(--ui-ink-muted); align-self: center; }
.smoke-queue__item {
    display: inline-flex; flex-direction: column; align-items: center; gap: .2rem;
    font-family: var(--font-display); text-transform: var(--type-name-case, uppercase); font-weight: 700;
    font-size: clamp(var(--font-sm), 2cqi, calc(var(--font-lg) * var(--scale-cap, 1)));
    background: var(--ui-raised); border: 0; border-radius: var(--radius-sm); box-shadow: var(--ui-shadow-raised);
    padding: clamp(2px, .5cqi, 8px) clamp(6px, 1.2cqi, 16px); min-width: 0; max-width: 100%;
}
.smoke-queue__item--next { box-shadow: inset 0 3px 0 var(--ui-accent), var(--ui-shadow-raised); }
@keyframes smoke-queue-pulse { 50% { box-shadow: inset 0 5px 0 var(--ui-accent), var(--ui-shadow-raised); transform: scale(1.06); } }
.smoke-queue__item--enter { animation: smoke-queue-pulse .9s ease-in-out 3; }
@media (prefers-reduced-motion: reduce) { .smoke-queue__item--enter, .smoke-vs__side--out { animation: none; } }
/* Pe sală coada stă pe UN rând (altfel la verdict, când intră challengerul, trecea pe două și ringul cobora cu ~96px): se
   scurtează cu „…" DOAR numele lungi, după treapta lor de lungime (același SSOT ca numele de pe ring). Numele scurte și URMEAZĂ nu
   se scurtează niciodată — a lăsa și scurtele să se strângă le tăia cu 2-3px („GUSHU" → „GUS…") la fiecare verdict cu un nume
   lung în coadă (măsurat, B192 G2 L1); 7 nume scurte încap oricum pe un rând și la 1280. `safe center`: dacă rândul tot n-ar
   încăpea, se aliniază la stânga în loc să taie AMBELE margini („La rând" și challengerul care intră rămân în imagine). */
.smoke-queue__nm { display: block; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.live-projector .smoke-queue { flex-wrap: nowrap; justify-content: safe center; }
.live-projector .smoke-queue__lbl { flex: none; white-space: nowrap; }
.live-projector .smoke-queue__item { flex: 0 0 auto; }
.live-projector .smoke-queue__item--m { flex-shrink: 1; }
.live-projector .smoke-queue__item--l { flex-shrink: 2; }
.live-projector .smoke-queue__item--next { flex-shrink: 0; }

/* SALA: finalul (clasament + desfășurător) crește ca restul componentelor de pe proiector (L2). `cqi` = PANOUL (fiecare
   `.lb-panel` e container; ~926px pe 1920), coeficientul = plafonul / 9.26, deci plafonul (`--scale-cap`) se atinge exact la
   1080p. Mărimile fixe împrumutate din `.lb-*` se suprascriu DOAR aici — /clasament nu se schimbă. */
.live-projector .smoke-tab .lb-panel__head { font-size: clamp(var(--font-xl), 3.9cqi, calc(var(--font-xl) * var(--scale-cap, 1))); }
.live-projector .smoke-tab .lb-panel__head .lb-panel__count { font-size: clamp(var(--font-xs), 2.4cqi, calc(var(--font-xs) * var(--scale-cap, 1))); }
.live-projector .smoke-tab .tier-table-header th { font-size: clamp(var(--font-xs), 2.4cqi, calc(var(--font-xs) * var(--scale-cap, 1))); }
.live-projector .smoke-tab .smoke-standings td { font-size: clamp(var(--font-md), 2.8cqi, calc(var(--font-md) * var(--scale-cap, 1))); }
.live-projector .smoke-tab .lb-table .entity-name { font-size: clamp(var(--font-lg), 3.45cqi, calc(var(--font-lg) * var(--scale-cap, 1))); }
.live-projector .smoke-tab .lb-table .smoke-standings__key { font-size: clamp(var(--font-2xl), 4.5cqi, calc(var(--font-2xl) * var(--scale-cap, 1))); }
.live-projector .smoke-tab .smoke-log__row { font-size: clamp(var(--font-sm), 2.6cqi, calc(var(--font-sm) * var(--scale-cap, 1))); }
.live-projector .smoke-tab .smoke-log__no,
.live-projector .smoke-tab .smoke-log__def,
.live-projector .smoke-tab .smoke-log__summary { font-size: clamp(var(--font-xs), 2.4cqi, calc(var(--font-xs) * var(--scale-cap, 1))); }
.live-projector .smoke-tab .smoke-log__tie { font-size: clamp(var(--font-2xs), 2.4cqi, calc(var(--font-xs) * var(--scale-cap, 1))); }

/* 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.
   L2: desfășurătorul E un `.lb-panel` (rama, capul și contorul vin de acolo); rândurile cap la cap, pe zebră. */
.smoke-log__list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; }
/* 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); padding: .35rem .75rem; }
.smoke-log__no { font-variant-numeric: tabular-nums; color: var(--ui-ink-muted); font-size: var(--font-xs); min-width: 2.2ch; }
.smoke-log__win { font-weight: var(--type-name-weight, 900); text-transform: var(--type-name-case, uppercase); }
.smoke-log__def { color: var(--ui-ink-muted); font-size: var(--font-xs); }
.smoke-log__lose { color: var(--ui-ink-muted); text-transform: var(--type-name-case, uppercase); }
.smoke-log__tally { font-variant-numeric: tabular-nums; font-weight: 800; color: var(--ui-win-ink); }
.smoke-log__summary { display: flex; align-items: center; min-height: var(--tap-min); margin: 0 .25rem .25rem; padding: .45rem .5rem; cursor: pointer; font-size: var(--font-xs); font-weight: 700; color: var(--ui-ink-muted); list-style: none; }  /* B212.3: avea 31px */
.smoke-log__summary::-webkit-details-marker { display: none; }
.smoke-log__summary:hover { color: var(--ui-ink); }
/* 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-log__row:nth-child(even) { background: var(--ui-zebra); }

/* Clasamentul Smoke (L2, D4 = B: V · Î · Serie, fără bară): coloanele de cifre centrate, ca la /clasament, cu
   lățimi-preferință în rem; Î și Serie se retrag lângă vedetă (victoriile = cheia rangului). */
.smoke-standings__num { width: 3.25rem; text-align: center; white-space: nowrap; font-variant-numeric: tabular-nums; }
.smoke-standings__rest { color: var(--ui-ink-muted); font-weight: 700; }

/* 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ă. */
/* ⚠️ FARA `border-bottom` (owner, 2026-09-28). Antetul avea propriul fir despartitor, iar la 1rem
   sub el venea linia de baza a benzii de categorii: doua linii orizontale aproape lipite, care nu
   separau lucruri diferite. Separatorul e acum UNUL singur, al benzii, prelungit pana in capat
   (vezi `.cat-strip` in scoreboard.css). Marja RAMANE: ea tine respiratia dintre antet si banda. */
/* COMPACT (B218, ADR 0059 — amendamentele ownerului pe prototipul v4): aerul de sub antet s-a strâns (1rem + 1rem → .5rem + .5rem),
   fiindcă banda de categorii de dedesubt e acum lipicioasă și își aduce propriul aer sus (`.cat-nav`, scoreboard.css). */
.res-hero { display: flex; align-items: stretch; gap: clamp(.6rem, 2vw, 1.1rem); padding: .25rem 0 .5rem; margin-bottom: .5rem; }
/* 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; }
/* `.res-hero__aside` (coloana de program din antet) a fost ȘTEARSĂ în iter. 2o odată cu markupul:
   programul s-a mutat în modalul „Detalii & program", unde are lățime întreagă. O regulă rămasă
   fără consumator e junk care minte la următorul grep. */

/* Butonul „Detalii & program" din rândul de meta — SINGURUL punct de intrare către descrierea
   evenimentului și program. B218 (ADR 0059, amendamentul ownerului pe v4: „pare că nu e aliniat la restul
   designului, încă e pastilă cu chenar"): rețeta vine din `.btn-ink.btn-ink--ghost` (base-layout.css) —
   ACELAȘI buton secundar ca „Înscrie-te" din cărțile de categorie, un singur vocabular pentru „apasă aici".
   Aici rămâne doar AȘEZAREA: podeaua de tap explicită (era ~28px, „control ajutător"; acum 44px, ca
   restul butoanelor) și, pe telefon, toată lățimea rândului de meta. Vechea pastilă proprie (chenar +
   umplere s1 + display 600 upper) a fost ȘTEARSĂ: sub `.btn-ink` ar fi fost oricum moartă (aceeași
   specificitate, base-layout se încarcă după), deci ar fi mințit la următorul grep (C3 din stres-test). */
.hero-info { min-height: var(--tap-min); white-space: nowrap; }
/* Săgeata = afordanța „duce undeva"; sare puțin la hover, ca să se citească ca deschidere, nu ca
   încă o iconiță decorativă. */
.hero-info__go { transition: transform .1s; }
.hero-info:hover .hero-info__go { transform: translateX(2px); }
/* 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; }
/* ── Modalul „Detalii & program" (iter. 2o) ──
   Un singur loc pentru ce descrie EVENIMENTUL: anvergura, descrierea (care până acum se salva și nu
   se afișa nicăieri) și linia de timp. Lățime maximă pentru că programul e o bandă orizontală. */
.info-modal__meta {
    display: flex; flex-wrap: wrap; align-items: center;
    gap: .3rem clamp(.75rem, 3vw, 2rem);
    font-size: var(--font-base); color: var(--ui-ink-muted);
    padding-bottom: .6rem; border-bottom: 1px solid var(--ui-hair);
}
.info-modal__meta i { margin-right: .35rem; color: var(--ui-ink-muted); }
/* Lățime de CITIRE, nu lățimea modalului: un paragraf întins pe 1400px nu se citește (~65-75 de
   caractere e norma tipografică). Programul de dedesubt, în schimb, folosește toată lățimea. */
.info-modal__desc {
    margin: .9rem 0 0; max-width: 70ch;
    font-size: clamp(var(--font-base), 1.1vw, var(--font-lg)); line-height: 1.65;
    color: var(--ui-ink);
}
.info-modal__empty { margin: .9rem 0 0; font-size: var(--font-sm); color: var(--ui-ink-muted); }
.info-modal__sec { margin-top: 1.1rem; }
/* Linia de timp intră aici fără marginea ei de sus (o dă secțiunea) și fără plafonul de coloană. */
.info-modal__sec .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); }
/* B218 (ADR 0059): starea + (DRAFT) + numele = UN grup pe UN rând (`nowrap`), numele se frânge ÎN cutia lui (`min-width: 0`),
   nu sub pilulă — „numele concursului se ridică lângă LIVE" (ownerul, 2026-10-04). Grupul ia restul rândului (`flex: 1 1 auto`),
   ca `.res-hero__acts` cu `margin-inline-start: auto` să rămână la capăt și să cadă sub el doar pe îngust. */
.res-hero__title { display: flex; flex-wrap: nowrap; align-items: center; gap: .55rem; flex: 1 1 auto; min-width: 0; }
/* Pilula de stare o treaptă mai mică decât în restul produsului (v4: „micșorăm puțin pilula de live și mărim puțin titlul"). */
.res-hero__title .page-state { flex: none; font-size: var(--font-2xs); padding: .15rem .5rem; }
/* Badge-ul DRAFT (owner, nepublicat) nu se frânge înăuntru — ⚠️ la 360 lasă numelui ~150px: se frânge pe cuvânt (`anywhere`); de văzut pe dispozitiv. */
.res-hero__title .badge-status { flex: none; white-space: nowrap; }
/* 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;
    /* ⚠️ TINTA DE TAP: afisul e clicabil (zoom). `border: 0` scoate chenarul de 2px, dar `width` si
       `min-height` sunt border-box (reboot), deci cutia ramane ≥ 72×96px pe desktop, iar pe telefon
       e banda pe toata latimea cu aspect 16/6. Static, nemasurat — nota a coborat din allowlist-ul
       de controale al skinului odata cu valoarea (B159 L10, F2). */
    border: 0; background: var(--ui-raised);   /* B226: locul afișului stă pe pagină — tonul cardului (pe s2: 1.09) */
box-shadow: var(--ui-shadow-raised); border-radius: var(--sm-r-card); }
.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%; }
    /* B218 (v4): „Detalii & program" pe toată lățimea pe telefon — ca „Înscrie-te" din cărțile de categorie. */
    .hero-info { flex: 1 1 100%; }
}
/* 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: var(--type-display-weight, 900); text-transform: var(--type-display-case, uppercase); letter-spacing: var(--type-display-tracking, .01em);
    /* B234 (Arena): numele concursului = AFIȘ — condensat, 32px pe telefon până la 96px pe lat, fluid din container (`cqi`).
       Titlul stă pe același rând cu pilula de stare (B218): `min-width: 0` îl ține în cutia lui. Un nume lung dintr-un cuvânt
       (SloboziaGotFlavor) se rupe DOAR dacă nu încape (`break-word`, cu cratimă unde limba o știe), nu oriunde. */
    font-stretch: var(--ar-wdth);
    font-size: clamp(2rem, .9rem + 4.2cqi, 6rem); line-height: .88; color: var(--ui-ink); margin: 0;
    min-width: 0; overflow-wrap: break-word; word-break: normal; hyphens: auto;
}
/* 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. */
/* B218: strâns sub titlu (`margin-top`), gap fix mic — rândul e scurt (locație · dată · buton). `align-items: center`, nu
   `baseline`: butonul tonal de 44px nu are o linie de scris comună cu textul. ⚠️ Mărimea textului NU se scrie aici — e a
   rolului 4 (mai jos în fișier, aceeași specificitate, câștigă). */
.res-hero__meta { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem .9rem; margin-top: .3rem; color: var(--ui-ink-muted); }
.res-hero__meta i { color: var(--ui-ink-muted); margin-right: .4rem; }
.res-hero__meta b { color: var(--ui-ink); 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 pastila selectată (`.cat-strip__item--on`, B218),
   care poartă și diviziunile 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; }
/* ⚠️ NU pune `container-type: inline-size` aici (încercat și retras în iter. 2o, raportat de user ca
   „line-up și juriu aliniate prost"). `container-type` implică `contain: inline-size`, adică lățimea
   cutiei se calculează IGNORÂND conținutul. `.res-cat-cluster` e însă un FLEX ITEM cu `flex: 0 1 auto`
   în `.res-cat-top` (space-between), deci baza lui vine tocmai din conținut → cu containment se
   prăbușește la ~0 și pastilele se rup pe rânduri. Regula generală: un element care se
   auto-dimensionează din conținut (flex item `auto`, `fit-content`, `inline-block`) NU poate fi
   container de interogare. Aici n-avea nici alt candidat: `.res-cat-head` e `width: fit-content` în
   modul proiector (vezi regula `.live-projector .res-cat-head` mai sus), deci ar fi avut exact
   aceeași problemă, dar numai pe ecranul de sală — adică o regresie care s-ar fi văzut abia în sală. */
.res-cat-cluster { display: flex; flex-wrap: wrap; align-items: flex-start; gap: .5rem clamp(1.25rem, 4vw, 3rem); min-width: 0; }
/* ── JURIUL ȘI LINE-UP-UL: carduri de persoană (B195 L5, prototipul fluxului live) ──
   Au înlocuit rândul de pastile `.res-jury` (iconiță + pastile). Grupul = eticheta SCRISĂ sus („Juriu" / „Line-up";
   la 2j.1 rămăsese doar iconița) și cardurile dedesubt, pe un rând care se înfășoară — aranjamentul fluid al casei.
   Mărimea: pe scara ECRANULUI (`vw`), deliberat — antetul categoriei e un rând de PAGINĂ pe toată lățimea, nu o
   componentă dintr-un panou (aceeași judecată ca la pastilele de dinainte, care le voiau „mari, sunt importanți"). */
.people__grp { display: flex; flex-direction: column; gap: .4rem; min-width: 0; }
/* Familia, mărimea, greutatea și majusculele vin din ROLUL 3 — ETICHETĂ (mai jos în fișier), unde `.people__lbl` a
   luat locul lui `.res-jury__lbl`. Aici doar ce nu e al rolului. */
.people__lbl { color: var(--ui-ink-muted); }
.people__row { display: flex; flex-wrap: wrap; gap: .5rem clamp(.4rem, .8vw, .7rem); }
/* Cardul: pastilă pe suprafața de card + umbra de card (prototipul `.person`), fără ramă (ADR 0057 §4). */
.person-card {
    display: inline-flex; align-items: center; gap: .55em; min-width: 0;
    padding: .25em .95em .25em .25em; border-radius: var(--radius-chip, 999px);
    background: var(--ui-raised); box-shadow: var(--ui-shadow-raised);
    color: var(--ui-ink); text-decoration: none;
    font-size: clamp(var(--font-base), 1.2vw, var(--font-xl));
    --av-size: 2.2em;
}
/* Linkul organizatorului spre pagina juratului: ridicarea la hover, ca orice card care se apasă. */
a.person-card:hover { box-shadow: var(--ui-shadow-float); }
/* Cheia juratului a expirat (organizatorul trebuie s-o reemită) — inelul de pericol; înainte: `border-danger`. */
.person-card--stale { box-shadow: inset 0 0 0 2px var(--ui-danger), var(--ui-shadow-raised); }
/* Cardul de persoană, varianta FLAT (`flat` pe `_person_card`, B204): pe /concursuri oamenii stau pe cardul categoriei, deci
   fără pastilă și fără umbră; avatarul o treaptă mai mic, numele la 14px, linia mică (Head · țara) la 11px. */
.person-card--flat { padding: 0; background: none; box-shadow: none; border-radius: 0; font-size: var(--font-base); --av-size: 1.75rem; }
.person-card--flat .person-card__sub { font-size: var(--font-xs); }
.person-card__who { display: flex; flex-direction: column; min-width: 0; line-height: 1.15; }
.person-card__nm { font-weight: 800; }
.person-card__sub { font-size: .72em; font-weight: 600; color: var(--ui-ink-muted); }
/* „Head" = starea de identitate a juratului-șef (bugetul violetului), pereche cu punctul de pe avatar. */
.person-card__sub b { color: var(--ui-accent); font-weight: 800; text-transform: var(--type-label-case, uppercase); letter-spacing: .03em; }

/* === 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ă.

   ⚠️ Cât timp un selector avea ȘI o regulă `body.kf` în @layer components, rolul de aici nu-l putea
   controla (ordinea layerelor bate specificitatea). Cele două cazuri — `.cat-tabs .nav-link` și
   `.cat-strip__item--on` — au fost curățate de proprietățile pe care le deține rolul, iar de la
   B159 L10 (F1) totul stă într-un singur layer: rolul chiar decide.

   ROL 1 (TITLU) stă lângă `.res-hero__name`, unde se citește împreună cu mărimea lui fluidă.
   ⚠️ `.home-sec__h` a IEȘIT din rolul ETICHETĂ (B159 L4.4, ADR 0054 decizia 7): capetele de pe pagina de start
   numesc exact conținutul căutat („Concursuri deschise", „Ultimul concurs"), deci sunt TITLURI. Rețeta lui stă
   în base-layout.css, lângă restul blocului de home, ca `.home-cta-band__t`. */

/* 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.
   `.people__lbl` (B195 L5) a luat locul lui `.res-jury__lbl` — același rol: eticheta unui grup de oameni. */
.people__lbl,
.rail-nav__lbl,
.home-stats__l,
.lb-kid__avg,
.lb-grp th {
    font-family: var(--font-mono); font-weight: 700;
    font-size: var(--font-xs); line-height: 1.3;
}
/* Tabul de VEDERE (`.cat-tabs .nav-link`) a ieșit din lista de deasupra la B234 (Arena): e titlu condensat, nu etichetă —
   rețeta lui stă mai jos, lângă regula de rol.
   ⚠️ Pastila de categorie (`.cat-strip__l1`) a IEȘIT din rolul ETICHETĂ la B218 (ADR 0059): activul și inactivul au
   acum O singură rețetă (display 700, `--font-lg`, fără majuscule), scrisă lângă pastilă în scoreboard.css — tocmai
   ca selecția să nu mai poată schimba mărimea (standardul Material 3 / Carbon / Apple HIG; lecția din 2026-09-28,
   când inactivul se randa la 12px față de 16px și se citea ca alt fel de obiect, rămâne valabilă: e păzită acum de o
   singură regulă, nu de două care trebuie ținute egale de mână). */
/* Majusculele și tracking-ul, pe ROL (B159 L0.8b): etichetele și tab-urile de vedere au azi aceeași rețetă, dar skinul
   le remapează separat (`--type-label-*` / `--type-tab-*`) — de aceea două reguli, lipite de lista de mai sus. */
.people__lbl, .rail-nav__lbl, .home-stats__l, .lb-kid__avg, .lb-grp th { text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .06em); }
.cat-tabs .nav-link { text-transform: var(--type-tab-case, uppercase); letter-spacing: var(--type-tab-tracking, .06em); }
/* Taburile Calificare | Bracket = navigarea PRINCIPALĂ a categoriei (iter. 2k: „mărim și mai mult fontul"). B234 (Arena): titlu de
   afiș — condensat, 900, pe mărimea tab-urilor subliniate (`--ar-fs-tab`), activ și inactiv la fel (selecția = sublinierea).
   Cazul și tracking-ul rămân pe rolul `tab`. */
.cat-tabs .nav-link { font-family: var(--font-display); font-weight: 900; font-stretch: var(--ar-wdth); font-size: var(--ar-fs-tab); line-height: 1.3; }

/* ---- TAB-URILE DE CATEGORIE: venit din kf-skin.css la B159 L10 (F1) ----
   Neprefixat, aceeasi specificitate ca regulile de baza → decide ordinea in text, exact
   precedenta pe care o dadea layerul inainte. */
  /* `.cat-tabs { border-bottom }` sters: skinul ii da rigla intreaga (1px `--sm-hair`).
     La fel `background` si `margin-bottom` de pe `.nav-link`, si hover-ul — toate intregi la skin. */
  /* `border: 0` stinge celelalte trei laturi; `border-bottom` tine GROSIMEA riglei de sub tab —
     3px, coborata din `@layer skin` la B159 L10 (F2) (era 2px inainte de skin).
     ⚠️ TINTA DE TAP: 3px LARGESTE tab-ul, nu-l stramteaza (static, nemasurat) — de-aia n-a cerut
     masuratoare. Daca vreodata scade sub 2px, masoara cu `ui-probe tap`. */
  /* B234 (Arena): tabul stă pe fir, fără umplere; paddingul de jos + bordura de 3px = sublinierea machetei (aceeași geometrie ca
     `inset 0 -3px 0` din machetă), dar BORDURĂ, nu umbră: modul cu culori forțate șterge umbrele, iar regulile `forced-colors` de
     mai jos pictează bordura. */
  .cat-tabs .nav-link {
    border: 0; border-bottom: 3px solid transparent; border-radius: 0;
  background: transparent; margin-bottom: -1px; padding: 0 0 calc(.6rem - 3px); }
  /* ⚠️ REVENIRE 2026-08-15: pusesem `var(--volt)` aici „ca să fie același verde ca la nivelul 1".
     Era o regresie invizibilă pe tema LIGHT: volt = lime #ccff00, iar ca LINIE pe suprafața deschisă
     dă 1.10:1 — marcajul tabului activ dispărea pur și simplu. `--kf-marker` E tokenul făcut pentru
     asta (tokens.css: „un marcaj trebuie să contrasteze cu ce e SUB el, deci urmează tema"):
     olive #506600 pe light (6.06:1), lime-dim pe dark (9.75:1). Traseul verde de la nivelul 1
     (linia benzii + șina lui `.cat-block`) folosea `--primary`, același olive — traseul a DISPĂRUT la B218
     (pastile, fără „L"); lecția despre marcaj rămâne. */
  /* `border-bottom-color` sters: skinul da marcajul tabului activ. Lectia din nota de deasupra
     ramane valabila pentru oricine il rescrie — un marcaj trebuie sa contrasteze cu ce e SUB el. */


/* ROL 2 — SUBTITLU: era tabul de categorie ACTIV (`.cat-strip__item--on .cat-strip__l1`, display 750 upper, `--font-lg`).
   ȘTERS la B218 (ADR 0059): pastila selectată NU mai are altă rețetă de text decât cea inactivă — selecția e doar
   umplerea (vezi `.cat-strip__l1` în scoreboard.css). Rolul își păstrează locul în registru, fără subiect azi. */

/* ROL 4 — CORP: singura zonă de text „normal" din antet. `--font-base` (B218, antetul compact al prototipului v4),
   nu `--sm-fs-body`: rândul de meta stă acum strâns sub titlu, nu ca paragraf. ⚠️ Mărimea se scrie AICI, nu în regula
   de așezare `.res-hero__meta` de mai sus — aceeași specificitate, iar asta vine mai târziu în fișier, deci câștigă
   (C2 din stres-testul planului: o editare acolo n-ar avea niciun efect). */
.res-hero__meta {
    font-family: var(--font-sans); font-weight: 400;
    font-size: var(--font-base); line-height: 1.35; color: var(--ui-ink-muted);
}

/* ROL 5 — CIFRE / META. Regula de aici avea UN SINGUR selector, `.cat-strip__l2` — linia de context
   a tabului de categorie (TOP N · diviziuni · stare). Linia a fost ȘTEARSĂ pe 2026-09-28 (banda trece
   pe un singur rând), deci regula rămânea fără subiect — a plecat odată cu ea. ⚠️ Numele `.cat-strip__l2`
   a REVENIT la B219, dar ca rândul diviziunilor de pe pastilă (doar cipuri `.cat-disc`, rețeta în scoreboard.css),
   NU ca text de rol — rolul rămâne fără subiect.
   ⚠️ Rolul êsi păstrează locul în registru: `.cat-disc` e candidatul evident, dar e componentă GLOBALĂ
   (/arhiva, banda de categorii, admin) — promovarea la rol e o schimbare separată, mai mare decât livrarea asta.
   (`.badge-top-n` a plecat la B204: rândul TOP N de pe /concursuri, singurul lui consumator, a dispărut.) */


/* === DOCUMENT LEGAL (confidențialitate / termeni) =========================================
   O SINGURĂ clasă cu reguli de element scopate sub ea — singurul loc din casă unde selectorii de
   element sunt justificați: e text lung scris de mână, iar alternativa (utilitare Bootstrap
   presărate prin Twig) ar face ca a treia pagină legală să arate altfel decât primele două.
   Măsura 65ch = pragul de lizibilitate (45-75 caractere pe rând); paginile NU poartă `page-wide`,
   deci containerul e 1200px, iar coloana se centrează în el.
   Regulile stau în @layer app → bat Bootstrap (@layer vendor) fără `!important`. */
.legal-doc { max-width: 65ch; margin-inline: auto; }
.legal-doc__meta {
    font-family: var(--font-mono); font-size: var(--font-2xs); color: var(--ui-ink-muted);
    text-transform: var(--type-label-case, uppercase); letter-spacing: var(--type-label-tracking, .08em); margin: -.5rem 0 2rem;
}
.legal-doc h2 {
    font-family: var(--font-display); font-weight: var(--type-title-weight, 900); text-transform: var(--type-title-case, uppercase);
    letter-spacing: var(--type-title-tracking, .02em); font-size: var(--sm-fs-title); margin: 2.25rem 0 .5rem;
}
.legal-doc h3 { font-size: var(--font-lg); font-weight: 700; margin: 1.25rem 0 .35rem; }
.legal-doc p, .legal-doc li { font-size: var(--font-base); line-height: 1.65; color: var(--ui-ink-muted); }
.legal-doc ul, .legal-doc ol { margin: 0 0 1rem; padding-left: 1.2rem; }
.legal-doc li { margin-bottom: .3rem; }
.legal-doc a { color: var(--ui-ink); }
.legal-doc strong { color: var(--ui-ink); }
/* Tabelele (temeiuri, cookie-uri) trag lateral pe telefon în loc să spargă pagina — aceeași regulă
   ca tabelele dense: se strâng întâi, trag după. Podeaua stă pe COLOANĂ, nu pe tabel. */
.legal-doc__table { overflow-x: auto; margin: .5rem 0 1.25rem; }
.legal-doc table { width: 100%; border-collapse: collapse; font-size: var(--font-sm); }
.legal-doc th, .legal-doc td {
    border-bottom: 1px solid var(--ui-hair); padding: .4rem .6rem;
    text-align: left; vertical-align: top; min-width: 6rem;
}
/* Coborata din `@layer skin` la B159 L10 (F2).
   B189: zebra alternează INTRĂRILE (`tbody.lb-entry`), nu rândurile — fiecare intrare are un rând
   principal + unul de detalii, deci `tr:nth-child(even)` ar fi colorat exact detaliile. Detaliile iau
   tenta intrării lor, deci se citesc ca un singur bloc cu numele. */
.lb-panel .tier-table tbody.lb-entry:nth-of-type(even) td { background: var(--ui-zebra); }
/* TENTA DE RANG pe locurile 1-2-3 (owner, 2026-09-28: „doar să le colorăm puțin în culorile de 1 2 3").
   Scrisă ca `color-mix` cu un token care se întoarce singur pe temă — aceeași formă pe care o are și
   `--sm-zebra` (site-palette.css), ca să nu inventez un al doilea mecanism de tentă în același tabel.
   ⚠️ Varianta `-ink`, NU culoarea medaliei: `--rank-gold/silver/bronze` sunt culori DESCHISE, făcute
   pentru UMPLERE. Ca tentă pe alb ar fi fost aproape invizibile pe light și stridente pe dark —
   capcana măsurată la podium (1.87 pe light vs 9.11 pe dark). Familia `-ink` e „rangul ca SEMN pe o
   suprafață" și are pereche pe fiecare temă (`tokens.css:410-414` / `:697`).
   ⚠️ ORDINEA: regula asta are aceeași specificitate ca zebra, deci trebuie să stea DUPĂ ea ca s-o bată.
   Nu o muta mai sus. `:hover` (`.lb-panel .tier-table tbody.lb-entry > tr:not(.lb-detail):hover td`,
   (0,5,3)) le bate pe amândouă prin specificitate.
   ⚠️ `:has()` pe INTRARE (B189: pe `tbody.lb-entry`, înainte pe rând), fiindcă clasa de rang stă pe
   `<span>`-ul din prima celulă, nu pe `<tr>` — iar markupul ăla e partajat cu `_dancer_row` și cu
   tabelul de crew-uri, deci NU se atinge. Pe intrare, și rândul de detalii ia tenta locului.
   ⚠️ PROCENTUL E 6, ALES PRIN MĂSURARE, nu din ochi — și e un plafon, nu o preferință. Fundalul fiind
   TRANSLUCID, `getComputedStyle` întoarce culoarea NEcompusă și minte; singura măsurătoare onestă e pe
   pixeli. Citite din randare, cifra pe tenta ei, cele șase perechi (3 locuri × 2 teme):
       12%  →  4.47 pe light loc 1 și 4.17 pe dark loc 3  — SUB prag
        8%  →  4.44 pe dark loc 3                         — SUB prag
        7%  →  toate trec, dar cel mai strâns e 4.52      — 0.02 marjă, prea puțin
        6%  →  toate trec, cel mai strâns 4.65            — ALES
   Cifra e 12px/900, deci pragul aplicabil e 4.5, nu 3 (nu se califică drept „text mare").
   ⚠️ `contrast-audit` NU POATE prinde perechea asta: fundalurile translucide sunt în categoria lui
   „nemăsurabil". Dacă se umblă la procent, se remăsoară pe pixeli — gate-ul verde nu e dovadă aici. */
.lb-panel .tier-table tbody.lb-entry:has(.rank-1) td { background: color-mix(in srgb, var(--ui-rank-gold-ink) 6%, transparent); }
.lb-panel .tier-table tbody.lb-entry:has(.rank-2) td { background: color-mix(in srgb, var(--ui-rank-silver-ink) 6%, transparent); }
.lb-panel .tier-table tbody.lb-entry:has(.rank-3) td { background: color-mix(in srgb, var(--ui-rank-bronze-ink) 6%, transparent); }
/* INTRAREA DESCHISĂ (B189): tenta de identitate pe tot grupul + muchie violet de 3px în stânga — se
   vede că rândul de detalii / membrii sunt ai numelui de deasupra. (0,5,3): bate zebra și tenta de rang.
   Copiii crew-ului își păstrează suprafața proprie (a doua regulă, aceeași specificitate, mai jos), ca
   membrul să nu se confunde cu crew-ul; muchia îi leagă. `:not(.lb-row)`, nu `.collapse`: în timpul
   animației Bootstrap înlocuiește `.collapse` cu `.collapsing`. */
.lb-panel .tier-table tbody.lb-entry:has(.lb-toggle[aria-expanded="true"]) > tr > td { background: var(--ui-accent-tint); }
.lb-panel .tier-table tbody.lb-entry:has(.lb-toggle[aria-expanded="true"]) > tr > td:first-child { box-shadow: inset 3px 0 0 var(--ui-accent); }
.lb-panel .tier-table tbody.lb-entry > tr.lb-kid:not(.lb-row) > td { background: var(--ui-sunken); }
.legal-doc th {
    font-family: var(--font-mono); font-size: var(--font-2xs); text-transform: var(--type-label-case, uppercase);
    letter-spacing: var(--type-label-tracking, .06em); color: var(--ui-ink-muted); font-weight: 400;
}


}

/* ⚠️ Regulile de mai jos au venit din `@layer skin` la B159 L10 (F2) si TREBUIE sa stea intr-un
   layer: o regula NELAYERIZATA bate toate layerele, deci ar fi capatat o precedenta pe care skinul
   n-o avea. `@layer app` e acelasi layer ca regulile de baza pe care le acopera. ⚠️ Ordinea din lant
   (base.html.twig): tokens → scoreboard → components → admin → base-layout → site-palette — deci la
   specificitate egala `base-layout.css` BATE regulile de aici; de aceea base-layout nu scrie culori /
   suprafete pe selectoarele din blocul „VALORI DE SITE" de mai jos (corectat 2026-10-03, zicea invers). */
@layer app {
   /* END @layer app */

  /* Culorile locului din calificare (fostele `--bs-secondary-color` pe `.col-rank-narrow`) stau de la B234 pe `.qual-rank`, în
     scoreboard.css: cifra nu mai poartă `.text-muted`. */
  /* B234 (Arena): contorul din capul panoului = plăcuță (colț de control), mai mare — pe toate panourile, nu doar în tabul de
     calificare. Plinul („8/8") e `badge-battle--completed` (lime + cerneala lui), nu `bg-success`. */
  .cat-panel-hdr .badge { border-radius: var(--radius-control, 0); letter-spacing: 0; font-size: var(--font-base); padding: .3rem .55rem; }
  /* Coborata din `@layer skin` la B159 L10 (F2). */
  .cat-tabs .nav-link:hover { background: transparent; color: var(--ui-ink); border-bottom-color: var(--ui-line); }
  /* Coborata din `@layer skin` la B159 L10 (F2). */
  .alert-success::before { content: "✓"; content: "✓" / ""; margin-inline-end: .35em; font-weight: 700; }
  /* Coborata din `@layer skin` la B159 L10 (F2). */
  .alert-info { background: var(--ui-subtle); border-color: transparent; color: var(--ui-ink); --bs-alert-link-color: var(--ui-ink); }
  /* Coborata din `@layer skin` la B159 L10 (F2). */
  .alert-secondary { background: var(--ui-subtle); border-color: var(--ui-line); color: var(--ui-ink-muted); }
  /* (`.cat-disc:not(.cat-disc--plain)` — cipul CONTURAT, coborât din skin la B159 L10 — și `.cat-strip__item--on .cat-disc:not(…)` au fost
     ȘTERSE la B219: rețeta plină „pe negativ" e acum a componentei, în regula de bază `.cat-disc` de mai sus (§ CHIPS). O regulă (0,2,0) aici,
     mai jos în foaie, ar fi bătut orice (0,2,0) de pe pastilă — capcana prinsă de stres-testul planului B219.) */

    /* ══════════ VALORI DE SITE pentru reguli care traiesc in foi PARTAJATE CU JURATUL ══════════
       `.alert-*` si `.brand-modal` isi au regula de baza in `tokens.css` / `base-layout.css`, pe care le
       incarca si ecranul juratului — iar acolo tokenii `--sm-*` nu exista. Regulile de baza raman ale
       juratului, neatinse; astea de aici sunt valorile de SITE. Coborate din `@layer skin` la B159 L10 (F2).
       ⚠️ ORDINEA din lant (`base.html.twig`): tokens → scoreboard → components → admin → base-layout → paleta.
       Fata de `tokens.css` castiga prin ordine; fata de `base-layout.css` NU (se incarca DUPA) — acolo regula de
       baza nu trebuie sa scrie deloc proprietatea pe care o da valoarea de site (corectat la B188, 2026-10-01).
       ⚠️ Nu muta declaratiile astea „mai aproape de regula lor": acolo ar strica ecranul juratului. */
    .alert-danger { background: var(--ui-danger-soft); border-color: transparent; color: var(--ui-on-danger-soft); --bs-alert-link-color: var(--ui-on-danger-soft); }
    .alert-warning { background: var(--ui-warning-soft); border-color: transparent; color: var(--ui-on-warning-soft); --bs-alert-link-color: var(--ui-on-warning-soft); }
    .alert-info { background: var(--ui-subtle); border-color: transparent; color: var(--ui-ink); --bs-alert-link-color: var(--ui-ink); }
    /* Succesul e un TOAST: pluteste, deci are nevoie de o suprafata — s1 + contur, ca modalul (nu umplere
       lime). Bifa vine din `::before`, ascunsa cititoarelor de ecran. */
    .alert-success { background: var(--ui-flat); border-color: var(--ui-line); color: var(--ui-ok); }
    /* Iconița „+" de la „Concurs nou", din meniul de cont. Regula de bază (greutatea) stă în
       `base-layout.css`, care e partajat cu juratul; CULOAREA e valoare de site, deci aterizează aici.
       Juratul nici nu randează bara, dar convenția fișierului rămâne convenție. */
    .app-nav__menu .app-nav__menu-cta .bi { color: var(--ui-win-ink); }
    /* BUTONUL GHOST (B234, Arena: „ghost vizibil pe scenă"): pe site = transparent, cu inel de cerneală 38%; sub cursor se
       inversează. Regula de bază (`base-layout.css`) e a JURATULUI — o folosește modalul de confirmare construit în JS — și scrie
       aceleași proprietăți, iar foaia aia se încarcă DUPĂ asta: de aceea (0,2,0) aici, nu o redeclarare de tokeni acolo (garda
       B230 nu lasă foaia comună să citească o culoare nouă din paletă). `:active` (0,2,0, base-layout) rămâne starea apăsată. */
    .btn-ink.btn-ink--ghost { background: transparent; color: var(--ui-ink); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ui-ink) 38%, transparent); }
    .btn-ink.btn-ink--ghost:hover { background: var(--ui-inverse); color: var(--ui-on-inverse); box-shadow: none; }
    /* BARA DE NAVIGAȚIE (B188, direcția B): culorile BENZII, din rolurile `--nav-*` (site-palette.css). Geometria e în
       `base-layout.css`, care nu mai scrie nicio culoare pe selectoarele astea. Inelul de focus ia culoarea textului
       benzii — pe banda de cerneală, cerneala paginii ar dispărea (1.00:1). */
    .app-nav { background: var(--nav-bg); box-shadow: var(--nav-shadow); --ui-focus: var(--nav-fg-on); --focus-ring: var(--nav-fg-on); /* puntea B231 */ }
    .app-nav__link { color: var(--nav-fg); }
    .app-nav__link--active { color: var(--nav-fg-on); }
    .app-nav__link--active::after { border-top-color: var(--nav-ind); }
    .app-nav__theme { border-color: var(--nav-ctl-line); color: var(--nav-fg-on); }
    .app-nav__user { border-color: var(--nav-ctl-line); color: var(--nav-fg); }
    /* „Login" (B234, Arena): conturat pe bandă, inversat sub cursor. (0,2,0) / (0,3,0): regula de bază `.app-nav__btn` (și hover-ul
       ei) stă în `base-layout.css`, care se încarcă după foaia asta. */
    .app-nav__btn.app-nav__btn--flash { background: transparent; border-color: var(--nav-ctl-line); color: var(--nav-fg-on); }
    @media (hover: hover) { .app-nav__btn.app-nav__btn--flash:hover { background: var(--nav-fg-on); border-color: var(--nav-fg-on); color: var(--nav-bg); } }
    /* Meniurile din bară (login / cont) stau pe tema PAGINII → inelul lor de focus revine la cerneala paginii. */
    .app-nav .dropdown-menu { --ui-focus: var(--ui-ink); --focus-ring: var(--ui-ink); /* puntea B231 */ }
    /* PRIMA PAGINĂ (B214): suprafețele cardurilor — ușile, concursul scos în față, RÂNDURILE arhivei (fiecare rând e un card, ca
       rândurile top 3 de alături — prototipul aprobat), banda „Cere cont". Geometria lor e în `base-layout.css` §17 (foaie comună cu
       juratul), care nu scrie nicio culoare pe selectoarele astea. Card pe pagină = treaptă tonală + umbră (cast-ui §3), iconița
       ușii stă o treaptă sub card. */
    .home-door, .home-feat, .home-list__row, .home-cta-band { background: var(--ui-raised); box-shadow: var(--ui-shadow-float); }
    .home-cta-band { color: var(--ui-ink); }
    .home-door__ico { background: var(--ui-sunken); color: var(--ui-ink); }

/* Coborata din `@layer skin` la B159 L10 (F2). */
.btn-outline-danger { --bs-btn-color: var(--ui-danger); --bs-btn-bg: transparent; --bs-btn-border-color: var(--ui-danger); --bs-btn-hover-color: var(--ui-on-danger-soft); --bs-btn-hover-bg: var(--ui-danger-soft); --bs-btn-hover-border-color: var(--ui-danger); --bs-btn-active-color: var(--ui-on-danger-soft); --bs-btn-active-bg: var(--ui-danger-soft); --bs-btn-active-border-color: var(--ui-danger); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.btn-danger { --bs-btn-color: var(--ui-on-danger); --bs-btn-bg: var(--ui-danger); --bs-btn-border-color: var(--ui-danger); --bs-btn-hover-color: var(--ui-on-danger); --bs-btn-hover-bg: var(--ui-danger-hover); --bs-btn-hover-border-color: var(--ui-danger-hover); --bs-btn-active-color: var(--ui-on-danger); --bs-btn-active-bg: var(--ui-danger-hover); --bs-btn-active-border-color: var(--ui-danger-hover); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.btn-outline-success { --bs-btn-color: var(--ui-ink); --bs-btn-bg: var(--ui-quiet); --bs-btn-border-color: var(--ui-line); --bs-btn-hover-color: var(--ui-ink); --bs-btn-hover-bg: color-mix(in srgb, var(--ui-ink) 12%, var(--ui-quiet)); --bs-btn-hover-border-color: var(--ui-line); --bs-btn-active-color: var(--ui-on-pressed); --bs-btn-active-bg: var(--ui-pressed); --bs-btn-active-border-color: var(--ui-pressed-edge); --bs-btn-disabled-color: var(--ui-ink-muted); --bs-btn-disabled-bg: transparent; --bs-btn-disabled-border-color: var(--ui-edge); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.btn-outline-warning { --bs-btn-color: var(--ui-ink); --bs-btn-bg: var(--ui-quiet); --bs-btn-border-color: var(--ui-line); --bs-btn-hover-color: var(--ui-ink); --bs-btn-hover-bg: color-mix(in srgb, var(--ui-ink) 12%, var(--ui-quiet)); --bs-btn-hover-border-color: var(--ui-line); --bs-btn-active-color: var(--ui-on-pressed); --bs-btn-active-bg: var(--ui-pressed); --bs-btn-active-border-color: var(--ui-pressed-edge); --bs-btn-disabled-color: var(--ui-ink-muted); --bs-btn-disabled-bg: transparent; --bs-btn-disabled-border-color: var(--ui-edge); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.btn-outline-primary { --bs-btn-color: var(--ui-ink); --bs-btn-bg: var(--ui-quiet); --bs-btn-border-color: var(--ui-line); --bs-btn-hover-color: var(--ui-ink); --bs-btn-hover-bg: color-mix(in srgb, var(--ui-ink) 12%, var(--ui-quiet)); --bs-btn-hover-border-color: var(--ui-line); --bs-btn-active-color: var(--ui-on-pressed); --bs-btn-active-bg: var(--ui-pressed); --bs-btn-active-border-color: var(--ui-pressed-edge); --bs-btn-disabled-color: var(--ui-ink-muted); --bs-btn-disabled-bg: transparent; --bs-btn-disabled-border-color: var(--ui-edge); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.btn-outline-info { --bs-btn-color: var(--ui-ink); --bs-btn-bg: var(--ui-quiet); --bs-btn-border-color: var(--ui-line); --bs-btn-hover-color: var(--ui-ink); --bs-btn-hover-bg: color-mix(in srgb, var(--ui-ink) 12%, var(--ui-quiet)); --bs-btn-hover-border-color: var(--ui-line); --bs-btn-active-color: var(--ui-on-pressed); --bs-btn-active-bg: var(--ui-pressed); --bs-btn-active-border-color: var(--ui-pressed-edge); --bs-btn-disabled-color: var(--ui-ink-muted); --bs-btn-disabled-bg: transparent; --bs-btn-disabled-border-color: var(--ui-edge); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.btn-secondary { --bs-btn-color: var(--ui-ink); --bs-btn-bg: var(--ui-quiet); --bs-btn-border-color: var(--ui-line); --bs-btn-hover-color: var(--ui-ink); --bs-btn-hover-bg: color-mix(in srgb, var(--ui-ink) 12%, var(--ui-quiet)); --bs-btn-hover-border-color: var(--ui-line); --bs-btn-active-color: var(--ui-on-pressed); --bs-btn-active-bg: var(--ui-pressed); --bs-btn-active-border-color: var(--ui-pressed-edge); --bs-btn-disabled-color: var(--ui-ink-muted); --bs-btn-disabled-bg: transparent; --bs-btn-disabled-border-color: var(--ui-edge); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.btn-primary { --bs-btn-color: var(--ui-ink); --bs-btn-bg: var(--ui-quiet); --bs-btn-border-color: var(--ui-line); --bs-btn-hover-color: var(--ui-ink); --bs-btn-hover-bg: color-mix(in srgb, var(--ui-ink) 12%, var(--ui-quiet)); --bs-btn-hover-border-color: var(--ui-line); --bs-btn-active-color: var(--ui-on-pressed); --bs-btn-active-bg: var(--ui-pressed); --bs-btn-active-border-color: var(--ui-pressed-edge); --bs-btn-disabled-color: var(--ui-ink-muted); --bs-btn-disabled-bg: transparent; --bs-btn-disabled-border-color: var(--ui-edge); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.btn-info { --bs-btn-color: var(--ui-ink); --bs-btn-bg: var(--ui-quiet); --bs-btn-border-color: var(--ui-line); --bs-btn-hover-color: var(--ui-ink); --bs-btn-hover-bg: color-mix(in srgb, var(--ui-ink) 12%, var(--ui-quiet)); --bs-btn-hover-border-color: var(--ui-line); --bs-btn-active-color: var(--ui-on-pressed); --bs-btn-active-bg: var(--ui-pressed); --bs-btn-active-border-color: var(--ui-pressed-edge); --bs-btn-disabled-color: var(--ui-ink-muted); --bs-btn-disabled-bg: transparent; --bs-btn-disabled-border-color: var(--ui-edge); }
  /* Avertismentul de dublura de la inscriere — VENIT din base-layout.css la B159 L10 (F2).
     Construit din JS de `entry_autocomplete_controller.js`, deci e strict al site-ului; foaia
     de unde a venit e incarcata si de ecranul juratului. */
  /* Warning fuzzy „ești tu?" la înscriere (near-duplicate nudge) — bloc full-width SUB rând */
  .dup-warn { width: 100%; margin: 0 0 .5rem; padding: .35rem .5rem; background: var(--ui-warning-soft); border: 1px solid var(--ui-warning-edge); border-radius: var(--radius-md); font-size: var(--font-xs); color: var(--ui-on-warning-soft); border-color: transparent; }
  .dup-warn__head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; margin-bottom: .25rem; }
  .dup-warn__q { color: var(--ui-on-warning-soft); font-weight: 600; }
  .dup-warn__close { flex-shrink: 0; border: 1px solid var(--ui-hair); background: var(--ui-flat); border-radius: var(--radius-sm); padding: .05rem .5rem; font-size: var(--font-xs); cursor: pointer; white-space: nowrap; color: var(--ui-ink-muted); }
  .dup-warn__close:hover { background: var(--ui-quiet); color: var(--ui-ink); border-color: var(--ui-line); }
  .dup-warn__pick { display: inline-block; margin: .12rem .2rem .12rem 0; padding: .12rem .5rem; background: var(--ui-flat); border: 1px solid var(--ui-hair); border-radius: var(--radius-sm); font-size: var(--font-xs); cursor: pointer; }
  .dup-warn__pick:hover { background: var(--ui-quiet); color: var(--ui-ink); border-color: var(--ui-ink); }

  /* ---- HOVER, coborat din `@layer skin` la B159 L10 (F2) ----
     ⚠️ Blocul sta INADINS la coada layerului: regulile de aici au aceeasi specificitate ca cele de
     baza pe care le acopera, deci ordinea decide — exact precedenta pe care le-o dadea layerul.
     Garda `(hover: hover)` ramane: pe touch `:hover` e lipicios, iar starea de repaus trebuie sa fie
     cea care se vede. */
  @media (hover: hover) {
    .kf-catrow:hover td { background: color-mix(in srgb, var(--ui-ink) 8%, transparent); color: var(--ui-ink); }
    /* Bara (B188): hover-ul linkului inactiv, al comutatorului de temă și al contului — pe rolurile benzii. */
    .app-nav__link:not(.app-nav__link--active):hover { color: var(--nav-fg-on); background: var(--nav-hover); }
    .app-nav__theme:hover { background: var(--nav-fg-on); border-color: var(--nav-fg-on); color: var(--nav-bg); }
    .app-nav__user:hover { color: var(--nav-fg-on); background: var(--nav-hover); }
    /* B189: pe rândul PRINCIPAL al intrării (butonul), nu pe detalii. (0,5,3) — bate zebra și tenta de
       rang, (0,4,2), și tenta de intrare deschisă, (0,5,3) dar mai sus în fișier. */
    .lb-panel .tier-table tbody.lb-entry > tr.lb-row:hover td { background: color-mix(in srgb, var(--ui-ink) 8%, transparent); color: var(--ui-ink); }
  }

  /* Partea de FORCED COLORS a taburilor de categorie: sublinierea e singurul semn al selectiei, iar
     modul cu culori fortate sterge culorile de chenar. Coborata din `@layer skin` la B159 L10 (F2). */
  @media (forced-colors: active) {
    .cat-tabs .nav-link:not(.active) { border-bottom-color: Canvas; }
    .cat-tabs .nav-link.active { border-bottom-color: Highlight; }
  }

/* Coborata din `@layer skin` la B159 L10 (F2). */
.entry-form .form-select:user-invalid { box-shadow: inset 0 0 0 1px var(--ui-danger); }
/* Coborata din `@layer skin` la B159 L10 (F2). */
.entry-form .form-select:focus { box-shadow: inset 0 0 0 1px var(--ui-ink); }
  /* Raza campurilor e o valoare de SITE: regula de baza sta in `tokens.css`, pe care il incarca si
     ecranul juratului, iar acolo `--sm-r-row` nu exista. `components.css` se incarca dupa, deci
     override-ul asta castiga pe site si lasa juratul cu raza lui Bootstrap. B159 L10 (F3). */
  .form-control, .form-select { border-radius: var(--sm-r-row); }

  /* Cifrele cu latime fixa pe toata pagina (coborat din `@layer skin` la B159 L10, F2). Foaia asta e
     incarcata doar de site, deci `body` neprefixat NU ajunge la ecranul juratului. */
  body { font-variant-numeric: tabular-nums; }
  /* Ultima declaratie care a mai purtat o valoare din `kf-skin.css` (B159 L10, F4). Body-ul acopera
     fereastra si cu continut scurt. Celelalte sase ale regulii `body.kf` erau identice cu ce da deja
     `html, body` din `tokens.css`, fiindca paleta remapeaza rolul kf si rolul de baza la acelasi
     token (`--kf-bg`/`--page-bg`, `--kf-text`/`--fg1`, `--kf-font`/`--font-sans`) — masurat, apoi
     sonda a confirmat pe 132 de variante. Neprefixata: foaia asta e doar de site. */
  body { min-height: 100dvh; }
  /* Confirmarile care au bifa in markup: ramane bifa, pleaca verdele brut. */
  .reg-done,
  .enf-opt.is-onfile > .enf-onfile .bi { color: var(--ui-ok); }
}
