/* Kerber 2.0 design tokens — dark-only v1 (spec §10.9).
   Values extracted from the Cominus source; provenance, contrast notes and the full component
   recipes live in docs/design/cominus-design-reference.md. All colors in all web components go
   through these --k-* tokens — never raw hex. The light theme (v2.1) will be one alternative
   token block, not a redesign.

   A11Y (Task 9, W1). Two of the three pieces have no automated oracle and are verified by eye at the
   package gate, which is a decision rather than an omission:
     - CONTRAST (scen 9, 10) is a property of the token PAIRS, not of any one rule here. The pairs
       this sheet uses — --k-text and --k-text-muted on --k-bg/--k-surface, --k-btn-text-on-accent on
       --k-accent — are measured and documented at ≥ WCAG AA in cominus-design-reference.md §2. A rule
       that invents a new pair is the thing to look for in review; this sheet has none.
     - ZOOM (scen 13, 14; ruling G15) targets "usable at 200% browser zoom". Everything here is sized
       in px or rem against the browser's own zoom, and the only viewport-locked height (--k-navbar-h,
       and the grid's 100dvh calc) reflows rather than clips — but the target is an eye judgement at
       the gate, and G15 says so explicitly.
     - KEYBOARD FOCUS (scen 11, 12) is the one that IS pinned: see --k-focus-ring below and the
       :focus-visible rules, guarded by ThemeTests. */

/* K3a′ D4 (W-02): Saira Semi Condensed 400/500/600/700 as woff2, all four converted from the SAME android build
   (android/app/src/main/res/font, Version 0.072; licence ../fonts/OFL.txt). The family keeps the name 'Saira' that
   --k-font-sans already gives every consumer. Before D4, 500 fell back to the 400 face and 700 was synthesised
   from 600. The TTFs in ../fonts stay: Kerber.Server.csproj embeds them for the working-day PDF and the map
   labels, not the web.
   Pinned by ThemeTests.D4_* (four faces, format('woff2'), file signature wOF2, OFL, no .ttf). */
@font-face {
    font-family: 'Saira';
    src: url('../fonts/SairaSemiCondensed-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Saira';
    src: url('../fonts/SairaSemiCondensed-Medium.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Saira';
    src: url('../fonts/SairaSemiCondensed-SemiBold.woff2') format('woff2');
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Saira';
    src: url('../fonts/SairaSemiCondensed-Bold.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

:root {
    /* surfaces & text */
    --k-bg: #0A0B14;
    --k-surface: #13151F;
    --k-text: #DADCE8;
    --k-text-muted: #8A93B0;
    /* Ekran 7, korak 6b: web-30's --label (web-00's palette) — the tier between --k-text and
       --k-text-muted, for group headings and key caps. A NEW PAIR, so its contrast is stated here
       (WCAG 2.x relative luminance): 9.4:1 on --k-surface, 10.1:1 on --k-bg. */
    --k-text-label: #B6B9D1;
    --k-border: #242845;          /* hairlines: row separators, segmented controls */
    --k-border-strong: #363C68;   /* structure: cards, dialogs, inputs */

    /* accent (cyan) family */
    --k-accent: #00B4D8;
    --k-accent-hover: #0593AF;
    --k-accent-soft: #45D7F4;
    --k-accent-indigo: #48508B;
    --k-accent-rgb: 0, 180, 216; /* rgba(var(--k-accent-rgb), .05/.1/.15/.2) washes */
    --k-btn-text-on-accent: #0A0B14;
    /* Task 2 (W1): provenance — Cominus's own --white-rgb compositing token (§2), needed for the
       topbar's hairline bottom border (rgba(var(--white-rgb), 0.03) in the §5 recipe). */
    --k-white-rgb: 255, 255, 255;

    /* semantics */
    --k-success: #35CB7D;
    --k-danger: #FF5651;
    /* W3 Task 5: the compositing form of --k-danger, for the same reason --k-accent-rgb exists —
       rgba(var(--k-danger-rgb), .06) washes. §10.1's red notification rows were the first caller; web-07
       #29 (P-v1 po mocku :78) took their wash away, and the token stays (a revert of P-v1 brings the
       wash back; ThemeTokenSmokeTests pins its channels against --k-danger). */
    --k-danger-rgb: 255, 86, 81;
    --k-success-rgb: 53, 203, 125;
    --k-warning: #F0B429;
    --k-warning-rgb: 240, 180, 41;

    /* task/assignment status (grids arrive with W-packages) */
    --k-status-pending: #6B7280;
    --k-status-in-progress: #00B4D8;
    --k-status-completed: #06D48D;
    --k-status-cancelled: #FF5C5C;
    --k-status-on-hold: #FFB347;
    --k-status-draft: #9CA3AF;
    /* DIZ-1 K2a (O-K2-8, ARH-C 050521): the OFF dot of `.k-status` — mock `.st i` #6B7590 (25/25). Not
       `--k-status-off`: the `--k-status-*` names above are the TASK status palette. A NEW PAIR for a
       non-text mark (WCAG 2.x 1.4.11, ≥ 3:1), measured with kontrast.pl (control #FFF/#000 = 21:1):
       3.96:1 on --k-surface, 4.27:1 on --k-bg. */
    --k-status-dot-off: #6B7590;

    /* web-08 08B (ARH-C 20261003-063036, mock :251 `--c:#5B6482`): the bar of a task BLOCK whose root has
       no colour in the day's scene (no GPS, or a run that left no stretch of route). Not a TaskPalette
       colour and not the map's off-task grey (#8a8f98, the legend's „Izvan zadatka") — a block is never
       outside a task — so it lives here, not in the WD-PALETTE mirror. */
    --k-wd-block-free: #5B6482;

    /* shape & rhythm */
    --k-radius-sm: 4px;           /* inputs, popups, badges */
    --k-radius-md: 6px;           /* buttons, segmented controls */
    --k-radius-lg: 8px;           /* cards-in-grids, panels */
    --k-radius: 10px;             /* cards, menus, dialogs */
    --k-scrim: rgba(0, 0, 0, 0.6);
    /* K2c (O-K2-7, ARH-C 050521): dialog shadow = mock `.dlg` (45 lines); raised panel = mock web-01:29 (QR box). */
    --k-shadow-dialog: 0 30px 80px rgba(0, 0, 0, 0.7);
    --k-shadow-raised: 0 8px 24px rgba(0, 0, 0, 0.45);

    /* layout */
    --k-header-h: 64px;           /* canonical §10-mapped token (Cominus --navbar-h) */
    --k-page-max: 1580px;
    --k-page-gutter: 28px;
    /* Task 2 (W1) fix round 1: plan-named alias for the shell recipe — derives from the canonical
       --k-header-h above instead of duplicating its value, so editing --k-header-h isn't a no-op. */
    --k-navbar-h: var(--k-header-h);
    /* How much page chrome sits between the topbar and a KerberGrid — a page heading plus its
       padding, which is what /dev/grid happens to have. It is a TOKEN rather than a constant inside
       .k-grid__dx because every future screen inherits that rule: a page with different chrome
       overrides this on its own container instead of fighting a hard-coded number in the shared
       sheet (too small and the grid runs off the viewport, too large and it leaves a gap).
       #3144 B (O-B2): FROM NOW ON ONLY THE FALLBACK. A live grid measures its own top and takes the rest of the
       window (--k-grid-fit-h, kerber-shell.js registerGridFit); this token sizes a grid only where that does not
       run — the prerender before the circuit, a browser without JS, and a grid inside a popup. */
    --k-grid-chrome-h: 132px;

    /* type */
    --k-font-sans: 'Saira', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;
    /* K3-F F3 (#3291): Fluent's ONE public font hook (DevExpress 405705: --dxds-* are the public API, --dxbl-*
       internal). Fluent 25.2.9 core.min.css defines it on :root as "segoe ui" + a system stack and READS it in
       94 places (mjereno u Fluent 25.2.9: 94 čitača — every --dxbl-<component>-font-family: grid, text edit,
       buttons, popups, scheduler …). This sheet loads after core.min.css and both sit on :root, so ours wins
       and every DevExpress text gets Saira. Pinned by ThemeTests.F3_dxds_font_sans_u_root_je_k_font_sans and
       FluentDxblVarsReadTests.F3_Fluent_definira_u_root_i_cita_dxds_font_family_sans_serif; computed font in
       ThemeTokenSmokeTests.F3_dx_tekst_grida_i_unos_u_sairi. */
    --dxds-font-family-sans-serif: var(--k-font-sans);
    /* K3a′ D3 (vlasnik W-02 b, web-decisions.md:75 — „tijelo/unos 15/400"): the page's TEXT size, on
       body (rule below) and on the global input/button rules. NOT the root: see --k-root-font-size. */
    --k-font-size: 15px;
    /* K3a′ D3 (ii) (ARH-C 012603, REV-D 012613): the REM ANCHOR stays 14px on html. Every DevExpress
       size is written in rem (Fluent 25.2.9 core.min.css `.dxbl-grid{--dxbl-grid-font-size:0.875rem}`, as
       BlazingDark; cell paddings,
       editor heights) and so are our rem caps; a 15px root would grow them all by 15/14. W-02 gives the
       table its own sizes (header 12, row 14), set on the grid below, not through the root. */
    --k-root-font-size: 14px;
    --k-label-tracking: 0.5px;

    /* Task 9 (W1) — the keyboard focus ring, stated once (scen 11, 12). A token rather than a
       repeated declaration because it has to be identical on a nav link, a button, an input and a
       DevExpress editor: a ring that changes shape as focus moves is a ring the eye stops tracking.
       --k-accent on --k-bg/--k-surface is the same pair the design reference documents at ≥ WCAG AA
       (docs/design/cominus-design-reference.md §2), which is also what WCAG 2.2's 3:1 non-text
       contrast asks of a focus indicator. */
    --k-focus-ring: 2px solid var(--k-accent);
    --k-focus-ring-offset: 2px;
}

/* K3a′ D5 — SVIJETLI BLOK TOKENA (vlasnik W-03 (a), web-decisions.md:76: „tokeni sada, izvedba iza pilota").
   BEZ PREKIDAČA: nijedan izvor ne postavlja data-k-theme (ThemeTests.D5_nijedan_izvor_ne_postavlja_data_k_theme),
   pa ovaj blok danas ništa ne crta. Web pilot ostaje tamni (spec §10.9).
   SELEKTOR nije :root (TopBarLayoutCssTests i ThemeTests.D3RootToken traže JEDAN :root). [data-k-theme="light"] ima
   istu specifičnost (0,1,0) kao :root, pa na <html> pobjeđuje redoslijed — zato blok stoji ODMAH IZA :root.
   VRIJEDNOSTI doslovno iz mocka docs/design/mocks/web-00-stilska-knjiga.html `.web.light` (r.37–43); ime u mocku je
   u komentaru retka. Par ima svaki token BOJE iz :root osim šest koji u mocku nemaju svijetlu vrijednost — --k-white-rgb,
   --k-status-dot-off, --k-wd-block-free, --k-scrim, --k-shadow-dialog, --k-shadow-raised — nema u mocku, nasljeđuju
   tamnu dok dizajn ne da (ARH-C 040719; --k-shadow-raised K2c #3385, ARH-C 115641). Tokeni bez boje (mjere, radijusi, font) i tokeni koji upućuju na drugi token (--k-focus-ring,
   --k-navbar-h) para nemaju. */
[data-k-theme="light"] {
    /* surfaces & text */
    --k-bg: #F1F3FF;              /* --bg */
    --k-surface: #DADCE8;         /* --surface */
    --k-text: #121423;            /* --text */
    --k-text-muted: #5B6383;      /* --muted */
    --k-text-label: #48508B;      /* --label */
    --k-border: #C5C8D9;          /* --border */
    --k-border-strong: #B3B7CC;   /* --border-strong */

    /* accent (cyan) family */
    --k-accent: #0E6079;          /* --primary */
    --k-accent-hover: #0B4F64;    /* --primary-hover */
    --k-accent-soft: #00B4D8;     /* --primary-soft */
    /* --admin: mock .web.light ga ne mijenja (.web :30); mob-00 .t-light :27 izričito #48508B. */
    --k-accent-indigo: #48508B;
    --k-accent-rgb: 14, 96, 121;  /* --primary-rgb */
    --k-btn-text-on-accent: #FFFFFF; /* --on-primary */

    /* semantics */
    --k-success: #1E9E5A;         /* --success */
    --k-danger: #D9342F;          /* --danger */
    --k-danger-rgb: 217, 52, 47;  /* --danger-rgb */
    --k-success-rgb: 30, 158, 90; /* izvedeno: --success #1E9E5A kao trojka (mock nema --success-rgb) */
    --k-warning: #B8860B;         /* --warn (ispuna/rub; tekst upozorenja je #6B4E06, M-A′) */
    --k-warning-rgb: 184, 134, 11; /* izvedeno: --warn #B8860B kao trojka */

    /* task/assignment status */
    /* mock .web.light ih ne mijenja (.web :32): --st-pending, --st-progress, --st-draft. --st-progress ostaje #00B4D8
       uz primarnu #0E6079 — točno po mocku. */
    --k-status-pending: #6B7280;
    --k-status-in-progress: #00B4D8;
    --k-status-draft: #9CA3AF;
    --k-status-completed: #1E9E5A; /* --st-done */
    --k-status-cancelled: #D9342F; /* --st-cancel */
    --k-status-on-hold: #6B4E06;  /* --st-hold (M-A′: tekst na 15 % ispuni, AA) */
}

/* base — replaces the P0.4 inline style block */
html, body {
    margin: 0;
    font-family: var(--k-font-sans);
    font-size: var(--k-root-font-size);
    background: var(--k-bg);
    color: var(--k-text);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}
/* K3a′ D3 (W-02 b, ARH-C 012603 (ii)): html keeps the 14px rem anchor from the rule above; the page's text
   is 15px. Same specificity as `html, body`, so it must stay AFTER it — order decides. */
body {
    font-size: var(--k-font-size);
    line-height: 1.45; /* F6 N5: BD reboot davao je 1.5; Fluent uz ApplyToPageElements=false ne daje nijedan; mock 1.45 bez jedinice */
}

/* K3-F N8 (ARH-C 203255 (A)), #3291 — THE BOOTSTRAP REBOOT SUBSET BlazingDark used to give.
   Source: DevExpress.Blazor.Themes 25.2.9 staticwebassets/blazing-dark.bs5.min.css
   (md5 eeb825f835c90d8632144daaef92c8f3); every value below is that sheet's, VERBATIM.
   Why: under Fluent (UseBootstrapStyles=false, ApplyToPageElements=false) no Bootstrap reaches the page, so
   headings, paragraphs, lists and forms fell back to the UA margins (measured: /notifications h1 margin
   13.4/13.4 instead of 0/7, line-height 29 instead of 24).
   ONLY what Fluent does not give: Fluent core.min.css 25.2.9 (md5 81c5423fb482491e04814e73212c99df) has the global
   `dl,ol,ul{margin-top:0}`, so that one declaration is not repeated here.
   EXCLUDED by name: font-weight (h1–h6 500 — our h1 600 stays; dt 700, its only declaration, so no dt rule);
   font-size (h1 calc(1.34375rem + 1.125vw), h2 calc(1.3rem + .6vw), h3 calc(1.278125rem + .3375vw),
   h4 calc(1.25625rem + .075vw), h5 1.09375rem, h6 .875rem, the ≥1200px steps, legend calc(1.275rem + .3vw)/1.5rem
   — our own h1 rule sets 20px); color:var(--bs-heading-color) (BD [data-bs-theme=dark] = inherit — a heading's
   UA colour already inherits); the .h1–.h6 utility classes (0 in src); address and blockquote (0 in src).
   K3-F N10 (ARH-C 034314, 040420; TEST-WEB v8d 040329) adds FORM CONTROLS and CODE, chosen by a tool (BD reboot
   element selectors × tags in src *.razor/*.cshtml, table in the PR): BD's
   `button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}` (raw
   <input> under Fluent fell to the UA Arial; PRIJE Saira), `code,kbd,pre,samp{font-family:var(--bs-font-monospace);
   font-size:1em}` and `code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}` (setup/recovery codes
   15px UA monospace, 46 chars 379 px in a 350 px box; PRIJE 13.125px BD stack, 331.83 px). EXCLUDED by name:
   kbd (our .k-topbar__search-key/.k-omnibox__key keep font-family:inherit, mock web-30), so the selector is
   `code,pre,samp`; color:var(--bs-code-color) (our light code colour stays); BD's own pre{display;margin;overflow;
   font-size}, button{border-radius}, button,select{text-transform}, select{word-wrap}, button{-webkit-appearance},
   textarea{resize} rules (outside the N10 order). VAR → LITERAL: --bs-font-monospace does not exist under Fluent,
   so its BD value (`:root,[data-bs-theme=light]`, the sheet's only definition) is written out verbatim.
   ORDER: this block stays BEFORE every rule of ours on the same elements — same (0,0,1) specificity, so the
   later rule of ours wins by order and every class rule wins by specificity.
   Pin: BdRebootSubsetTests (each declaration EQUAL to the BD rule read from the package, not a literal; the
   monospace literal EQUAL to the BD variable's definition). */
h1, h2, h3, h4, h5, h6 { margin-top: 0; margin-bottom: .5rem; line-height: 1.2; }
p { margin-top: 0; margin-bottom: 1rem; }
ol, ul { padding-left: 2rem; }
dl, ol, ul { margin-bottom: 1rem; }
ol ol, ol ul, ul ol, ul ul { margin-bottom: 0; }
dd { margin-bottom: .5rem; margin-left: 0; }
figure { margin: 0 0 1rem; }
label { display: inline-block; }
fieldset { min-width: 0; padding: 0; margin: 0; border: 0; }
legend { float: left; width: 100%; padding: 0; margin-bottom: .5rem; line-height: inherit; }
legend + * { clear: left; }
code, pre, samp { font-family: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace; font-size: 1em; }
code { font-size: .875em; word-wrap: break-word; }
button, input, optgroup, select, textarea { margin: 0; font-family: inherit; font-size: inherit; line-height: inherit; }
/* K3-F N8 kraj (end of the BD reboot subset) */

/* Task 2 (W1): the real shell. <main class="k-page"> replaces the old bare `main` rule (which used
   to squeeze EVERY page, including /log's full-width table, into a 28rem box — see the comment this
   replaced). Deliberately no horizontal/vertical padding here: /log's own .log-page already carries
   a page-specific gutter (predates the shell), and anon pages center via .card below — adding gutter
   here too would double it. A future full-width page (KerberGrid) can add its own, same pattern. */
.k-page {
    min-height: calc(100dvh - var(--k-navbar-h));
    max-width: var(--k-page-max);
    margin: 0 auto;
    box-sizing: border-box;
}

/* DIZ-1 K3a′ G5: the wrapper around a DxToastProvider (KerberToastHost in the shell, the §12 Admin
   screens' own). Only a DOM anchor for browser tests (data-kerber-toast-host): no box of its own, so an
   Admin provider stays outside .k-admin's flex gap exactly as before. Pinned by KerberToastHostTests. */
.k-toast-host { display: contents; }

/* ── SHELL PRIMITIVES (DIZ-1 K1c) ─────────────────────────────────────────────────────────────────────
   One control, one rule, every screen. `.k-switch` (#3029) belongs here too; whichever of K1c / #3029 /
   #3053 merges later moves its rule into this section (REV-D 213631 U4).

   THE JOINED SEGMENT (vlasnik 76 a, BRAIN 2126): mock web-00:113-116 `.seg`, on theme tokens — measured
   mock --primary = --k-accent (#00B4D8), --on-primary = --k-btn-text-on-accent, --label = --k-text-label,
   --border-strong = --k-border-strong, --r-md = --k-radius-md. One clipping box, the items flush inside
   it and separated only by their right border: no gap, no margin, no radius of their own. A consumer
   class on the box carries PLACEMENT only (U1). Pinned by KerberSegmentCssTests. */
.k-seg {
    display: inline-flex;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    overflow: hidden;
}
.k-seg__item {
    display: inline-flex;
    align-items: center;
    padding: 0 14px;
    height: 34px;
    font: inherit;
    font-size: 12px;   /* 25 of 27 mocks (ARH-C 005949 t.2); web-00:114 draws 13px / .4px */
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-text-label);
    background: transparent;
    border: 0;
    border-right: 1px solid var(--k-border-strong);
    cursor: pointer;
}
.k-seg__item:last-child {
    border-right: 0;
}
.k-seg__item--on {
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
}
/* No hover (mock web-00:113-116 draws spans): the items are <button>s, and the global `button:hover` (0,1,1)
   would fill an idle item with --k-accent-hover so it reads as selected (Codex P2 #3270). These (0,2,0)
   rules give back the RESTING values; they touch no outline, so the keyboard ring below is unchanged. */
.k-seg__item:hover {
    background: transparent;
    border-color: var(--k-border-strong);
    color: var(--k-text-label);
}
.k-seg__item--on:hover {
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
}
/* D1 — an item's icon, mock web-05:101 `.seg span svg { width:15px; height:15px; margin-right:7px }`: one size
   and one gap for every segment (web-16:408 spaces with a non-breaking space instead — named, REV-D 001240
   V2). No colour of its own: the svg strokes currentColor, so the active item's on-accent text colours it. */
.k-seg__icon {
    display: inline-flex;
    margin-right: 7px;
}
.k-seg__icon svg {
    width: 15px;
    height: 15px;
}
/* The keyboard ring is an OUTLINE, never a shadow the colour of the fill (REV-D 171059 U1). It is drawn
   INSIDE the item: the box clips (overflow:hidden), so an outer ring would be cut off — the same inset the
   omnibox hit and the location tab use. On the active item an accent ring inside an accent fill would
   vanish, so there it takes the on-accent colour. */
.k-seg__item:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: -4px;
}
.k-seg__item--on:focus-visible {
    outline-color: var(--k-btn-text-on-accent);
}

/* THE PILL (DIZ-1 K2a, plan k2-g3-k4 v1 §2.1): mock web-10:177 `.pill`, 21 of 22 mocks, on tokens. One rule
   per variant; synonyms are a selector list of that one rule (§0). Outside it, named: the task status pills
   (TaskPalette, #3036), the live „u tijeku" pill (`k-attendance-pill--live`) and the chips. Pinned by
   KerberOznakeCssTests. */
.k-pill {
    display: inline-block;
    vertical-align: 1px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    padding: 2px 7px;
    border-radius: var(--k-radius-sm);
    border: 1px solid var(--k-border-strong);
    color: var(--k-text-label);
}
/* mock web-07:79 `.act .pill` (23). No margin-left: the space before the pill is the consumer's place in
   its row, so the consumer carries it. */
.k-pill--compact {
    font-size: 10px;
    padding: 2px 6px;
}
.k-pill--al, .k-pill--active {
    border-color: var(--k-danger);
    color: var(--k-danger);
    background: color-mix(in srgb, var(--k-danger) 12%, transparent);
}
.k-pill--man, .k-pill--old {
    border-color: var(--k-warning);
    color: var(--k-warning);
}
.k-pill--blk, .k-pill--rev {
    border-color: var(--k-danger);
    color: var(--k-danger);
}
.k-pill--main {
    border-color: var(--k-accent);
    color: var(--k-accent-soft);
}
.k-pill--off {
    border-style: dashed;
    color: var(--k-text-muted);
}
.k-pill--late {
    border-color: var(--k-success);
    color: var(--k-success);
}

/* THE STATUS DOT (DIZ-1 K2a, §2.2): mock web-05:114-117 `.st`, 25 of 25. Off is --k-status-dot-off with no
   glow; on and alarm glow at 60 % and 70 %. */
.k-status {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    white-space: nowrap;
}
.k-status i {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--k-status-dot-off);
}
.k-status--on i {
    background: var(--k-success);
    box-shadow: 0 0 6px color-mix(in srgb, var(--k-success) 60%, transparent);
}
.k-status--al i {
    background: var(--k-danger);
    box-shadow: 0 0 6px color-mix(in srgb, var(--k-danger) 70%, transparent);
}

/* KEY / VALUE, form A (DIZ-1 K2a, §2.3; ARH-C 014825): mock web-10:193-194 `.kv` on a `dl`. The key column
   is --k-kv-col (150px when unset); a CONSUMER sets it on its own element (web-05 130px, web-06 140px) —
   the shell does not know the screen (REV-D 051040 Z2). `--caps` (web-05:137, web-06:136) owns its gap; its
   `dt` takes the field label's typography (§2.5, G3: 12px / 600 / uppercase / tracking / --k-text-label)
   WITHOUT display: block and WITHOUT the label's margin — it is a grid cell, not a block above a box. The
   declarations sit in this one `.k-kv--caps dt` rule, not in the `.k-field-label` selector list: a list
   naming `.k-kv--caps dt` would be a second K2a rule for that element (KerberOznakeCssTests' one-rule pin).
   `.k-kv dt` and `.k-kv--caps dt` are both (0,1,1), so ORDER decides the colour: this rule stays after it. */
.k-kv {
    display: grid;
    grid-template-columns: var(--k-kv-col, 150px) 1fr;
    gap: 8px 14px;
    font-size: 14px;
    margin: 0 0 14px;
}
.k-kv dt {
    color: var(--k-text-muted);
}
.k-kv dd {
    margin: 0;
    color: var(--k-text);
    font-weight: 500;
}
.k-kv--caps {
    gap: 6px 12px;
}
.k-kv--caps dt {
    padding-top: 2px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-text-label);
}

/* THE BUTTON (DIZ-1 K2b, plan k2-g3-k4 v1 §2.4): mock web-16:35 `.btn` (the block of web mocks) on tokens.
   The font is THREE declarations with `font: inherit` FIRST (REV-D 051040 Z1): `inherit` inside the
   shorthand drops the whole declaration, and a shorthand after weight/size resets them. No line-height (the
   mock has none). `cursor: pointer` comes from web-00:103 only, the focus ring from the shell's rule, not a
   mock (Z4). Disabled lives in the base, on `:disabled` and `[aria-disabled="true"]` (no `.dis`).
   Hover (ARH-C 233659 (a)): one rule per modifier, each beside it, on an enabled button only (REV-D 002518
   N1): `:hover:not(:disabled):not([aria-disabled="true"])` at (0,4,0) beats the global `button:hover`
   (0,1,1), which fills background and border with `--k-accent-hover`. `--primary` has no hover of its own
   on purpose: the global accent-hover fill is its hover. `--outline` hovers like `--secondary` (mock
   web-00:106): hover does not change what the colour means. A disabled button under the mouse is its base
   (ARH-C 003457 (c)): the base rule of each of the four colour modifiers also lists `:disabled:hover` and
   `[aria-disabled="true"]:hover`, at (0,3,0) above the global `button:hover`, so a disabled `.k-btn--*`
   keeps its own colours. Still a gap, found on main: a disabled `<button>` with no `.k-btn--*` modifier (a
   bare `<button>`, or `.k-btn` alone) takes the global accent-hover fill; K2b does not change it.
   A `.k-btn` on an `<a>` gets none of the global `button` rules, so `--primary` there has no fill change on hover;
   the global `a:hover` would recolour its text, which the `a.k-btn--primary:hover` rule below prevents (Codex P2 #3307).
   `:active` is a gap: the plan prescribes none, so there is no rule. `--danger-outline` is #3097's (W-04, at
   the end of the sheet): its shape is this base's, and it has the same two forms as the colour modifiers here.
   `text-decoration: none` (W-42 (b) I1, ARH-C 130803, K-3 DIZ-1 T1): a `.k-btn` on an `<a>` would otherwise be
   underlined by the UA stylesheet and, until K3-F, BlazingDark's reboot `a{text-decoration:underline}`; the first
   such anchor is W-42's `data-kerber-location-tasks-new`.
   Pinned by KerberGumbCssTests. */
.k-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    height: 36px;
    padding: 0 18px;
    border-radius: var(--k-radius-md);
    border: 1px solid transparent;
    font: inherit;
    font-weight: 600;
    font-size: 13px;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    white-space: nowrap;
    cursor: pointer;
    text-decoration: none;
}
.k-btn svg {
    width: 16px;
    height: 16px;
}
.k-btn:disabled, .k-btn[aria-disabled="true"] {
    opacity: .4;
    cursor: not-allowed;
}
.k-btn:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-btn--primary,
.k-btn--primary:disabled:hover,
.k-btn--primary[aria-disabled="true"]:hover {
    background: var(--k-accent);
    border-color: var(--k-accent);
    color: var(--k-btn-text-on-accent);
}
/* Codex P2 #3307 (ARH-C 181837 (b)): on an <a> the global `a:hover` (0,1,1) beats `.k-btn--primary` (0,1,0) and
   would paint --k-accent-soft text on the --k-accent fill (~1.44:1). The link keeps its text colour; the fill
   is untouched, and a <button> still hovers through the theme's `button:hover` (233659 (a)). */
a.k-btn--primary:hover:not([aria-disabled="true"]) {
    color: var(--k-btn-text-on-accent);
}
.k-btn--secondary,
.k-btn--secondary:disabled:hover,
.k-btn--secondary[aria-disabled="true"]:hover {
    background: transparent;
    border-color: var(--k-border-strong);
    color: var(--k-text);
}
.k-btn--secondary:hover:not(:disabled):not([aria-disabled="true"]) {
    background: transparent;
    border-color: var(--k-accent);
    color: var(--k-accent);
}
.k-btn--outline,
.k-btn--outline:disabled:hover,
.k-btn--outline[aria-disabled="true"]:hover {
    background: transparent;
    border-color: var(--k-accent);
    color: var(--k-accent-soft);
}
.k-btn--outline:hover:not(:disabled):not([aria-disabled="true"]) {
    background: transparent;
    border-color: var(--k-accent);
    color: var(--k-accent);
}
/* O-K2-6 (b), ARH-C 050521: dark text on the danger fill, as on the primary — 6.26:1. The mock's #fff gives
   3.13:1, under AA for 13px text; named deviation. */
.k-btn--danger,
.k-btn--danger:disabled:hover,
.k-btn--danger[aria-disabled="true"]:hover {
    background: var(--k-danger);
    border-color: var(--k-danger);
    color: var(--k-btn-text-on-accent);
}
/* Never the accent: the danger hover keeps the danger fill. */
.k-btn--danger:hover:not(:disabled):not([aria-disabled="true"]) {
    background: var(--k-danger);
    border-color: var(--k-danger);
    color: var(--k-btn-text-on-accent);
}
.k-btn--sm {
    height: 28px;
    padding: 0 10px;
    font-size: 11px;
}

/* THE FIELD LABEL (DIZ-1 G3, plan k2-g3-k4 v1 §2.5): mock web-10:196 `.fld label` (21 web mocks) on
   tokens. ONE rule; `.k-wizard__label` (DIZ-5, an alias instead of touching its consumers, §3) and
   `.k-worker-editor__label` (DIZ-2 20b, ARH-C 113745) are its selector list, never a second rule. Tracking
   is --k-label-tracking (0.5px; web-00 and web-01 draw .06em) and the margin is 6px (web-04 draws 4px) —
   the plan's ruling. `.k-kv--caps dt` takes the same typography in its own K2a rule (see KEY / VALUE). */
.k-field-label, .k-wizard__label, .k-worker-editor__label {
    display: block;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-text-label);
    margin-bottom: 6px;
}
/* mock `.fld label em` (21 web mocks): the required-field mark. */
.k-field-label em, .k-wizard__label em, .k-worker-editor__label em {
    color: var(--k-danger);
    font-style: normal;
    margin-left: 3px;
}
/* Layout, not typography: mock `.fld` is a block with label margin 6px; here the field is a flex column with
   its own gap (wizard 6, worker editor 4), so the label margin closes to 0 / 2px — 6px between label and box
   (TEST-WEB 122030: 12 / 10 before). The worker-editor 6px is pinned in E2E
   (CompanyWorkerEditSmokeTests.G3_razmak_natpisa_do_polja_je_6px_uz_kontrolu_para); the wizard's is not.
   Specificity (0,2,0) beats the label list (0,1,0). */
.k-wizard__field > .k-wizard__label { margin-bottom: 0; }
.k-worker-editor__field > .k-worker-editor__label { margin-bottom: 2px; }
/* mock `.fld { margin-bottom: 12px }` — the value in force in 14 web mocks (web-14…web-28 restate the 14px
   rule with 12px later in the sheet; web-01 and web-10…web-13 keep 14px). */
.k-field {
    margin-bottom: 12px;
}
/* DxFormLayout captions: none today (0 consumers); the first DxFormLayout carries
   `CaptionCssClass="k-field-label"` (ARH-C 110452 G2 (a)). */

.card {
    background: var(--k-surface);
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius);
    padding: 20px;
    text-align: center;
    /* Centering that used to live on the bare `main` rule (pre-W1) — moved here so login/setup/
       admin-login keep their pre-shell look now that <main> is the full-width .k-page. */
    max-width: 28rem;
    margin: 4rem auto;
}

/* K3a′ D3: page title 20px — vlasnik W-02 b „naslov stranice 20/600" (was 18px). */
h1 {
    font-size: 20px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-accent);
}

a {
    color: var(--k-accent);
}
a:hover {
    color: var(--k-accent-soft);
}

/* TEXT-ENTRY INPUTS ONLY — checkbox and radio are EXCLUDED, and the exclusion is a fix rather than
   tidiness (issue #149, found on the 24.8.2026 gate day). This sheet is deliberately registered AFTER
   DevExpress's theme so Kerber's tokens win where they overlap (see App.razor), which meant a bare
   `input` selector also won over DevExpress's own checkbox rules — on all 51 DxCheckBox instances in
   the app at once. A checkbox is not a text box, and the three declarations below broke it in three
   separate ways: `min-height: 36px` + `padding` inflated the box to roughly two text rows (what the
   owner saw), `background` painted over the check mark so the checked state was invisible even when
   the stored value was true, and the inflated input covered the wrapper DevExpress binds its click
   handling to — so clicks landed on nothing and no checkbox in the web app could be toggled at all.
   Range and file inputs DO still match this selector (Copilot review of #151): neither is used on
   any Kerber screen today, so the first screen to add one decides then whether it belongs in the
   exclusion list — an unused element is not worth a selector arm nobody exercises. */
input:not([type="checkbox"]):not([type="radio"]) {
    font-size: var(--k-font-size);
    padding: 6px 12px;
    min-height: 36px;
    box-sizing: border-box;
    border-radius: var(--k-radius-sm);
    border: 1px solid var(--k-border-strong);
    background: var(--k-surface);
    color: var(--k-text);
}
input::placeholder {
    color: var(--k-text-muted);
    opacity: 0.7;
}
input:hover {
    border-color: var(--k-text-muted);
}
input:focus {
    border-color: var(--k-accent);
    outline: none;
}

button {
    font-family: var(--k-font-sans);
    font-size: var(--k-font-size);
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    padding: 8px 20px;
    border-radius: var(--k-radius-md);
    border: 1px solid var(--k-accent);
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    cursor: pointer;
    transition: background 0.2s ease, border-color 0.2s ease;
}
button:hover {
    background: var(--k-accent-hover);
    border-color: var(--k-accent-hover);
}
button:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* K3a′ G1, SCOPE B — THE K2 SHAPE ON ACTION BUTTONS ONLY (owner W-04 "dialog and form buttons", W-10/W-11; ARH-C 025931
   scope B, REV-D 025922 technique). The K2 primitive's shape (.k-btn: 36 px, 13/600, caps, --k-label-tracking), no
   colours, reaches exactly two kinds of button, each through its own rule:
     1. a STANDALONE DxButton with text, Medium size. DevExpress declares a button's size as variables ON THE BUTTON
        itself (blazing-dark 25.2.9: `.dxbl-btn` declares --dxbl-btn-font-size 0.875rem, --dxbl-btn-padding-x 0.75rem
        and --dxbl-btn-padding-y 0.25003125rem, and SizeMode Small/Large redeclares them on `.dxbl-btn-standalone.dxbl-sm`
        / `.dxbl-lg`), so the shape goes through those variables at (0,5,0); only what has no variable — height, case,
        tracking, weight — is set directly. Small, Large and icon-only buttons keep DevExpress's sizes.
     2. a bare <button> with NO class (the setup, recovery and admin sign-in forms): (0,1,1).
   OUT OF SCOPE BY CONSTRUCTION, not by exception names: the top bar's search and logout buttons and the grid's
   link-buttons (.k-grid__link--button and its kin) carry a class and are not DxButtons; the buttons inside editors,
   pagers and toolbars are DxButton parts DevExpress does not mark `dxbl-btn-standalone`, so they stay on DevExpress's
   variables. A <button> with a class that wants the K2 shape uses .k-btn (K2b) — and neither rule below is in that
   list (U1). The global `button` rule above keeps its colours, font and padding and gets NO height or case, so
   nothing with a class changes size (pin: KerberGumbCssTests G1_globalni_button_i_dxbl_btn_bez_visine_i_verzala).
   RISK: `dxbl-btn-standalone` is DevExpress's internal class; K3-F (Fluent) re-measures G1, and the computed-style
   smoke (CompanySmokeTests G1_gumb_radnje_je_K2_a_tipka_editora_i_link_grida_nisu) catches a renamed class.
   Pins: KerberGumbCssTests G1_DX_gumb_radnje_K2_kroz_varijable, G1_goli_gumb_bez_klase_ima_oblik_K2. */
.dxbl-btn.dxbl-btn-standalone:not(.dxbl-sm):not(.dxbl-lg):not(.dxbl-btn-icon-only) {
    --dxbl-btn-font-size: 13px;
    --dxbl-btn-padding-x: 18px;
    --dxbl-btn-padding-y: 0;
    height: 36px;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-weight: 600;
}
button:not([class]) {
    height: 36px;
    padding: 0 18px;
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}

/* K3-F N9 (b) (ARH-C 204603, REV-D 204508, #3291) — TEXT ON A PRIMARY DX BUTTON IS --k-btn-text-on-accent (#0A0B14),
   the dark text K2's .k-btn--primary already draws on the accent (mock --on-primary). Fluent 25.2.9 core.min.css
   (md5 81c5423fb482491e04814e73212c99df) declares `.dxbl-btn{…--dxbl-btn-primary-color:var(--dxds-color-content-neutral-
   default-static-dark-rest)…}` — white, 2.46:1 on #00B4D8, a regression — and reads it in
   `.dxbl-btn.dxbl-btn-primary{…--dxbl-btn-color:var(--dxbl-btn-primary-color)…}`; hover and active follow, since
   `.dxbl-btn` defaults `--dxbl-btn-hover-color` and `--dxbl-btn-active-color` to `var(--dxbl-btn-color)`. Declared here on
   the SAME element at the same (0,1,0): this sheet is registered after DevExpress's, so it wins by order. A DevExpress
   class, theme-wide ON PURPOSE: every primary DxButton (82 DxButtons in src, all with a RenderStyle: 3 explicit Primary,
   21 Primary/Secondary by state — the period selectors, the wizard's step strip, two filter toggles) and DevExpress's own
   primary buttons. NOT covered, measured 0 in src: DxDropDownButton / DxSplitButton / DxButtonGroup (their
   `--dxbl-btn-{dropdown,split,group}-contained-primary-active-color` are white too); Outline/Text primary read
   `--dxbl-btn-outline-color` / `--dxbl-btn-text-color`, not this variable (RenderStyleMode: 0 in src).
   Pin: FluentDxblVarsReadTests.N9b_tekst_primarnog_DX_gumba_je_k_btn_text_on_accent;
   E2E: ThemeTokenSmokeTests.N9b_aktivni_gumb_razdoblja_tamni_tekst_i_kontrast_4_5. */
.dxbl-btn { --dxbl-btn-primary-color: var(--k-btn-text-on-accent); }

/* keyboard focus — NEW in 2.0 (Cominus has none; spec decision 6).
   Task 9 (W1) a11y pass: this used to be `outline: none` plus a 0.3-alpha box-shadow. Both halves
   were wrong for the shell the W-packages are building on top of it:
     - a box-shadow is PAINT, so it is clipped by any scroll container or overflow:hidden ancestor
       (the topbar and the grid are both), and it disappears entirely in forced-colors/high-contrast
       mode — an outline is laid out outside the box and survives both;
     - 0.3 alpha put the indicator well under the 3:1 WCAG 2.2 asks of it.
   ONE rule rather than four (nav links, search box, export buttons, logout): :focus-visible already
   means "every element the keyboard can land on", so enumerating them could only leave one out. The
   two rules below exist because something else in this sheet or in DevExpress's would win otherwise —
   not to add a different ring. */
:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* `input:focus` above zeroes the outline and is MORE specific (0,1,1) than the bare :focus-visible
   rule (0,1,0), so without this an input keyboard-focus drew no ring at all. */
input:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* DEVEXPRESS CHECKBOX / RADIO / SWITCH IN KERBER'S ACCENT, THEME-WIDE (ARH-C 170718; REV-D 171059
   stamp, conditions U1-U5; DIZ-5; ported to Fluent in K3-F F2, #3291). The theme is Fluent Dark
   (App.razor); its checkbox colours are a STATE MACHINE of variables: one value per state on the root
   (`.dxbl-checkbox { --dxbl-checkbox-primary-checked-check-element-bg … }`, 0,1,0), which state rules
   copy into the drawing variables (`.dxbl-checkbox…-checked { --dxbl-checkbox-check-element-bg:
   var(--dxbl-checkbox-primary-checked-check-element-bg) }`). Overriding the per-state value therefore
   reaches the checkbox fill, the switch track (same variable) and the radio (ring AND dot both read
   `…-check-element-border`). Measured in devexpress.blazor.themes.fluent/25.2.9 core.min.css; the
   BlazingDark names this block used before F2 (`--dxbl-checkbox-check-element-checked-bg`,
   `--dxbl-checkbox-switch-checked-bg`, `--dxbl-checkbox-radio-*`, …) are read by no Fluent rule
   (FluentDxblVarsReadTests). The variables are not documented (DevExpress docs MCP) — "not a
   contract"; re-measure them on a theme upgrade.
   A DEVEXPRESS CLASS SELECTOR, NAMED AS A DEPARTURE from "variables, never a DevExpress class name"
   (W4 Task 10 below): DevExpress sets these variables ON THE ELEMENT ITSELF, so neither :root nor an
   inherited value can reach them, and no class of ours sits on every consumer.
   DEPENDS ON STYLESHEET ORDER (U5): this rule and DevExpress's have the SAME specificity (0,1,0), so
   Kerber wins only because App.razor registers the DevExpress theme BEFORE this sheet — move the link
   and every checkbox turns Fluent's own accent ramp again while the CSS-reading pins stay green;
   ThemeTests pins the order too. Validation states (`.valid.modified` / `.invalid`) and the
   disabled/readonly fills stay DevExpress's on purpose.
   The BORDER of a checked box and of the ON track takes the accent too: Fluent draws it in its own
   `--dxds-color-border-primary-compound-rest`, which would ring our fill in a second shade (BlazingDark
   had no checked border). */
.dxbl-checkbox {
    --dxbl-checkbox-primary-checked-check-element-bg: var(--k-accent);
    --dxbl-checkbox-primary-checked-check-element-border: var(--k-accent);
    --dxbl-checkbox-primary-checked-hover-check-element-bg: var(--k-accent-hover);
    --dxbl-checkbox-primary-checked-hover-check-element-border: var(--k-accent-hover);
}
/* Content ON the accent (Codex k0 [P2], #3053): BlazingDark's white check mark on #00B4D8 was 2.46:1;
   mock web-04 M:70 draws it in --on-primary = our --k-btn-text-on-accent (~8:1). Fluent declares the
   glyph colour on `.dxbl-checkbox:not(.dxbl-checkbox-switch):not(.dxbl-checkbox-radio)` (0,3,0) — a
   plain checkbox only, as before — so the override uses the same selector, later in the cascade. */
/* K3-F N11a (ARH-C 051721, #3291) — THE BOX 18 x 18 AND ITS CHECK MARK 12 px, per mock web-04:70
   `.chk i { width: 18px; height: 18px; … font-size: 12px }` and web-00:133 (18 x 18). Every DxCheckBox except
   switch and radio (21 of the 24 `<DxCheckBox` tags in src; 3 are switches, 0 radios, none sets a SizeMode).
   Measured v10 (TEST-WEB): under Fluent the box was 14 x 14 and the glyph 10.5 px (BlazingDark: 17.5 / 12.25).
   Fluent 25.2.9 core.min.css (md5 81c5423fb482491e04814e73212c99df) DECLARES both sizes on THIS selector (0,3,0):
   `--dxbl-checkbox-check-element-checkbox-size-m: var(--dxds-spacing-160)` (1rem) and
   `--dxbl-checkbox-check-element-icon-size-m: var(--dxds-spacing-120)` (0.75rem), and CONSUMES them on it too:
   `--dxbl-checkbox-check-element-width/-height: var(…-checkbox-size-m)` and
   `--dxbl-checkbox-check-element-icon-size: var(…-icon-size-m)`, drawn by
   `.dxbl-checkbox .dxbl-checkbox-check-element { width/height: var(--dxbl-checkbox-check-element-width/-height) }`
   and `….dxbl-checkbox-check-element>.dxbl-image { width/height: var(--dxbl-checkbox-check-element-icon-size) }`.
   So the hook is the medium (-m) value, on the same selector, later in the cascade (this sheet loads after
   Fluent's; ThemeTests pins the order). `.dxbl-sm` / `.dxbl-lg` read the -s / -l values and are NOT covered
   (0 in src). INTERNAL DX VARIABLES, NOT A CONTRACT (docs.devexpress.com/Blazor/405705, 25.2: `--dxbl-*` "may
   change between versions"); the pin reads the package, so a DX upgrade fails it instead of silently shrinking
   the box. The border and fill stay Fluent's (F-v1): the mock's 1.5 px border is not carried over.
   The two size lines sit in the glyph colour's rule: ONE rule per selector (ThemeTests reads exactly one).
   Pin: FluentDxblVarsReadTests.N11a_DxCheckBox_18px_i_kvacica_12px_kroz_Fluentove_m_varijable;
   E2E: ThemeTokenSmokeTests.N11a_kucica_carobnjaka_18x18_kvacica_12. */
.dxbl-checkbox:not(.dxbl-checkbox-switch):not(.dxbl-checkbox-radio) {
    --dxbl-checkbox-check-element-check-icon-primary-color: var(--k-btn-text-on-accent);
    --dxbl-checkbox-check-element-checkbox-size-m: 18px;
    --dxbl-checkbox-check-element-icon-size-m: 12px;
}
/* FOCUS (U1): the ring is the house outline from the token, with an offset that separates it from the
   fill (the recipe REV-D asked of `.k-switch` in #3029). BlazingDark drew focus as a box-shadow in the
   fill's colour (its two `…-focus-shadow-color` variables were set transparent here until F2); Fluent
   draws no focus shadow at all but an OUTLINE on this same element, from
   `.dxbl-checkbox .dxbl-checkbox-check-element:has(input[type=checkbox]:focus-visible,input[type=radio]:focus-visible)`
   (0,4,1). The selector below repeats that :has() list, so it has the same specificity and wins by
   order (U5) — with the shorter `:has(input:focus-visible)` (0,3,1) Fluent's 1.75 px ring replaced ours.
   Inside a FOCUSED DX GRID ROW DevExpress's own, more specific rule still wins — no grid selection
   column uses it today. */
.dxbl-checkbox .dxbl-checkbox-check-element:has(input[type="checkbox"]:focus-visible, input[type="radio"]:focus-visible) {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
/* THE SWITCH'S LABEL per the mock's .tog (web-14/15 M:265-266; ARH-C 184525, REV-D 184455): 14 px in
   --text, 10 px from the track. DevExpress draws the label itself (DxCheckBox child content; 25.2 has
   no label CSS class — MCP: CssClass, LabelPosition and LabelWrapMode only) at
   --dxbl-checkbox-font-size 0.875rem (12.25 px on our 14 px root) with --dxbl-checkbox-spacing 0.5rem
   of padding, and sets no colour, so the label took its PARENT's (218,220,232 on GeneralTab, white in
   a DxPopup). INTERNAL DX VARIABLES, NOT A CONTRACT (measured in blazing-dark.bs5.min.css 25.2.9;
   Fluent 25.2.9 core.min.css reads the same two names, K3-F F2). Two classes (0,2,0) outrank
   DevExpress's `.dxbl-checkbox` (0,1,0) that declares them, whatever the sheet order; the colour sits on
   the switch root, so the label takes it instead of the dialog's.
   Switches only: the mock draws no other DX checkbox label. The UNCHECKED track stays DevExpress's —
   under Fluent 25.2.9 transparent with a neutral border (`--dxbl-checkbox-primary-unchecked-check-element-*`)
   and a subdued thumb; the mocks have no unchecked state (named, ARH-C 184525).
   THE ON THUMB is DARK per mock web-04 (--on-primary); web-14/15 :266 draws it #fff, and we depart from
   it for contrast (ARH-C 190105). Fluent declares the thumb colour per state on THIS selector (0,2,0):
   `--dxbl-checkbox-primary-checked-check-element-trigger-bg` and its hover twin (BlazingDark's
   `--dxbl-checkbox-switch-element-bg`, set on `.dxbl-checkbox` until F2, is read by no Fluent rule); the
   unchecked, disabled and readonly thumbs keep their own Fluent variables.
   K3a′ N2: the size is an explicit 14px (mock `.tog` web-14:265), no longer var(--k-font-size) — under D3
   that is the 15px body. */
.dxbl-checkbox.dxbl-checkbox-switch {
    --dxbl-checkbox-font-size: 14px;
    --dxbl-checkbox-spacing: 10px;
    color: var(--k-text);
    --dxbl-checkbox-primary-checked-check-element-trigger-bg: var(--k-btn-text-on-accent);
    --dxbl-checkbox-primary-checked-hover-check-element-trigger-bg: var(--k-btn-text-on-accent);
}

/* BARE checkboxes and radios (REV-D 171059 U4) — e.g. QrGenerationPage's `k-company-qr__check`, which
   otherwise shows the browser's default colour. Colour only, no box model (see issue #149 above);
   the same recipe as `.k-wd__scrub`. */
input[type="checkbox"], input[type="radio"] {
    accent-color: var(--k-accent);
}

.error {
    color: var(--k-danger);
}

code.recovery {
    display: block;
    margin: 0.2rem 0;
    /* K3-F N10 (ARH-C 040420, #3291): ONE LINE per code. /setup/reveal and /login/admin/recovered print each recovery
       code (46 chars) in its own block; at the BD size (N10 block: 13.125px stack) it measures 331.83 px in the 350 px
       card, and nothing may break it across lines. Pin: BdRebootSubsetTests N10_code_recovery_jedan_redak. */
    white-space: nowrap;
    /* K3-F F5 (iv) (ARH-C 073853, #3553 e2e): the fallback mono font on Linux (0.6 em advance, no Consolas) overflows
       46 chars into the 350 px card (scrollWidth 362 on CI); 3 % tighter is 46 x 0.57 em x 13.125 = 344.1 px
       (computed). Windows Consolas: 313.8 px (computed). */
    letter-spacing: -0.03em;
    /* K3-F P2 (Codex P2 #3553, ARH-C 094855 (b), #3291): at <= 386 px (344.1 px code + 42 px card padding/border) the
       one-line code is wider than the card; it scrolls inside its own box instead of widening the page (360 px: code
       344 > 318, page 365 > 360, run 37744912941). nowrap stays (ARH-C 040420). Pin: ThemeTokenSmokeTests N10c. */
    overflow-x: auto;
}

/* Task 3 (W1) fix round 1: Task 2's original rule here showed this element as a warning-colored
   banner for the components-reconnect-show/-failed/-rejected classes — a leftover placeholder
   interpretation of §10.5 from before ConnectionIndicator existed. The brief is explicit now that
   this element is visually hidden UNCONDITIONALLY (scen 27: "no blocking overlay" — the indicator,
   mounted in TopBar, is the only visible connection UI) and stays in the DOM purely as the MECHANISM
   kerber-shell.js observes: its components-reconnect-* classes still drive Blazor's own give-up
   detection, they just never paint anything. */
#components-reconnect-modal.k-reconnect { display: none; }

/* Task 2 (W1) — app shell topbar. Recipe ported from docs/design/cominus-design-reference.md §5
   (.topbar / .topbar__inner / .nav__link), re-expressed in --k-* tokens: --surface → --k-surface,
   --accent (nav hover/active) → --k-accent-soft per the §10 token mapping table. */
.k-topbar {
    position: sticky;
    top: 0;
    z-index: 1000;
    height: var(--k-navbar-h);
    background: var(--k-surface);
    border-bottom: 1px solid rgba(var(--k-white-rgb), 0.03);
    backdrop-filter: saturate(115%) blur(4px);
}
.k-topbar__inner {
    height: 100%;
    max-width: var(--k-page-max);
    margin: 0 auto;
    padding-inline: var(--k-page-gutter);
    box-sizing: border-box;
    display: grid;
    /* DIZ-1 K1 (k0 #2931 P2, CI run 36881987742): the BRAND column may shrink below its content, so a
       200-character tenant name is cut with an ellipsis instead of pushing the menu out — but never
       below 6rem (TEST-WEB 222426: at minmax(0, 1fr) the Development menu, four DEMO entries longer,
       took it to 0 px and the logo lay over „NADZORNA PLOČA"). 6rem is the old brand's width („K"
       square + „KERBER", 99 px measured at 1440 on ded12f92e), so the topbar fits no worse than on
       main, and the logo plus the start of the name always stand side by side. The ACCOUNT column
       never shrinks — minmax(max-content, 1fr) — so search, connection, user and „Odjava" can never
       slide under the menu (SearchSmokeTests' fit pin). With room to spare both sides are 1fr and the
       menu stays centred (web-00 :75 `1fr auto 1fr`). Pinned: TopBarLayoutCssTests (the rule) and
       ShellSmokeTests.Logo_and_tenant_name_stand_clear_of_the_menu (the browser). */
    grid-template-columns: minmax(6rem, 1fr) auto minmax(max-content, 1fr);
    align-items: center;
    gap: 16px;
}
.k-topbar__brand { display: flex; align-items: center; gap: 10px; min-width: 0; }
/* DIZ-1 K1 (web-00 :76-78): the brand mark is an image — the tenant's uploaded logo or Kerber's PNG —
   32×32, never the old cyan "K" square. object-fit keeps a non-square tenant logo inside the box. */
.k-topbar__logo {
    display: block;
    width: 32px;
    height: 32px;
    object-fit: contain;
    flex: none;
}
.k-topbar__client {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    text-transform: uppercase;
    font-size: 16px;
    font-weight: 700;
    color: var(--k-accent);
    letter-spacing: var(--k-label-tracking);
    text-shadow: 0 0 20px rgba(var(--k-accent-rgb), 0.3);
}
/* The super admin's brand is Kerber's own short name, and at 1180 px its menu holds the brand column at the
   6rem floor, narrower than the logo, the gap and „KERBER": the name was cut to „KER…". There it does not
   shrink, so it is whole; it reaches into the column gap, the grid's columns (and so the menu) are unchanged.
   Only the super admin's bar, the one that carries the admin entries: a tenant's name may run to 200
   characters and is still cut with an ellipsis by the rule above. */
.k-topbar__inner:has(.k-topbar__link--admin) .k-topbar__client { flex-shrink: 0; }
.k-topbar__nav { display: flex; align-items: center; justify-content: center; gap: 4px; }
/* K3a′ D3 (ARH-C 013301): the menu link keeps its OWN 14px instead of var(--k-font-size), which is now the 15px
   body. W-02 b names no size for the topbar navigation, and the 1180 px topbar pin holds it on one line: measured
   by the DIZ-1 probe (run 37389856637), the super admin's bar has 12 px of brand slack at 1180 and breaks onto two
   lines with 15px links. */
.k-topbar__link {
    position: relative;
    padding: 6px 10px;
    color: var(--k-text-muted);
    text-decoration: none;
    text-transform: uppercase;
    font-weight: 700;
    letter-spacing: var(--k-label-tracking);
    font-size: 14px;
    transition: color 0.14s ease;
}
.k-topbar__link::after {
    content: '';
    position: absolute;
    left: 10px; right: 10px; bottom: -4px;
    height: 2px;
    background: var(--k-accent-soft);
    transform: scaleX(0);
    transition: transform 0.14s ease;
}
/* DIZ-1 K1, A10 (web-00 :84 `.nav a.admin`): the super-admin-only entry („Admin log") in indigo.
   One class, so `.active` (two classes) still lights it when the operator is on that page. */
.k-topbar__link--admin { color: var(--k-accent-indigo); }
.k-topbar__link:hover { color: var(--k-accent-soft); }
.k-topbar__link.active { color: var(--k-accent-soft); }
.k-topbar__link.active::after { transform: scaleX(1); }
.k-topbar__account { display: flex; align-items: center; justify-content: flex-end; gap: 12px; }
/* #3344 (vlasnik 218 DA, plan v2 §1): the account name is at most 160 px, one line, cut with an
   ellipsis — a tenant admin's „Ime Prezime" runs to 201 characters, a super admin's Username to 100,
   and uncapped a long one could push the menu onto a second row. The full name is in the tooltip below. */
.k-topbar__username {
    color: var(--k-text-muted);
    text-transform: uppercase;
    font-weight: 700;
    letter-spacing: var(--k-label-tracking);
    font-size: 13px;
    max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* #3344: the wrapper is the tab stop (tabindex="0" in TopBar.razor) and the tooltip's anchor; its ring
   is the general :focus-visible rule above. min-width: 0 lets the name shrink to its 160 px cap. */
.k-topbar__user { position: relative; display: inline-flex; align-items: center; min-width: 0; }
/* #3344: the full name, under the account name and right-aligned with it, on hover and on keyboard focus (pure CSS, so it
   also shows for a short name, with the same text; no Esc — WCAG 1.4.13, Refs #3445). Sized to its
   text (max-content — absolutely positioned it would otherwise shrink to the 160 px wrapper), at most
   320 px — the named literal `max-width: 320px` of .k-task-media, there being no width token — and a
   longer name breaks onto more lines, anywhere, since a Username may carry no space at all. */
.k-topbar__username-full {
    display: none; position: absolute; top: calc(100% + 8px); right: 0; z-index: 1001;
    padding: 6px 10px; background: var(--k-surface); border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm); box-shadow: var(--k-shadow-raised); color: var(--k-text);
    font-size: 13px; font-weight: 400; letter-spacing: 0; text-transform: none;
    width: max-content; max-width: 320px; white-space: normal; overflow-wrap: anywhere;
}
.k-topbar__user:hover .k-topbar__username-full,
.k-topbar__user:focus-visible .k-topbar__username-full { display: block; }
.k-topbar__logout-form { margin: 0; }
.k-topbar__logout {
    background: transparent;
    border: 1px solid var(--k-border-strong);
    color: var(--k-text);
    padding: 6px 14px;
    font-size: 12px;
}
.k-topbar__logout:hover {
    background: transparent;
    border-color: var(--k-danger);
    color: var(--k-danger);
}

/* Task 3 (W1) — connection indicator (§10.5, ruling G17). 10px dot + label, mounted right of the
   topbar nav (TopBar.razor → ConnectionIndicator.razor). Colors are the existing --k-success/
   --k-warning/--k-danger semantic tokens above (defined for Task 1) — no new tokens needed, and per
   the "no raw hex" rule every color here goes through one of them. */
.k-conn { display: flex; align-items: center; gap: 8px; }
.k-conn__dot { width: 10px; height: 10px; border-radius: 50%; background: var(--k-text-muted); }
.k-conn__label {
    text-transform: uppercase;
    font-weight: 700;
    letter-spacing: var(--k-label-tracking);
    font-size: 12px;
    color: var(--k-text-muted);
}
/* W-07 odbrojavanje na kartici prijave (scen 38-40). Upozorenje ispod 30 s ide na
   --k-warning: ista boja koju W-05 daje stanju „paznja", pa se prag vidi u boji, a ne samo
   u imenu klase. Pin mjeri IZRACUNATU boju, jer klasa bez pravila ne mijenja nista na
   ekranu (nalaz Codexa k0, 12.9.). */
/* Logo je gumb radi tipkovnice, ali bez izgleda gumba: `all: unset` mu skida okvir i pozadinu, pa
   nasljeduje od `.card` (ne od `h1` — mock web-01 kadar A, DIZ-5: gumb vise nije u naslovu). Izgled
   mu daju `.k-login__logoimg` (slika, vec `display:block`) i `.k-login__brand` (rijec Kerber ispod);
   sam gumb je blok centriran u kartici. Fokusni prsten NAMJERNO ostaje (`:focus-visible` iz teme)
   - to je jedini znak koji tipkovnicki korisnik ima. */
.k-login__logo { all: unset; cursor: pointer; display: block; margin: 0 auto; }
/* Mock web-01 kadar D (W-07): indigo crta na vrhu kartice = isti znak admin dijela kao M-10a na
   telefonu. Negativne margine IZVEDENE su iz stvarnog `.card` paddinga (20px), ne prepisane iz
   mocka (32/36px) — inace crta lebdi iznad kartice, viri sa strane i na uskom zaslonu daje
   vodoravno prelijevanje (k0 P2, 19.9.). */
.k-login__adminline { height: 3px; background: var(--k-accent-indigo); margin: -20px -20px 22px; border-radius: var(--k-radius) var(--k-radius) 0 0; }
/* Rijec KERBER kao znak: na `/login` je gumb (W-07b pet klikova), ovdje je goli naslov jer nema
   sto otkrivati — pet klikova vodi upravo na ovu stranicu. */
/* #2184 (kadar D `.wm`, REV P4-1 na #2274): rijec Kerber je ZNAK, ne naslov — s `h1` je presla na
   `div`, pa bez ovog pravila pada na 16 px / 400. Velicina, tezina i razmak iz mocka; boja = naglasak
   (7,38:1 na povrsini kartice). Mockov `text-shadow` se ne prenosi: ukras bez tokena. */
.k-login__brand { margin-bottom: .25rem; font-size: 22px; font-weight: 700; letter-spacing: .12em;
    text-transform: uppercase; color: var(--k-accent); }
/* #2184 (kadar D `img.logo`): vlasnikov PNG 56 px iznad rijeci Kerber; blok da stoji u svom retku, a
   velicina iz atributa da kartica ne skace dok se slika ucitava. */
.k-login__logoimg { display: block; margin: 0 auto 10px; }
/* Naslov prijave: `var(--k-text)`, NE mockov indigo — indigo #48508B na povrsini kartice daje 2,42:1,
   ispod 4,5:1 (f77150789, Codex r4053343417 na #1744; REV P2-1 na #2274). Indigo ostaje samo na crti.
   Kontrast mjeri e2e nad IZRACUNATIM bojama (`AdminLoginLayoutSmokeTests`), ne grep nad ovim retkom. */
.k-login__adminheading { color: var(--k-text); }
/* Mock web-01 kadar A (DIZ-5): naslov kartice „Prijava na web" — globalni h1 (r. 147) daje 18 px /
   600 / verzal; mock ga crta u boji TEKSTA, ne naglaska, i s razmakom od riječi Kerber iznad. */
.k-login__heading { margin: 18px 0 6px; color: var(--k-text); }
/* Mock web-01 kadar A (`.card p`, `.timer`): poziv i redak valjanosti su u prigušenoj boji OZNAKE
   (`--label` = `--k-text-label`), ne u bijeloj; redak valjanosti 14 px i odmaknut 12 px od panela.
   Samo klase kartice `/login` — `.card p` bi promijenio i kadar D (`/login/admin`). */
.k-login__prompt { color: var(--k-text-label); }
.k-login__validity { color: var(--k-text-label); margin-top: 12px; font-size: 14px; }
/* Bijeli panel oko QR-a (mock `.qrbox`): skener lakše čita kod na svijetloj podlozi nego na tamnoj
   kartici. CENTRIRA GA `align-self: center`, ne `text-align`: DX tema (Bootstrap `.card`) daje
   kartici `display: flex; flex-direction: column`, pa bi se panel kao flex-stavka rastegnuo preko
   cijele širine kartice s kodom uz lijevi rub (izmjereno, DIZ-5 snimka: 350 px umjesto 248 px).
   `inline-block` ostaje za karticu koja nije flex (tada je centrira `.card { text-align: center }`).
   Slika blok da nema razmaka ispod. Sjena je token `--k-shadow-raised` (mock web-01:29), ne sjena
   dijaloga: K2c (O-K2-7) je `--k-shadow-dialog` podigao na 30/80/.7 mocka `.dlg`, što panelu ne pripada. */
.k-login__qrbox { display: inline-block; align-self: center; padding: 14px; border-radius: 8px;
    background: rgb(var(--k-white-rgb)); box-shadow: var(--k-shadow-raised); }
.k-login__qrbox img { display: block; }
/* #2184 (Codex P2, nalaz 1): kartica centrira sadrzaj (`.card { text-align: center }`), pa su oznaka
   i polje bez ovog pravila stajali u istom retku, centrirani. Mock kadar D (`.fld`): oznaka IZNAD
   polja, poravnata ulijevo, polje u punoj sirini. Geometriju mjeri e2e
   `AdminLoginLayoutSmokeTests`, ne grep nad ovim retkom. */
.k-login__field { text-align: left; margin: 0 0 14px; }
.k-login__field label { display: block; margin-bottom: 6px; }
.k-login__field input { display: block; width: 100%; }
/* Zvjezdica je OZNAKA OBAVEZNOSTI uz labelu; `aria-hidden` jer `required` na polju vec nosi istu
   informaciju za citace zaslona, pa bi izgovaranje zvjezdice bilo dvostruko. */
.k-login__req { color: var(--k-danger); font-style: normal; }
/* Adresa posluzitelja sitno dolje (mock: „Kerber 2.0 · int.kerber.hr"); host dolazi iz zahtjeva. */
.k-login__foot { text-align: center; color: var(--k-text-muted); font-size: .8rem; margin-top: 1rem; }
.k-login__logo:focus-visible { outline: var(--k-focus-ring); outline-offset: 2px; }
/* Mock web-01 kadar A (DIZ-5, `.timer b`): Consolas, naglasak, 600. `--k-font-mono` token nije
   definiran u temi — vrijedi rezerva, a u njoj je Consolas PRVI, kao u mocku. Izmjereno (DIZ-5,
   Chromium na Windowsu): `ui-monospace` tamo nije poznat font (sirina probe jednaka nepostojecem
   fontu), pa je stari redoslijed (ui-monospace, Cascadia Mono, Consolas) padao na Cascadia Mono:
   celija 8,2 px naspram 7,7 px Consolasa (14 px / 600), pa dvotocka (4 px tinte) stoji s sirim
   razmacima. S Consolasom su sirine znak po znak jednake mockovu `.timer b`; preostali razmak oko
   dvotocke je svojstvo monospace celije i postoji i u mocku. `--warn` stoji IZA i nadjacava boju,
   pa zuto ispod 30 s ostaje (W-07). */
.k-login__countdown { font-variant-numeric: tabular-nums; color: var(--k-accent); font-weight: 600;
    font-family: var(--k-font-mono, Consolas, "Cascadia Mono", ui-monospace, monospace); }
.k-login__countdown--warn { color: var(--k-warning); font-weight: 600; }
/* STANJE B JE ZUTO (scen 40: „prikazuje se zuti redak isteka"). Bez ovoga je redak isteka bio u
   obicnoj boji teksta, pa je zuto upozorenje NESTAJALO tocno u trenutku kad kod postaje nevaljan -
   nalaz Codexa k0, krug 7. Boju mjeri pin nad IZRACUNATIM stilom potrosaca, ne grep nad ovim retkom. */
.k-login__expired { color: var(--k-warning); font-size: 13px; } /* K3c rez B: web-01-prijava.html:40 .strip */
/* B16a (W-07 :81, W-05 :79): poruke prijave (`?error=istekao|opozvan`, stanje B) su ŽUTI REDAK NA VRHU — mock
   web-01:40 `.strip { position: absolute; top: 0; left: 0; right: 0 }`. Izgled (žuta pozadina, rub i točka, tekst
   `--k-text`) daju klase retka veze `.k-conn-strip.k-conn-strip--warn`; ovo pravilo daje SAMO položaj. Izvan toka,
   pa se kartica ne pomakne kad skripta redak otkrije ili sakrije. Roditelj NE dobiva `position: relative`: na
   anonimnoj stranici nema pozicioniranog pretka (`main.k-page`, `body`, `html` su statični), pa je sadržni blok
   početni — redak stoji na vrhu stranice u punoj širini prozora, kao mockov `.strip` u `.web`; `relative` na
   `.k-page` suzio bi ga na `--k-page-max`. Bez `display` (F4 par je `.k-conn-strip[hidden]`). Tekst je
   `--k-text` jer `.k-conn-strip` (iste specifičnosti, kasnije u listu) nadjačava boju `.k-login__expired`. */
.k-login__strip { position: absolute; top: 0; left: 0; right: 0; }

/* STANJE C (scen 46): potvrda da je kod preuzet i da prijava traje. Kvačica nosi boju uspjeha, a
   poruka ostaje u običnoj boji teksta — zeleno je znak, ne cijela rečenica. Boju mjeri pin nad
   izračunatim stilom potrošača, nikad grep nad ovim retkom. */
.k-login__potvrda { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
/* F4: Fluent bez Bootstrapa nema [hidden] — UA [hidden] gubi od display: flex iznad (K3-F, #3291). */
.k-login__potvrda[hidden] { display: none; }
.k-login__kvacica { color: var(--k-success); font-weight: 700; }
/* K3a′ N2: own 14px (mock `.timer` web-01:32), not the 15px body (D3); „Kod je očitan…" beside it stays 15. */
.k-login__napredak { color: var(--k-text-muted); font-size: 14px; }
/* POTROSEN KOD IZBLIJEDI (W-07, stanje C). Prozirnost, ne skrivanje: kartica i dalje pokazuje STO je
   ocitano, ali kod vise ne izgleda kao poziv na skeniranje. Vrijednost mjeri pin nad izracunatim
   stilom, ne grep nad ovim retkom. */
.k-login__qr--potrosen { opacity: .35; transition: opacity .2s ease; }

.k-conn--connected .k-conn__dot { background: var(--k-success); }
.k-conn--connected .k-conn__label { color: var(--k-success); }
.k-conn--reconnecting .k-conn__dot { background: var(--k-warning); }
.k-conn--reconnecting .k-conn__label { color: var(--k-warning); }
.k-conn--lost .k-conn__dot { background: var(--k-danger); }
.k-conn--lost .k-conn__label { color: var(--k-danger); }

/* Task 5 (W1) — KerberGrid over the DX theme (written over Blazing Dark; Fluent Dark since K3-F). Recipe from
   docs/design/cominus-design-reference.md §6 "Grid — the most important pattern": chromeless (no
   outer frame, transparent over the page bg), header 11px/600 UPPERCASE --muted with 0.5px tracking,
   data rows separated only by a --border hairline, hover a cyan wash.
   HOW, and why it is mostly variables rather than selectors: DevExpress publishes per-component CSS
   custom properties (--dxbl-grid-*) that the theme itself consumes, so re-pointing those at Kerber's
   --k-* tokens is the supported, upgrade-safe way to restyle the grid — DevExpress's own guidance is
   that rules written against internal class names "may stop working after you upgrade"
   (docs.devexpress.com/Blazor/401740 "CSS Classes"). Only the two things with no variable —
   uppercase header text and its letter-spacing — need an element selector.
   ZEBRA, with its history: the §6 recipe's zebra striping was at first deliberately NOT carried over — "it
   fights the hover wash on a dark surface", and §9 drops the pager it was designed alongside. The OWNER brought
   it back on 15.10. (one of the small details from the approved design): mock
   docs/design/mocks/web-00-stilska-knjiga.html:377-381, rule :154. It is now drawn so that it cannot fight —
   hover, the selected row and a row's tone all take precedence; rule and mechanism at
   `.k-grid__dx tr.k-grid__row--alt` below. §9 still drops the pager. */
/* k0 #2931 @ 8a565254b P2-2 (DIZ-1 K1): the height budget belongs to the WRAPPER, not to DxGrid. K1 put the
   toolbar (search, export) and the footer outside DxGrid; with the budget left on .k-grid__dx they sat outside it
   too and pushed the footer below the window (TEST-WEB 155026: /dev/grid +31 px at 1440×900 and 1280×800). The
   wrapper takes what the shell leaves and DxGrid fills the rest of it as a flex item — still a bounded height,
   which is what virtual scrolling needs. The floor is today's 320 px grid plus toolbar and footer.
   #3144 B: what the shell leaves is MEASURED — --k-grid-fit-h is the window's height below this grid's own top,
   written inline by kerber-shell.js (registerGridFit). The fallback is the rule this sheet had before, byte for
   byte (prerender, no JS, popup); KerberGridFitTests' P6 holds both halves. */
.k-grid {
    display: flex;
    flex-direction: column;
    height: var(--k-grid-fit-h, calc(100dvh - var(--k-navbar-h) - var(--k-grid-chrome-h)));
    min-height: 410px;
}

/* #2543/#2521 — THE SETTLE GATE. While the circuit is live (data-k-grid-live='1') but the grid has not
   yet sorted or restored its rows (data-k-grid-settled='0'), a row does not take the pointer: a click
   in that window landed on whatever row DevExpress refilled the same place with once the sort
   arrived. Both attributes are KerberGrid's own (settled: MarkSettled writes '1', CloseSettleGate writes '0'
   again on every swap/live/search reload after the first settle, #3251), and the
   row handle is Kerber's own data-k-row-key, not a DevExpress class. The prerender (live='0') is NOT
   covered: nothing reshapes it, and its href links must work before the circuit exists. Invisible on
   purpose - no new look (ARH 2240). No rule under .k-grid may switch pointer events back on for a
   child of a row, or that child takes the click back (REV 2304 P2-3); GridSettleGateTests' P-4 holds
   this rule's shape and that absence. */
.k-grid[data-k-grid-live='1'][data-k-grid-settled='0'] [data-k-row-key] { pointer-events: none; }

.k-grid__dx {
    /* Virtual scrolling needs a bounded height or DxGrid grows to fit every row (DevExpress docs,
       "Scrolling in Blazor Grid" → Row Virtualization → Grid Height). Bounded by the .k-grid wrapper above:
       a zero-basis flex item of a fixed-height column. min-height: 0 lets it shrink below its content —
       without it a flex item's automatic minimum is its content and DxGrid grows to every row again. */
    flex: 1 1 0;
    min-height: 0;

    --dxbl-grid-bg: transparent;
    --dxbl-grid-color: var(--k-text);
    --dxbl-grid-border-color: var(--k-border);
    /* DIZ-1 K1b (j): the frame is .k-grid__box's (the mocks' `.gridbox`); DxGrid's own 1px outer border
       (Fluent 25.2.9 core.min.css: 0.0625rem through --dxds-border-width-10 on `.dxbl-grid`; BlazingDark 1px)
       would draw a second line just inside it.
       #4283: the zero carries a unit because the theme also does arithmetic with this variable — the column resize
       handle sits at `right: calc((var(--dxbl-grid-border-width) - 7px) / 2 - 1 * var(--dxbl-grid-border-width))`
       (core.min.css 25.2.9), and a unitless 0 minus 7px makes that calc() invalid, so `right` falls back to auto and
       the handle of every column except the last sits by the header's LEFT edge instead of its right border. */
    --dxbl-grid-border-width: 0px;
    /* ARH-C 005949 t.2 (REV-D2 §4): th background .02 in 25 of 27 mocks; td padding 10px 12px in 19.
       K3-F F5: Fluent 25.2.9 paints the header cell with this variable AS IS (its 0,4,2 rule on
       th:not(.dxbl-grid-empty-cell)); BlazingDark mixed 10 % black into it and drew the .02 as a ≈ .12 grey (the rule
       was effectively dead). K3-F N6 (ARH-C 200925): painted as is, the .02 is a see-through STICKY header (DX's thead:
       position sticky, z-index 2, background inherit from our transparent --dxbl-grid-bg) — scrolled rows show through.
       So the mock's at-rest colour as an OPAQUE composite: 2 % white over the .k-grid__box surface (web-07:62
       `.gridbox { background: var(--surface) }`, web-07:64 `th { background: rgba(255,255,255,.02) }`) — the same
       colour at rest, opaque under scroll. Pin: GridMockMajorityCssTests.Zaglavlje_je_neprozirni_kompozit_vecine. */
    --dxbl-grid-header-bg: color-mix(in srgb, rgb(var(--k-white-rgb)) 2%, var(--k-surface));
    --dxbl-grid-text-cell-padding-y: 10px;
    --dxbl-grid-text-cell-padding-x: 12px;
    /* REV-D 005530 N2: every mock's `table.g th { color: var(--label) }` (web-00:147, web-05:105, web-14:64). */
    --dxbl-grid-header-color: var(--k-text-label);
    --dxbl-grid-header-font-weight: 600;
    /* K3-F F2 (Fluent 25.2.9 core.min.css): the sortable header's hover reads THIS variable too
       (`th.dxbl-grid-header-sortable:hover { background-color: var(--dxbl-grid-hover-bg) }`), so the
       BlazingDark-only `--dxbl-grid-hover-bg-static` (same value; BlazingDark mixed it with 30 % black) is
       gone. Also gone, read by no Fluent rule: `--dxbl-grid-filter-panel-bg` (Fluent paints the filter
       panel from the global `--dxds-color-surface-neutral-subdued-rest`, no --dxbl hook; no KerberGrid
       shows a filter panel) and `--dxbl-grid-draggable-header-color` (read by neither theme). */
    --dxbl-grid-hover-bg: rgba(var(--k-accent-rgb), 0.05);
    --dxbl-grid-hover-color: var(--k-text);
    --dxbl-grid-selection-bg: rgba(var(--k-accent-rgb), 0.12);   /* tr.sel .12 in 21 mocks (REV-D2 §4) */
    --dxbl-grid-selection-color: var(--k-text);
    --dxbl-grid-focus-bg: rgba(var(--k-accent-rgb), 0.1);
    --dxbl-grid-focus-color: var(--k-text);
    --dxbl-grid-focus-frame-color: var(--k-accent);
    --dxbl-grid-footer-bg: transparent;
    --dxbl-grid-footer-color: var(--k-text-muted);
    --dxbl-grid-group-footer-bg: transparent;
    --dxbl-grid-group-footer-color: var(--k-text-muted);
    /* drag-reorder hint chip — §6 keeps structure on --card-stroke, fill on --surface */
    --dxbl-grid-draggable-header-bg: var(--k-surface);
    --dxbl-grid-draggable-header-border-color: var(--k-border-strong);
}

/* ZEBRA (owner 15.10. — the approved design's alternating rows).
   Mock docs/design/mocks/web-00-stilska-knjiga.html:154 `table.g tr.zebra td { background: rgba(19,21,31,.5) }` on the
   2nd/4th/6th row (:377-381); Cominus §6 (docs/design/cominus-design-reference.md:224): odd rows get the surface
   at half opacity.
   WHICH ROWS: KerberGrid.OnCustomizeElement puts .k-grid__row--alt on every data row with an ODD VisibleIndex —
   DevExpress's row index, not :nth-child, which under virtual scrolling would count from wherever the viewport
   starts and count spacer rows too.
   THE COLOUR, one rule for both themes, existing tokens only, no theme selector: the mock alternates --bg with a
   half-step towards --surface. Our table lies on the .k-grid__box --surface, so the same two tones come as --surface
   and a half-step towards --bg — --bg at 50 % over the surface. Dark: #0A0B14 over #13151F ≈ −4.5/−5/−5.5 per
   channel (a darker stripe); light ([data-k-theme="light"] block): #F1F3FF over #DADCE8 ≈ +11.5 (a lighter one).
   The hover wash is the accent at .05 — lighter and cyan on dark, ≈ −10/255 on light — so in both themes it moves
   the other way and in another hue than the stripe. History: the first take (2 % white, 8e83c2a31) was invisible
   on the light surface (≈ +0.7/255) and was replaced by the half-step towards --bg described above.
   WHY IT CANNOT FIGHT THE HOVER WASH: it is not a background on the row or on its cells but the row's RESTING
   colour in DevExpress's own model. Fluent 25.2.9 core.min.css paints every body row with
   `.dxbl-grid .dxbl-grid-table>tbody>tr { background-color: var(--dxbl-grid-row-bg) }` (0,2,2) and defines
   `--dxbl-grid-row-bg: var(--dxbl-grid-bg)` on `.dxbl-grid`. Re-pointing the variable on an odd row changes only
   that resting colour: DevExpress's hover (0,7,2), selected-row (0,6,0) and focused-row (0,5,0) rules paint the
   same <tr> from their own variables and outrank it, and a row tone (.k-grid__row--marked) paints the <td>s,
   which lie above the <tr>. Pins: GridHoverCssTests.Zebra_* (the cascade and the composite colours, both themes),
   GridRowCssTests (which rows get the class), FluentDxblVarsReadTests.Zebra_DX_pravila_retka_su_doslovna (the
   quoted DX rules are real). */
.k-grid__dx tr.k-grid__row--alt {
    --dxbl-grid-row-bg: color-mix(in srgb, var(--k-bg) 50%, transparent);
}

/* The one part with no CSS variable. Two class selectors (not one) on purpose: DevExpress warns a
   single-class rule loses to the theme's own more specific selectors. */
/* W-11 (bez okomitih crta u gridu) NEMA ovdje pravila — i to je izmjereno, ne propust: mutant
   M-G5 (11.9. 14:18) pokazao je da uklanjanje takvog pravila NE mijenja izracunati stil, jer
   DevExpress 25.2.9 u ovoj temi okomite rubove celija ionako ne crta. Override interne klase bez
   ucinka ne ulazi (spec 11.0). Ishod cuva pin G-5 (GridChromeSmokeTests): ako nadogradnja
   DevExpressa ikad nacrta okomite crte, pin pada i pravilo tada ulazi s RED referencom. */

/* B11 — W-11's other half, the horizontal line between body rows (web-decisions.md:84; every mock:
   `table.g td { border-bottom: 1px solid var(--border) }`). K1b (j) zeroes --dxbl-grid-border-width for the
   frame, and in Fluent 25.2.9 the same variable is the body cell's border-top-width (core.min.css:
   `.dxbl-grid .dxbl-grid-table>tbody>tr>td`), so the row line went with the frame. Only the width comes back;
   colour and style stay DX's (inherited from the table: --dxbl-grid-border-color = --k-border above, solid).
   No line above the first data row comes from DX itself, with or without virtual scrolling (devexpress.blazor.
   themes.fluent 25.2.9 core.min.css md5 81c5423f, rule 1406 / 1407 counted by `}`):
   `…>tbody>tr:first-child>td{border-top-width:0}` and `…>tbody>tr:first-child:is([dxbl-top-virtual-spacer-element])
   +tr:not([dxbl-top-virtual-spacer-element])>td{border-top-width:0}` (0,5,4). A zero of our own had no effect
   (mutant M2, e2e-web-targeted 38646590965: G5 / G11 / G11b green without it), so it is not here (spec 11.0);
   the E2E's first-row "0px" guards DX's zero across upgrades. One rule (W-11). Pins:
   GridBoxCssTests.Crta_izmedju_redaka_tijela, E2E GridChromeSmokeTests.G11. */
.k-grid__dx .dxbl-grid-table > tbody > tr > td {
    border-top-width: 1px;
}
/* B11 R3 — no line under the LAST data row on a short list (mock `tr:last-child td { border-bottom: 0 }`). The line
   rule above hits every body row, and so does DX's own (core.min.css 25.2.9 md5 81c5423f, rule 1325 by `}`:
   `…>tbody>tr>td{… border-top-width:var(--dxbl-grid-border-width) …}`); DX shows its empty row only when the table
   does not scroll (rule 1472: `.dxbl-grid-table:not(.dxbl-grid-table-no-scroll)>tbody>.dxbl-grid-empty-row
   {display:none}`), so on a short list that row's top edge is a line under the last data row (probe e2e-web-targeted
   38657765572). A zero of its own, (0,3,3) over the line's (0,2,3); the line's selector stays as it is — a :not() on
   it would tie DX's first-row zero (0,3,3) and leave the first row to load order. Pins:
   GridBoxCssTests.Kratki_popis_bez_crte_ispod_zadnjeg_retka, E2E GridChromeSmokeTests.G11c. */
.k-grid__dx .dxbl-grid-table > tbody > tr.dxbl-grid-empty-row > td {
    border-top-width: 0;
}
/* B11b — the line under the header (mock web-02-zadaci.html:62 `table.g th { … border-bottom: 1px solid
   var(--border-strong) }`). DX draws it on the LAST header row's cells, `th` and `td` alike (core.min.css
   `…>thead>tr:last-child>th`, `…>td`), from the same zeroed variable, coloured `inherit` (= --k-border). On grids
   with ShowFilterRow the last header row is the filter row, whose cells are `td`: the line goes under the WHOLE
   header, where DX put it (ARH-C 194407 (a)). The empty filler cell keeps DX's zero, as in the body. (0,4,3) beats
   DX's (0,3,3) without relying on order. Pins: GridBoxCssTests.Crta_ispod_zaglavlja, E2E GridChromeSmokeTests.G11b. */
.k-grid__dx .dxbl-grid-table > thead > tr:last-child > :is(th, td):not(.dxbl-grid-empty-cell) {
    border-bottom-width: 1px;
    border-bottom-color: var(--k-border-strong);
}

/* Prazno podrucje (M-1 presuda): jedan predlozak u KerberGridu za sve gridove. Izgled (isprekidani
   okvir, naslov + uputa) dolazi s W-05; ovdje samo citljiv, prigusen redak da tablica ne izgleda
   pokvareno dok W-05 ne stigne. */
/* DIZ-1 K1, element E11 (web-00:192-193 `.empty`, :424; W-05): dashed frame, the title in text colour,
   the page's hint under it muted. */
.k-grid__empty {
    margin: 12px 0;
    padding: 34px 20px;
    color: var(--k-text-muted);
    text-align: center;
    border: 1px dashed var(--k-border-strong);
    border-radius: var(--k-radius-lg);
}
.k-grid__empty-title {
    display: block;
    color: var(--k-text);
    font-size: 15px;
    font-weight: 600;
    margin-bottom: 4px;
}
.k-grid__empty-hint { display: block; }

/* DIZ-1 K1 — THE ONE TOOLBAR ROW (W-32; web-02:147-149, web-14:300-302; element E1): title and the
   page's lead tools on the left, its end tools · search · „Izvoz ▾" · primary action on the right, in
   ONE row above the grid header (web-00 `.pagehead` :98-99/:290 + `.gridbar` :142/:368). */
.k-grid__bar {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}
.k-grid__head { display: flex; flex-direction: column; gap: 2px; }
/* web-00:99 `.pagehead h1` — 20/600 CAPS cyan (W-02 b). */
.k-grid__title {
    margin: 0;
    font-size: 20px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-accent);
}
/* web-07:119 `.sub` — the page's subtitle under its title. */
.k-grid__sub { font-size: 13px; color: var(--k-text-muted); }
.k-grid__lead { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.k-grid__tools {
    display: flex;
    align-items: center;
    gap: 10px;   /* the mocks' .tools gap (ARH-C 005949 t.2) */
    margin-left: auto;
}
/* web-05:174 / web-06:170 — the chips' own row under the toolbar row. */
.k-grid__below { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
/* web-00:370 `.btn.sec.sm` — „Izvoz ▾" in the toolbar row: the SAME DxToolbar the grid always had (Task 8),
   chromeless over the page, its drop-down button drawn as a small outlined button (structure on the border
   colour, cyan on hover — W-04). DevExpress CSS variables only, for the upgrade-safety reason the grid block
   above states.
   K3-F F5 G2 (REV-D 083036): the BUTTON's focus ring is --k-accent, Task 9's house ring colour. Measured in Fluent
   25.2.9 core.min.css: a toolbar button takes its ring colour from `--dxbl-btn-toolbar-focus-outline-color`,
   declared on `.dxbl-toolbar` (var(--dxds-color-border-focus-default) = #fffffe; BlazingDark #9b17e2) and read by
   `.dxbl-toolbar:not([data-dx-focus-hidden]) .dxbl-toolbar-item>.dxbl-btn` (0,4,0) into the button's own
   --dxbl-btn-focus-outline-color. This class sits on that same `dxbl-toolbar` element (KerberGridToolbarTests' golden),
   so the tie (0,1,0) goes to this sheet by order. Width and offset follow the house `:focus-visible` rule, which
   names export buttons (ARH-C 110742): `-width` the house ring's width (the first word of --k-focus-ring, 2px —
   that token is a shorthand, so the number is repeated, not new, as W4's block does), `-offset` THROUGH
   --k-focus-ring-offset; Fluent's are 0.125rem / 0.0625rem (`.dxbl-toolbar`), copied by the same 0,4,0 rule into the
   button's --dxbl-btn-focus-outline-size/-offset, which `.dxbl-btn:focus-visible` draws.
   Pin: FluentDxblVarsReadTests.F5_G2b_prsten_Izvoza_debljina_i_razmak_po_kucnom_pravilu. The `-dropdown-btn-` variable is the OPENED MENU's split item; Fluent declares it on
   `.dxbl-toolbar-dropdown`, the menu itself. Pin: FluentDxblVarsReadTests.F5_G2_prsten_fokusa_gumba_Izvoz_je_k_accent. */
.k-grid__export {
    --dxbl-toolbar-bg: transparent;
    --dxbl-toolbar-color: var(--k-text);
    --dxbl-btn-toolbar-focus-outline-color: var(--k-accent);
    --dxbl-btn-toolbar-focus-outline-width: 2px;
    --dxbl-btn-toolbar-focus-outline-offset: var(--k-focus-ring-offset);
    --dxbl-toolbar-dropdown-btn-focus-outline-color: var(--k-accent);
    flex: none;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}
/* The „Izvoz ▾" BUTTON's colours (K3-F F2, #3291). BlazingDark exposed them as TOOLBAR variables
   (`--dxbl-toolbar-btn-*`, set on the toolbar root above until F2) and copied them into the button's own
   `--dxbl-btn-*`; Fluent 25.2.9 has no toolbar-level colour hook — core.min.css declares the button's
   `--dxbl-btn-*` ON THE BUTTON (`.dxbl-btn.dxbl-btn-secondary`, 0,2,0; the toolbar's hover/active tint via
   `--dxbl-btn-secondary-hover-bg` at 0,6,0). So the port sets the SAME `--dxbl-btn-*` names BlazingDark fed
   (bg, color, border/hover-border/active-border/disabled-border colour, hover bg + colour, active bg +
   colour) on the button itself: our class + two DevExpress classes (0,3,0) — a DEVEXPRESS CLASS SELECTOR,
   NAMED AS A DEPARTURE (as `.dxbl-checkbox` above), because no class of ours reaches the <button>
   (DxToolbarItem renders `button.dxbl-btn.dxbl-btn-secondary.dxbl-toolbar-btn`, KerberGridToolbarTests'
   render pin). Values are the ones the toolbar variables carried. Not ported, read by no Fluent rule:
   `--dxbl-toolbar-border-color` (read by neither theme) and `--dxbl-toolbar-dropdown-btn-{bg,color,
   border-color}` — in BlazingDark those painted the items of the OPENED MENU, not this button (their
   values duplicated the button's); Fluent declares the menu items' colours on the items themselves,
   with no toolbar hook. */
.k-grid__export .dxbl-btn.dxbl-toolbar-btn {
    --dxbl-btn-bg: transparent;
    --dxbl-btn-color: var(--k-text);
    --dxbl-btn-border-color: var(--k-border-strong);
    --dxbl-btn-hover-border-color: var(--k-border-strong);
    --dxbl-btn-active-border-color: var(--k-border-strong);
    --dxbl-btn-disabled-border-color: var(--k-border-strong);
    --dxbl-btn-hover-bg: transparent;
    --dxbl-btn-hover-color: var(--k-accent);
    --dxbl-btn-active-bg: rgba(var(--k-accent-rgb), 0.15);
    --dxbl-btn-active-color: var(--k-text);
    /* K3-F N9 (a) (ARH-C 204603, #3291): the caption takes the toolbar root's size and weight (`.k-grid__export` above,
       11px / 600, mock web-00:370 `.btn.sec.sm`) — Fluent sets the button's own (measured 12.25px / 400), so it does not
       inherit them. Size through the hook: Fluent 25.2.9 core.min.css (md5 81c5423fb482491e04814e73212c99df)
       `.dxbl-btn{…font-size:var(--dxbl-btn-font-size)…}`, the variable declared on `.dxbl-btn` (0,1,0) and
       `.dxbl-btn.dxbl-sm` / `.dxbl-lg` (0,2,0); this rule is (0,3,0). Weight DIRECTLY, a named departure: the hook
       `--dxbl-btn-font-weight` exists, but Fluent sets it on toolbar buttons at (0,6,0)
       (`.dxbl-toolbar>.dxbl-btn-toolbar .dxbl-toolbar-btn.dxbl-btn:not(.dxbl-ribbon-item-split.dxbl-ribbon-item-primary)
       {…--dxbl-btn-font-weight:var(--dxds-font-weight-base-default)…}`), so reaching it would take a (0,6,0) selector;
       `font-weight` here (0,3,0) beats `.dxbl-btn{font-weight:var(--dxbl-btn-font-weight)}` (0,1,0), as G1 does.
       Pin: FluentDxblVarsReadTests.N9a_gumb_Izvoz_nosi_velicinu_i_tezinu_korijena_trake. */
    --dxbl-btn-font-size: 11px;
    font-weight: 600;
}

/* DIZ-1 K1b, (j) ARH-C 2218: the table's frame — the mocks' `.gridbox`, the same rule in 24 screen mocks
   (web-05:103, web-14:62): one rounded card around the table and its footer, on tokens (--k-radius = 10px).
   Measured: no screen wraps a grid in a bordered card of its own, so no frame doubles. Pinned by
   GridBoxCssTests and KerberGridToolbarTests.Okvir_obuhvaca_tablicu_i_podnozje_a_ne_alatni_red. */
.k-grid__box {
    /* k0 #3152 [P1]: a bounded flex item of the .k-grid wrapper (#2931 P2-2 keeps the height budget there) AND a flex
       column for DxGrid and the footer — DxGrid's flex: 1 1 0 / min-height: 0 needs a flex parent, or it grows to
       its content and the footer leaves the window. */
    display: flex;
    flex-direction: column;
    flex: 1 1 0;
    min-height: 0;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius);
    overflow: hidden;
    background: var(--k-surface);
}
/* #4688: the loading frame goes away in the same render that mounts KerberGrid, and DxGrid draws its first frame
   without the header row, so the card's content was one header shorter than the frame's and the footer jumped up.
   While the card has no header row it keeps that row's height on top; once DxGrid draws the header this selector
   stops matching and the header takes the same height, so nothing moves. The height is the frame's header cell
   (.k-grid-frame__table th below, from the same numbers: padding 10px above and below, 12px at line-height 1.4285,
   the 1px line under it). A rule of its own, so .k-grid__box above stays byte for byte. Pin:
   GridBoxCssTests.Okvir_bez_zaglavlja_cuva_visinu_zaglavlja. */
.k-grid__box:not(:has(.dxbl-grid-header-row)) { padding-top: calc(2 * 10px + 12px * 1.4285 + 1px); }

/* #4688 — THE TABLE'S LOADING FRAME (KerberGridLoadingFrame, look B, the owner's choice): while a page reads its first
   rows it draws the grid's header over an empty body in the same card, so the main area keeps the table's shape.
   The card is a rule of its OWN with the grid box's four declarations above, on the same
   tokens — not a shared selector, so .k-grid__box stays byte for byte, and without its flex chain (#2931, #3152:
   that height budget belongs to the .k-grid wrapper, which the frame is not in). Pin:
   GridBoxCssTests.Okvir_ucitavanja_nosi_iste_cetiri_deklaracije_kao_okvir_tablice. No animation. */
.k-grid-frame__box {
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius);
    overflow: hidden;
    background: var(--k-surface);
}
/* The frame's Head (the Table/Map/Both switch on Locations and Workers) stands 12px above the box — the
   map-grid's own gap between its top row and its table (`.k-mapgrid { display: grid; gap: 12px; }` below), so nothing
   moves when the grid takes the frame's place. Only when something stands above the box: without a Head the box is
   the frame's first child, this selector does not match, and the other seven pages are unchanged. A rule of its
   own, so `.k-grid-frame__box` keeps exactly the grid box's four declarations (GridBoxCssTests). */
.k-grid-frame > * + .k-grid-frame__box { margin-top: 12px; }
/* The table as DxGrid lays its own out (Fluent 25.2.9 core.min.css `.dxbl-grid .dxbl-grid-table{border-collapse:separate;
   …border-spacing:0;table-layout:fixed;width:100%}`), so the given column widths land where the grid's do. */
.k-grid-frame__table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    table-layout: fixed;
}
/* The header cell as the grid's (.k-grid__dx), value for value, because the grid's variables are declared on
   .k-grid__dx and do not reach the frame: padding 10px 12px (--dxbl-grid-text-cell-padding-y/-x above, which DX spends as
   the header cell's `padding`), 12px CAPS on --k-label-tracking (.k-grid__dx .dxbl-grid-header), weight 600 and
   --k-text-label (--dxbl-grid-header-font-weight / -color), the opaque header composite (--dxbl-grid-header-bg), the
   1px --k-border-strong line under the header, and DX's own line-height 1.4285, left alignment and middle
   vertical alignment (core.min.css `.dxbl-grid{--dxbl-grid-line-height:1.4285;…text-align:left}` and the cell rule's
   `vertical-align:middle`; no Kerber rule changes them). ONE LINE, cut with an ellipsis: KerberGrid sets
   TextWrapEnabled="false" (KerberGrid.razor:71; DevExpress.Blazor 25.2.9 XML: false = „trim extra words and display an
   ellipsis"), which DX draws through `.dxbl-grid.dxbl-grid-nowrap{--dxbl-grid-white-space:nowrap;…}` and
   `.dxbl-grid.dxbl-grid-nowrap .dxbl-grid-header-content>span{white-space:var(--dxbl-grid-white-space)}` with the
   caption span's `overflow:hidden;text-overflow:ellipsis` (core.min.css 25.2.9) — a wrapping caption here would make
   the frame's header taller than the grid's. The cell's height is NOT measured by any test: the values are copied,
   the E2E (LoadingFrameSmokeTests) compares only the header texts and a lower bound of the main area's height. */
.k-grid-frame__table th {
    padding: 10px 12px;
    font-size: 12px;
    line-height: 1.4285;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-text-label);
    background: color-mix(in srgb, rgb(var(--k-white-rgb)) 2%, var(--k-surface));
    border-bottom: 1px solid var(--k-border-strong);
    text-align: left;
    vertical-align: middle;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    overflow-wrap: normal;
}
/* The status line keeps the page's loading class (its marker) and is for a screen reader only: clipped to a 1px box
   after .k-task-measure__violation, not display:none / visibility:hidden, which would hide it from the reader too.
   Two classes, (0,2,0), because the pages' own loading-line rules (one class: .k-locations__loading,
   .k-workers__loading, .k-company-templates__loading and the rest) set a margin and some stand later in this sheet.
   Pin: GridBoxCssTests.Redak_stanja_okvira_je_skriven_clipom. */
.k-grid-frame .k-grid-frame__status {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/* DIZ-1 K1, elements F1/F4 (web-00:158/:385 `.gfoot`; web-07:142, web-14:320, web-02:167): the count on the
   left, the remembered-layout note on the right, muted 12 px. ARH-C 005949 t.2 (REV-D2 §8, 25 of 27 mocks): 8px 12px,
   a top line in --k-border-strong, items centred — the screen mocks over web-00:158. */
.k-grid__foot {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    padding: 8px 12px;
    border-top: 1px solid var(--k-border-strong);
    font-size: 12px;
    color: var(--k-text-muted);
}
/* k0 #2931 @ c23e51779 P2 (k0-3): the count carries the search phrase, and a flex item's automatic minimum width is
   its content — a long phrase on one line widened the footer and scrolled the document sideways. min-width: 0
   lets it shrink, and the phrase is cut with an ellipsis; the full text is on the span's title. */
.k-grid__count {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.k-grid__note::before { content: '· '; }
.k-grid__remember { margin-left: auto; }

/* K3a′ D3 (vlasnik W-02 b „zaglavlje tablice 12/600 CAPS"): the header cell's 12px goes through DevExpress's own
   variable, DECLARED ON THE CELL — Fluent 25.2.9 core.min.css (as BlazingDark) sets the cell's size itself,
   `.dxbl-grid .dxbl-grid-table>thead>tr>th{font-size:var(--dxbl-grid-font-size)}` (0,2,3), so a plain
   `font-size` here (0,2,0) would be a dead line; the theme declares the variable only on `.dxbl-grid`
   (0.875rem), not on the cell, so ours wins there (REV-D 012613, technique A — the same recipe as
   `.k-task-detail__tree thead th` further down). The theme has no `--dxbl-grid-header-font-size`. */
.k-grid__dx .dxbl-grid-header {
    --dxbl-grid-font-size: 12px;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}
/* K3a′ D3 (W-02 b „redak tablice 14/400", ARH-C 013208): a body cell is 14px through the same variable on the
   cell — DX's `…>tbody>tr>td{font-size:var(--dxbl-grid-font-size)}` (0,2,3) spends it; without it the cell is
   0.875rem = 12.25px at the 14px rem anchor. */
.k-grid__dx tbody td {
    --dxbl-grid-font-size: 14px;
}

/* DIZ-1 K1b, vlasnik (BRAIN 2120, i): the sort arrow stands next to the caption, as web-00:148 draws it
   (`th svg { 12×12; margin-left: 4px; color: var(--primary) }`). DevExpress's theme (25.2.9) gives these
   two classes `margin-left: auto`, which pushes the glyph to the header's right edge. No documented hook
   exists (docs MCP 25.2), so the class names are not a contract — the same exception as `.dxbl-checkbox`.
   KerberGrid shows no filter-menu funnel (FilterMenuButtonDisplayMode.Never), so nothing else needs its
   auto margin back. Pinned by GridSortGlyphCssTests. */
.k-grid__dx .dxbl-grid-sort-asc,
.k-grid__dx .dxbl-grid-sort-desc {
    margin-left: 4px;
    color: var(--k-accent);
}
.k-grid__dx .dxbl-grid-sort-asc svg,
.k-grid__dx .dxbl-grid-sort-desc svg {
    width: 12px;
    height: 12px;
}

/* REV-D 005530 N3: the SORTED column's caption is the mocks' `th.sort { color: var(--primary-soft) }`
   (web-05:106, web-14:65, web-16:65) = --k-accent-soft. DevExpress 25.2.9 marks no sorted header cell (theme
   selectors measured: only the glyph classes), so the cell that HOLDS the glyph is selected and the header
   colour re-pointed there; the glyph keeps its own --k-accent (rule above). Pinned by GridSortGlyphCssTests. */
.k-grid__dx th:has(.dxbl-grid-sort-asc, .dxbl-grid-sort-desc) {
    --dxbl-grid-header-color: var(--k-accent-soft);
}


/* Search box: DIZ-1 K1 moved it from DxGrid's top panel into the toolbar row (.k-grid__bar); web-00
   :145 `.search { width: 280px }` sizes it, with the old 220 px floor kept for a narrow window. */
/* #4283: with column resizing on, DevExpress draws one column separator (3 px, as tall as the table) over a
   column's left edge, data rows included; a click there would not open the row. Resizing starts on the
   header's resize anchor, so the separator takes no pointer events. */
.k-grid .dxbl-grid-columns-separator { pointer-events: none; }

.k-grid .k-grid__search { width: 280px; min-width: 220px; }

/* Task 9 (W1) — the search box's focus ring goes on the EDITOR, not on the <input> inside it: a
   DxTextBox is an input plus its clear button, and ringing only the input would draw a box around
   part of the control the user is in. `:has()` keeps this on our own CssClass rather than on a
   DevExpress class name — the same upgrade-safety reason the grid block above states for using
   DevExpress's CSS variables (docs.devexpress.com/Blazor/401740 "CSS Classes": rules written against
   internal class names "may stop working after you upgrade"). The second rule then removes the inner
   ring the global input:focus-visible would otherwise draw as well. */
.k-grid .k-grid__search:has(:focus-visible),
.k-mapgrid > .k-grid__bar .k-grid__search:has(:focus-visible),
.k-company-alarms__toolbar .k-grid__search:has(:focus-visible) {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
    border-radius: var(--k-radius-sm);
}
.k-grid .k-grid__search input:focus-visible,
.k-mapgrid > .k-grid__bar .k-grid__search input:focus-visible,
.k-company-alarms__toolbar .k-grid__search input:focus-visible { outline: none; }

/* Task 5 (W1) — /dev/grid demo page chrome. */
.grid-demo {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px var(--k-page-gutter);
}
.grid-demo__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}
.grid-demo__actions { display: flex; align-items: center; gap: 8px; }

/* W2 Task 2 — KerberMap and the /dev/map demo. The canvas needs a HEIGHT IN CSS: a provider map
   sizes itself to its container, and a container that is only as tall as its (empty) content
   collapses to nothing — a map that is "loaded" and invisible. */
.k-map {
    position: relative;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-lg);
    overflow: hidden;
    background: var(--k-surface);
}
/* THE CANVAS IS ITS OWN STACKING CONTEXT, and that is a fix rather than tidiness (bot k1).
   Google paints its overlays with explicit z-indices — cluster 900, selected 1000, playback 1100
   (kerber-map-google.js; Azure assigns none) — and .k-map is position:relative with NO z-index, so it
   establishes nothing. Without this line those overlays compete with the switch in the PAGE’s stacking
   order and can paint over it.

   WHY NOT SIMPLY z-index:1200 ON THE SWITCH: measured — the theme already spends 1000 on .k-topbar and
   on two modal backdrops (.k-wizard__modal-backdrop, .k-location-visits__modal-backdrop, both
   position:fixed inset:0). A map control above 1000 globally would punch through a modal. Isolating
   here keeps the provider’s 900/1100 INSIDE the canvas, where they belong, and lets the switch win
   with a 1 instead of racing numbers it does not own. */
.k-map__canvas { width: 100%; height: 420px; position: relative; z-index: 0; }
/* W-13 (3) and (1) — THE RING OF THE SELECTED POINT AND THE SOFT RING OF THE POINT WHOSE ROW IS UNDER THE POINTER,
   on Azure. kerber-map-azure.js puts one of these two classes on the HtmlMarker's own element (applySelection, through
   ringOf); Google's canvas-painted marker cannot take CSS, so kerber-map-google.js draws the same ring as a symbol.
   THE SHAPE IS THE MOCK'S: docs/design/mocks/web-05-lokacije.html:80 / :82 (the same lines in web-06-radnici.html:75 /
   :77) — `.pin.sel i` gets a dark 3px separator and then the light cyan out to 6px (the mock's --primary-soft is
   --k-accent-soft; W-14 „svijetli cyan = odabrano"), `.pin.hov i` a soft 7px wash of the accent at .3. The mock's dark
   separator #0b101c has no token of its own; --k-bg is the nearest one.
   AROUND THE POINT ON THE GROUND, NOT AROUND THE PIN: the mock's 14px dot (`.pin i`) stands ON its place, while a
   provider's pin stands above it, and the two providers' pins differ in shape and height — the ground point is the
   one place where the ring is the same on both. A pseudo-element rather than a box-shadow on the element itself,
   because that element is the pin's rectangular wrapper. Pointer events pass through it to the pin. */
.k-map-ring--selected::after,
.k-map-ring--hover::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: 0;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    transform: translate(-50%, 50%);
    pointer-events: none;
}
.k-map-ring--selected::after { box-shadow: 0 0 0 3px var(--k-bg), 0 0 0 6px var(--k-accent-soft); }
.k-map-ring--hover::after { box-shadow: 0 0 0 7px rgba(var(--k-accent-rgb), .3); }
/* #4342 — THE WORKER'S LINE OF TEXT under the worker glyph, on both providers: Azure's module draws it inside the
   HtmlMarker's content, Google's gives the classic Marker's label this class. Colour, size, weight and family come
   from the modules (docs/design/mocks/web-02d-zadatak-uzivo.html `lbl-live` / `lbl-stale`); this rule adds only the
   HALO. The mock draws the text straight onto its dark map; a satellite or light road base is not dark, so the
   letters get a dark rim of --k-bg — the same token the selected ring above takes for the mock's dark separator.
   Nothing here touches pointer-events, position or z-index: the line is part of its marker and lies in the marker's
   own layer. */
.k-map-worker-label { text-shadow: 0 0 2px var(--k-bg), 0 0 2px var(--k-bg), 0 0 4px var(--k-bg); }
/* W-15 t. 1 — the base switch, drawn OVER the map in its top-right corner.

   THE MOCK SAYS right:54px AND THIS SAYS 12px, deliberately. Those 54px leave room for the zoom /
   "prikaži sve" control that sits at right:12px IN THE MOCK and does not exist in the app yet.
   Measured rather than assumed: the Azure module adds no provider controls at all, and the Google one
   switches off map-type, street-view and fullscreen at creation, leaving only zoom — bottom right. The
   top-right corner is empty on both providers, so 54px would read as a misaligned control rather than
   a considered gap. When "prikaži sve" lands, this becomes 54px.

   The chips themselves reuse .k-mapgrid__row-select’s shape (same tokens, same 4px/10px padding the design
   asks for); what is added here is only the floating container. */
.k-map__views {
    position: absolute;
    right: 12px;
    top: 12px;
    /* One is enough: the canvas above isolates the provider’s own 900/1000/1100, so this only has to
       beat a sibling, not a number from another library. */
    z-index: 1;
    display: flex;
    gap: 4px;
    padding: 6px;
    background: var(--k-surface);
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
}
.k-map__view {
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .5px;
    color: var(--k-text-muted);
    background: transparent;
    border: 0;
    border-radius: var(--k-radius-sm);
    padding: 4px 10px;
    cursor: pointer;
}
/* The chosen base reads as PRESSED — announced through aria-pressed too, so the state is not colour
   alone (the same rule .k-seg__item--on follows). */
.k-map__view--on {
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
}
/* THE ICON FORM (owner 12.9. 19:23, W-15 answer (a)): the same three buttons, behind a layer button,
   for surfaces where the words do not fit. The group drops BELOW the toggle so it never covers the
   corner the worker just clicked. */
.k-map__views--icon { flex-direction: column; align-items: flex-end; padding: 4px; }
.k-map__views-group { display: flex; gap: 4px; }
.k-map__views--icon .k-map__views-group { margin-top: 4px; }
.k-map__views-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    color: var(--k-text-muted);
    background: transparent;
    border: 0;
    border-radius: var(--k-radius-sm);
    cursor: pointer;
}
.k-map__views-toggle[aria-expanded="true"] {
    color: var(--k-btn-text-on-accent);
    background: var(--k-accent);
}
.k-map__views-glyph { width: 18px; height: 18px; }
/* W-20 — THE CALLOUT: the card that belongs to one point, with a tail that points at it.

   EVERY COLOUR HERE IS A TOKEN, and the two that differ from the mock are a RULING rather than a
   slip (architect 13.9. 22:02). Measured first: the mock and this theme share their neutrals to the
   digit (#13151F, #DADCE8, #242845, #363C68 are --k-surface/--k-text/--k-border/--k-border-strong),
   which is why the two that do NOT match stand out — the mock's cyan #77D9F7 against
   --k-accent-soft #45D7F4, and its literal 8px radius against --k-radius 10px. The theme is the
   ratified system, so the theme wins and the mock carries the note.

   POSITION COMES FROM ARITHMETIC, NOT FROM CSS (MapCalloutLayout): `left`/`top` are written by the
   component and --k-map-callout-tail carries the tail's offset from the card's own left edge. CSS
   deliberately owns no `left: 50%` fallback for that variable: the mock's fixed 50% IS the defect
   scen 29 forbids, so a card whose tail offset went missing must look broken rather than plausibly
   wrong.

   Z-INDEX 1, AND EARLIER IN THE MARKUP THAN THE BASE SWITCH. Both need to clear the canvas (its own
   stacking context, above), but between siblings the later one wins — so the switch stays clickable
   over a callout that reaches the top-right corner, without touching the numbers already reasoned
   about above. */
.k-map__callout {
    position: absolute;
    z-index: 1;
    box-sizing: border-box;
    min-width: 230px;
    /* THE CARD NEVER OUTGROWS THE MAP — owner's W-20 dopuna 12.9.: "oblačić skrola unutar sebe".
       A long name and a dozen rows (scen 37) would otherwise make a card taller than the 420 px canvas,
       and `.k-map` clips its overflow, so the lower rows would be unreachable rather than scrollable.
       The cap is the map's OWN height (`max-height: 100%` resolves against `.k-map`), so a taller map
       gives a taller card without a second number to keep in step — and the measurement sees the result,
       because the frame the arithmetic is given carries the card's RENDERED height.
       The cap stays HERE; the scrolling is the body's (`.k-map__card-body`, below): a card that is itself a
       scroll container composites as its own layer over the provider's WebGL canvas — a hole in the map — and
       clips its own tail (08F probes 3 / 4). */
    max-height: 100%;
    display: flex;
    flex-direction: column;
    padding: 10px 12px;
    font-size: 13px;
    color: var(--k-text);
    background: var(--k-surface);
    border: 1px solid var(--k-accent-soft);
    border-radius: var(--k-radius);
    /* The second ring is the mock's cyan halo, expressed with the token the theme documents for
       exactly this (`rgba(var(--k-accent-rgb), …)` washes) — at .2, which is a value that set names,
       rather than the mock's .25, which it does not. The drop shadow is the theme's raised token. */
    box-shadow: var(--k-shadow-raised), 0 0 0 1px rgba(var(--k-accent-rgb), .2);
}
/* The tail is two triangles, the outer one carrying the border colour and the inner one the fill —
   the mock's own construction (9 px under 7 px), kept because it is what makes the tail look like a
   continuation of the card's border rather than a sticker on top of it.

   THE ROLES ARE SWAPPED RELATIVE TO THE MOCK, and that removes a z-index rather than adding style:
   the mock draws the border in ::after and the fill in ::before, which then needs `z-index: 1` to
   climb back on top. Pseudo-elements already paint ::before first and ::after second, so putting the
   FILL in ::after gets the same picture with no layer at all — and one less owner in the theme's
   z-index enumeration, which MapSwitchStackingTests deliberately keeps closed. */
.k-map__callout::before,
.k-map__callout::after {
    content: '';
    position: absolute;
    border: 9px solid transparent;
    left: calc(var(--k-map-callout-tail) - 9px);
}
.k-map__callout::after {
    border-width: 7px;
    left: calc(var(--k-map-callout-tail) - 7px);
}
.k-map__callout--above::before { bottom: -9px; border-bottom: 0; border-top-color: var(--k-accent-soft); }
.k-map__callout--above::after { bottom: -7px; border-bottom: 0; border-top-color: var(--k-surface); }
.k-map__callout--below::before { top: -9px; border-top: 0; border-bottom-color: var(--k-accent-soft); }
.k-map__callout--below::after { top: -7px; border-top: 0; border-bottom-color: var(--k-surface); }
/* The one render between "an element is selected" and "we know where its card goes": the card is laid
   out — which is what makes it measurable (scen 37) — and shows nothing. `visibility`, never `display`,
   because a display:none card has no size to measure, which is the whole reason it is here. */
.k-map__callout--measuring { visibility: hidden; }
/* W-20 lijek (08F, ARHITEKT 025058): THE BODY SCROLLS, NOT THE CARD. The card is a flex column under its cap
   (max-height: 100% above), so this body is bounded by it; min-height: 0 lets the flex item be shorter than its
   content, which is what turns a long card into a scrolling one (owner's W-20 dopuna 12.9.). The name carries no
   'callout' on purpose: MapCalloutLookTests O6 enumerates every k-map__callout rule and KerberCalendarWeb16Tests
   (6) every 'callout' rule. It scrolls only with `--scroll` (below). */
.k-map__card-body {
    min-height: 0;
}
/* W-20 lijek v2 (08F, ARHITEKT 042755): the body is a scroller ONLY when the host measured the card at its cap
   (MapCalloutLayout.IsAtCap) — a short card has no scroll container at all, not even the one rounding pixel
   (keyed run 38336441078: scrollHeight 37 / clientHeight 36). No 'callout' in the name (O6 / KerberCalendarWeb16Tests (6)). */
.k-map__card-body--scroll {
    overflow-y: auto;
    overscroll-behavior: contain;
}
/* Scen 61: the degraded state sits OVER the (empty) canvas rather than beside it, so an unavailable
   map reads as one thing that failed instead of a blank rectangle with a note next to it. */
.k-map__unavailable {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0;
    padding: 0 24px;
    text-align: center;
    color: var(--k-text-muted);
    background: var(--k-surface);
}
.map-demo {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px var(--k-page-gutter);
}
.map-demo__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}
.map-demo__actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.map-demo__status { margin: 0; color: var(--k-text-muted); }
.map-demo__maps { display: grid; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); gap: 16px; }
.map-demo__map h2 { font-size: 14px; text-transform: uppercase; letter-spacing: var(--k-label-tracking); color: var(--k-text-muted); margin: 0 0 8px; }

/* W2 Task 9 — KerberCalendar and the /dev/calendar demo (§11.3.3).

   THE SHIFT BACKDROP IS A CELL BACKGROUND, not an element drawn over the grid, which is what makes
   scen 2 ("the backdrop covers neither the task's content, its text nor its interactive surface")
   true by construction rather than by z-index bookkeeping: DevExpress paints appointments in a layer
   above the time cells, so a task is always on top of whatever its cells are washed with, and the
   cell underneath stays as clickable as any other (scen 40).

   VERY LIGHT GREY, ON A DARK THEME (scen 3 — "vizualno sekundarna, vrlo svijetlosiva pozadina").
   A low-alpha white wash rather than a fixed grey: it reads as the same "slightly lifted" surface at
   any DevExpress cell colour underneath, and it cannot approach the contrast of the appointments,
   which is the whole point — the shift is context, the task is the content. */
.k-calendar { --k-shift-backdrop: rgba(255, 255, 255, 0.055); }
/* The class is REPEATED deliberately (0,3,0 rather than 0,2,0). A DevExpress time cell already
   carries its own colour classes — a week view stamps `dxbl-sc-time-cell dxbl-sc-dashed-cell
   dxbl-scheduler-disabled-color` on the very cells a shift decorates (measured against 25.2.9) — and
   a single-class rule of ours is not reliably stronger than theirs. Bumping specificity with our OWN
   class name rather than by naming one of theirs is what keeps this rule from breaking the moment
   DevExpress renames an internal class (scen 45/262). */
.k-calendar .k-calendar__shift.k-calendar__shift { background-color: var(--k-shift-backdrop); }
.k-calendar__dx { width: 100%; }
/* Scen 44: the same shape .k-map__unavailable has, so "the thing is not here, and why" reads
   identically wherever a W2 component degrades. Not absolutely positioned: unlike the map there is
   no canvas underneath to sit over — the scheduler simply is not rendered. */
.k-calendar__unavailable {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 240px;
    margin: 0;
    padding: 0 24px;
    text-align: center;
    color: var(--k-text-muted);
    background: var(--k-surface);
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-lg);
}
.k-calendar__task { height: 100%; padding: 2px 6px; overflow: hidden; }
/* PILOT 24.10. — the TASK BLOCK (mock web-16 `.tk` M:344 and web-12 `.tk` M:261; the same values as the shift
   calendar legend's `.k-shift-legend__swatch--task`): every drawn appointment carries `k-calendar__task`
   (KerberCalendar.TaskCssClass), and this rule is the block's fill — KerberCalendar's appointment template replaces
   DevExpress's `.dxbl-apt-bg`, the one element Fluent 25.2.9 paints, so without it a task in Zadaci › Kalendar and in
   the location's Kalendar is transparent and its duration cannot be seen. The context task of the shift calendar gets
   its fill here too and keeps only its own opacity. The class is repeated for the specificity reason the shift
   backdrop's rule above documents (0,3,0), and THE ORDER IS LOAD-BEARING: the web-17 block further down (the shift
   block, its exempt border and the context task, rules on k-shift-occurrence and k-shift-context-task) has the SAME
   specificity and comes LATER, so it wins and the shift stays the white block. Pinned by
   ShiftsTabWeb17CalendarTests.Pilot_Pravilo_zadatka_ispred_smjene_i_konteksta. */
.k-calendar .k-calendar__task.k-calendar__task {
    background: rgba(var(--k-accent-rgb), 0.28);
    border: 1px solid var(--k-accent);
    border-radius: 4px;
}
.calendar-demo { display: flex; flex-direction: column; gap: 12px; padding: 16px var(--k-page-gutter); }
.calendar-demo__actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.calendar-demo__status { margin: 0; color: var(--k-text-muted); }
/* K3-F N11b (ARH-C 051721, #3291) — THE SCHEDULER TOOLBAR's buttons ("Danas", the range button, ‹ ›) in 600
   with 0.5 px tracking, per mock web-16:319 `.wk .today { … font-size: 12px; font-weight: 600;
   text-transform: uppercase; letter-spacing: .5px; … }`. Measured v10 (TEST-WEB): under Fluent 400 / normal,
   BlazingDark 600 / 0.5px. Fluent 25.2.9 core.min.css (md5 81c5423fb482491e04814e73212c99df) draws both on the
   button itself, `.dxbl-btn { font-weight: var(--dxbl-btn-font-weight); letter-spacing:
   var(--dxbl-btn-letter-spacing) }` (0,1,0), and sets the weight VARIABLE for toolbar buttons at (0,6,0)
   (`.dxbl-toolbar>.dxbl-btn-toolbar .dxbl-toolbar-btn.dxbl-btn:not(…) { --dxbl-btn-font-weight:
   var(--dxds-font-weight-base-default) }`), so the PROPERTIES are set directly here: 0,3,0 beats 0,1,0 whatever
   the order; Fluent has no rule on `.dxbl-sc-toolbar` at all. ONLY the scheduler's toolbar
   (`dxbl-toolbar.dxbl-sc-toolbar` inside `dxbl-scheduler`; KerberCalendar is the one wrapper): the grid's
   „Izvoz ▾" (`.k-grid__export`, N9a) and every other DX toolbar keep their own. NOT carried over: the mock's
   `text-transform: uppercase` (not there under BlazingDark either — an existing departure) and its 12 px.
   The 16k-5 week bar below sets its own DANAS weight and tracking (same values) and comes later.
   Pin: FluentDxblVarsReadTests.N11b_traka_rasporeda_600_i_razmak_0_5px_samo_sc_toolbar;
   E2E: ThemeTokenSmokeTests.N11b_traka_kalendara_lokacije_600_i_0_5px_a_Izvoz_nepromijenjen. */
.dxbl-scheduler .dxbl-sc-toolbar .dxbl-btn { font-weight: 600; letter-spacing: .5px; }
/* web-16 16k-1 — KerberCalendar shared part A (mock web-16 k2 M:316-347; W-40, W-41 (2)). */
.k-calendar__caption { margin: 0 8px; font-size: 16px; font-weight: 600; color: var(--k-text); }
.k-calendar__legend { display: flex; align-items: center; gap: 14px; font-size: 12px; color: var(--k-text-muted); }
.k-calendar__subject { display: block; font-weight: 600; }
.k-calendar__detail { display: block; font-size: 11px; line-height: 1.2; }
.k-calendar__detail:empty { display: none; }
/* The shift's name, once per piece, top right of its cell (mock .sh i M:341). pointer-events: none
   keeps a press on the label a press on the cell — the label is never a target of its own. */
.k-calendar__cell { display: flex; justify-content: flex-end; align-items: flex-start; height: 100%; }
.k-calendar__shift-label {
    padding: 2px 5px 0 0;
    font-size: 10px;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    white-space: nowrap;
    color: rgba(var(--k-white-rgb), 0.35);
    pointer-events: none;
}
/* web-16 16k-3 — KerberCalendar dark grid (mock web-12 M:245-268, web-16/17 M:329-351; W-40). Everything
   scoped to .k-calendar--dark is the opt-in grid; the host-clock marks (past/today/now) work without it.
   The dxbl-* classes named here are DevExpress's own markup, not a contract: measured in 25.2.9 and pinned
   by KerberCalendar_16k3_DX_klase_postoje. */
/* T1 — the surface and the lines (mock .cal M:245, .col M:254). The time cells go transparent so the
   shift backdrop (0,3,0 above) still paints on top of the surface. */
.k-calendar--dark .k-calendar__dx { background-color: var(--k-surface); border: 1px solid var(--k-border-strong); border-radius: var(--k-radius); }
.k-calendar--dark .dxbl-sc-time-cell { background-color: transparent; border-color: var(--k-border); }
/* K3-F (#3553 e2e): Fluent 25.2.9 gives every body td `border-color: inherit` (#767676 from the table) with
   `.dxbl-scheduler .dxbl-sc-table>tbody>tr>td` (0,2,3), which out-ranks the rule above (0,2,0). The border alone
   goes up, our class three times (0,4,0); the background stays at 0,2,0 so the shift backdrop (0,3,0) still wins. */
.k-calendar--dark.k-calendar--dark.k-calendar--dark .dxbl-sc-time-cell { border-color: var(--k-border); }
.k-calendar--dark .dxbl-sc-date-hr { border-color: var(--k-border); border-bottom-color: var(--k-border-strong); }
/* T2 — the day header "Pon / 7.9." (mock .days M:246-250). DevExpress pads its header cell itself (measured in
   Fluent 25.2.9 core.min.css: `.dxbl-scheduler .dxbl-sc-dayview .dxbl-sc-date-hr{padding:4px 12px 3px 12px}` at
   0,3,0, every td 4px; BlazingDark .25rem + .4725rem left), which would
   double ours (REV-D U4 (5)); our own class repeated (0,3,0, later in the cascade) takes it to 0. DevExpress's
   own "today" bar is client-side (not in bUnit's markup, measured 16k-3 T0.2) — NEMJERENO until the browser. */
.k-calendar--dark.k-calendar--dark .dxbl-sc-date-hr { padding: 0; }
.k-calendar__day {
    display: flex; flex-direction: column; align-items: flex-start; padding: 8px 10px;
    font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; color: var(--k-text-label);
}
.k-calendar__day-name { display: block; }
.k-calendar__day-date { display: block; font-size: 16px; font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--k-text); }
.k-calendar__day--today,
.k-calendar__day--today .k-calendar__day-date { color: var(--k-accent-soft); }
/* T3 — host-clock washes as IMAGE layers, so a shift's background-color survives underneath. The raw mock
   value lives HERE ONLY, as a calendar-scoped property beside --k-shift-backdrop (REV-D 000337 U2): no theme
   token exists for it. */
.k-calendar {
    --k-calendar-past-wash: rgba(0, 0, 0, 0.12);                  /* mock web-12 M:256 (.col.past) */
    --k-calendar-today-wash: rgba(var(--k-accent-rgb), 0.03);     /* mock web-12 M:255 (.col.today) */
}
.k-calendar .k-calendar__past.k-calendar__past { background-image: linear-gradient(var(--k-calendar-past-wash), var(--k-calendar-past-wash)); }
.k-calendar .k-calendar__today.k-calendar__today { background-image: linear-gradient(var(--k-calendar-today-wash), var(--k-calendar-today-wash)); }
/* T4 — the now line and its dot (mock .now M:267-268), at a sixth of its cell; never an inline style. Our own
   class is REPEATED (0,4,1): DevExpress's client-side today bar `.dxbl-scheduler .dxbl-sc-today.dxbl-sc-time-cell::before`
   is 0,3,1 and would otherwise restyle the dot on today's cells. The line sits in the cell layer, i.e. UNDER
   appointments (mock z-index 3 draws it over) — named deviation, ARH-C Q4. */
.k-calendar .k-calendar__now.k-calendar__now { position: relative; }
.k-calendar.k-calendar .k-calendar__now.k-calendar__now::after { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px; background: var(--k-danger); pointer-events: none; }
.k-calendar.k-calendar .k-calendar__now.k-calendar__now::before { content: ""; position: absolute; left: -4px; top: -3px; width: 8px; height: 8px; border-radius: 50%; background: var(--k-danger); pointer-events: none; }
.k-calendar.k-calendar .k-calendar__now--at-0.k-calendar__now--at-0::after { top: 0; }
.k-calendar.k-calendar .k-calendar__now--at-1.k-calendar__now--at-1::after { top: calc(100% / 6); }
.k-calendar.k-calendar .k-calendar__now--at-1.k-calendar__now--at-1::before { top: calc(100% / 6 - 3px); }
.k-calendar.k-calendar .k-calendar__now--at-2.k-calendar__now--at-2::after { top: calc(100% * 2 / 6); }
.k-calendar.k-calendar .k-calendar__now--at-2.k-calendar__now--at-2::before { top: calc(100% * 2 / 6 - 3px); }
.k-calendar.k-calendar .k-calendar__now--at-3.k-calendar__now--at-3::after { top: 50%; }
.k-calendar.k-calendar .k-calendar__now--at-3.k-calendar__now--at-3::before { top: calc(50% - 3px); }
.k-calendar.k-calendar .k-calendar__now--at-4.k-calendar__now--at-4::after { top: calc(100% * 4 / 6); }
.k-calendar.k-calendar .k-calendar__now--at-4.k-calendar__now--at-4::before { top: calc(100% * 4 / 6 - 3px); }
.k-calendar.k-calendar .k-calendar__now--at-5.k-calendar__now--at-5::after { top: calc(100% * 5 / 6); }
.k-calendar.k-calendar .k-calendar__now--at-5.k-calendar__now--at-5::before { top: calc(100% * 5 / 6 - 3px); }
/* T5 — the hour column "01:00", right-aligned on its line (mock .hours M:253). DevExpress 25.2 has no ruler
   template; these are its own classes, pinned by KerberCalendar_satnica_hh_mm. DevExpress hides the compact
   text with `.dxbl-scheduler .dxbl-sc-hour-min-text-compact` (0,2,0, Fluent 25.2.9 core.min.css as BlazingDark); ours is
   0,2,0 too and loads after it, so the cascade order decides — measured in the browser by the E2E smoke. */
.k-calendar--dark .dxbl-sc-hour-text { display: none; }
.k-calendar--dark .dxbl-sc-minute-cell { color: transparent; }
.k-calendar--dark .dxbl-sc-hour-min-text-compact {
    display: inline-block; transform: translateY(-50%);
    font-size: 11px; color: var(--k-text-muted); font-variant-numeric: tabular-nums;
}
/* K3-F (#3553 e2e): Fluent 25.2.9 sizes and colours the span itself with
   `.dxbl-scheduler .dxbl-sc-table tr>td.dxbl-sc-hour-cell>span` (0,3,3: 14px, #fffffe), and with the same path
   under the conditional `dxbl-hour-time-scale` table class (0,4,3); the rule above (0,2,0) loses to both. Our
   class four times (0,5,0) out-ranks them, no important flag. */
.k-calendar--dark.k-calendar--dark.k-calendar--dark.k-calendar--dark .dxbl-sc-hour-min-text-compact { font-size: 11px; color: var(--k-text-muted); }
/* C4 — the hour column as the mock draws it (web-12 M:246/M:251 `56px`, M:253 `.hours span`, M:254 hour lines
   only), measured in the browser (16k-3 C4 T0; E2E Web12_k1_C4a…C4e). DevExpress's ruler is TWO tds per row —
   the hour td (rowspan 2, width var(--dxbl-scheduler-time-cell-width)) and a minute td whose 1 px right border is
   the line before the first day — and its own rule for both is `.dxbl-scheduler .dxbl-sc-table tr>td.…` (0,3,2),
   so the minute td is out-ranked by our class repeated three times (0,4,0); never !important.
   Width: the hour td 55 px through DevExpress's own property + the minute td reduced to its 1 px line = 56 px,
   and the empty header corner (border-box, its 1 px border included) = 56 px, so the days stay aligned.
   K3-F F2: Fluent 25.2.9 names the property `--dxbl-scheduler-time-cell-width` (BlazingDark's
   `--dxbl-scheduler-hour-cell-width` is read by no Fluent rule) and declares it on `.dxbl-scheduler` (0,1,0,
   = var(--dxds-spacing-300) ≈ 26 px) — the element that carries our k-calendar__dx, so our two classes (0,2,0)
   outrank it. Fluent also places the sticky minute td at `left: var(--dxbl-scheduler-time-cell-width)` (= the
   hour td's width, as BlazingDark did) and the header corner at twice it, which the 56 px rule below beats. */
.k-calendar--dark .k-calendar__dx { --dxbl-scheduler-time-cell-width: 55px; }
.k-calendar--dark.k-calendar--dark.k-calendar--dark .dxbl-sc-minute-cell { width: 0; padding: 0; overflow: hidden; }
.k-calendar--dark.k-calendar--dark .dxbl-sc-time-rulers-caption { width: 56px; }
/* The label hangs on its hour line, 8 px from the column line: absolutely placed in the hour td (DevExpress makes
   that td sticky, i.e. positioned), whose top IS the line — the mock places each span's top on its line. */
.k-calendar--dark.k-calendar--dark .dxbl-sc-hour-min-text-compact { position: absolute; top: 0; right: 8px; }
/* W-00: the mock's ruler starts at 01:00 (web-12 M:302 — no "00:00"); hanging on line 0 it would sit half above
   the grid. The first row of the body is 00:00 (the only `tr:first-child` that holds an hour td) — true only while the week view sets no VisibleTime/ShowWorkTimeOnly;
   with either, row one is no longer 00:00 and the E2E pin (first VISIBLE label = 01:00, by content) fails loudly. */
.k-calendar--dark.k-calendar--dark tr:first-child > .dxbl-sc-hour-cell .dxbl-sc-hour-min-text-compact { display: none; }
/* Hour lines only: DevExpress's half-hour line is the dashed bottom border of the :00 cell — made transparent
   (not removed), so no row changes height; the hour line (bottom of the :30 cell) keeps T1's --k-border.
   K3-F (#3553 e2e): Fluent 25.2.9 colours that line with `.dxbl-scheduler .dxbl-sc-table>tbody>tr>td.dxbl-sc-dashed-cell`
   (0,3,3, #505150); our class four times (0,5,0) out-ranks it and T1's time-cell border (0,4,0), whatever the order. */
.k-calendar--dark.k-calendar--dark.k-calendar--dark.k-calendar--dark .dxbl-sc-dashed-cell { border-bottom-color: transparent; }
/* N-a/N-b/N-c — the hour column as the mock draws it (web-12 M:247-254): no background of its own (it shows the
   calendar surface), no horizontal lines, and ONE continuous vertical line at its boundary with Monday in --k-border
   (mock `.cal .col { border-left }`, header `.days div { border-left }`). DevExpress paints its ruler tds
   (`dxbl-sc-time-scale-cell` = exactly its hour + minute tds) and the header corner with
   var(--dxbl-scheduler-background-color) at (0,3,2) / (0,3,0), draws their borders in its own border colour, and
   gives no day td a left border (measured, 16k-3 C4 hold A) — so the line stays where DevExpress draws it, on the
   minute td's right (present in every row, 1 px wide since C4) and the corner's right, recoloured; our class three
   times (0,4,0), on those cells only — DevExpress's variables are left alone. Opaque surface, not transparent: the
   tds are sticky and must still cover the days when the grid scrolls sideways. */
.k-calendar--dark.k-calendar--dark.k-calendar--dark .dxbl-sc-time-scale-cell { background-color: var(--k-surface); border-bottom-color: transparent; }
.k-calendar--dark.k-calendar--dark.k-calendar--dark .dxbl-sc-minute-cell { border-right-color: var(--k-border); }
.k-calendar--dark.k-calendar--dark.k-calendar--dark .dxbl-sc-time-rulers-caption { background-color: var(--k-surface); border-bottom-color: transparent; border-right-color: var(--k-border); }
/* N-d — the day header's lines are the frame's colour (mock .cal { border } M:245, .days { border-bottom } M:246,
   both --border-strong). DevExpress draws the header table's own top and bottom border (full width, through the
   corner) in its border colour with `.dxbl-scheduler .dxbl-sc-dayview .dxbl-sc-headers-scroll-area
   .dxbl-sc-headers-container .dxbl-sc-table.dxbl-sc-horizontal-view` (0,6,0, measured 16k-3 N-d); the same path
   under our two classes (0,7,0) recolours exactly that table — no !important, DevExpress's variables untouched. */
.k-calendar--dark .k-calendar__dx .dxbl-sc-dayview .dxbl-sc-headers-scroll-area .dxbl-sc-headers-container .dxbl-sc-table.dxbl-sc-horizontal-view { border-top-color: var(--k-border-strong); border-bottom-color: var(--k-border-strong); }

/* web-16 16k-2 — the calendar becomes the W-20 card's positioned ancestor ONLY when a host asked for cards
   (KerberCalendar.Callout); the card itself is the map's .k-map__callout, unchanged (DOPUNA 3 Q16-4). */
.k-calendar--positioned { position: relative; }

/* web-16 16k-5 — KerberCalendar week bar (mock web-16 M:317-320, web-12 M:234-237, web-17 M:317-320) */
/* ‹ DANAS › as outlined buttons (mock .wk .nav M:318, .wk .today M:319), only under .k-calendar--weekbar, which
   KerberCalendar sets ONLY with OutlinedWeekBar inside its own toolbar. Every selector reaches the buttons through
   OUR data-k-calendar-nav attribute (it lands on DevExpress's <button>): this block names no DevExpress class and
   no --dxbl-* variable, so a DevExpress rename cannot silently unstyle it and nothing outside this bar is touched
   (REV-D2 t.2). Our class is REPEATED (0,3,0) to stand against DevExpress's button rules; whether that is enough
   is the browser's verdict (E2E computed style) — if not, the class repeats once more, never !important.
   The mock's `font-size: 16px` on .nav sizes a "‹" glyph; with DevExpress's own chevron (ARH-C O2) it has nothing
   to size, so it is not carried over. The caption (.wk .lbl M:320) is .k-calendar__caption above; inside this bar
   only its start margin changes — see the caption rule at the end of this block (L1). */
.k-calendar--weekbar.k-calendar--weekbar [data-k-calendar-nav="previous"],
.k-calendar--weekbar.k-calendar--weekbar [data-k-calendar-nav="next"] {
    width: 32px; height: 32px; padding: 0;
    border: 1px solid var(--k-border-strong); border-radius: var(--k-radius-md);
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--k-text-label);
    /* M:317 `.wk { gap: 6px }`: the gap DEPENDS on DevExpress's left margin on non-first toolbar button items
       (3.5 px, measured: CI 37298397820, TEST-WEB CDP 141023), so the spacing goes on the END edge — that DX rule
       (about 0,8,0) outranks ours on the start edge, and has no rival on the end edge. Each of ‹ DANAS › adds
       2.5 px there: DX 3.5 + 2.5 = mock 6 for ‹–DANAS and DANAS–›. DX's 3.5 does NOT reach the caption, which is
       a templated toolbar item, not a button (TEST-WEB CDP 141023; CI 37310007161 measured › to caption 10.5 =
       2.5 + 8), so the caption rule at the end of this block (L1) gives the caption 11.5 px on its start edge:
       ›'s 2.5 + 11.5 = mock 6 + 8 = 14 (M:317 + M:320 `.lbl { margin: 0 8px }`). The E2E pin
       Web16_k5_Izgled_gumba_po_mocku measures all three gaps (6, 6, 14, each ±1), so a DX change fails it. */
    margin-inline-end: 2.5px;
}
.k-calendar--weekbar.k-calendar--weekbar [data-k-calendar-nav="today"] {
    height: 32px; padding: 0 12px;
    border: 1px solid var(--k-border-strong); border-radius: var(--k-radius-md);
    display: inline-flex; align-items: center;
    font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: var(--k-label-tracking);
    color: var(--k-text-label);
    margin-inline-end: 2.5px; /* M:317 gap 6, see the ‹ › rule above */
}
/* The word only (mock M:444 "Danas", no icon): DevExpress's today icon is swapped for this class. */
.k-calendar--weekbar.k-calendar--weekbar .k-calendar__nav-icon-none { display: none; }
/* The mock draws no states; the keyboard focus stays visible with the shell's own ring (the global
   :focus-visible is 0,1,0 and a DevExpress button rule could outrank it). */
.k-calendar--weekbar.k-calendar--weekbar [data-k-calendar-nav]:focus-visible {
    outline: var(--k-focus-ring); outline-offset: var(--k-focus-ring-offset);
}
/* L1 (REV-D 144706) — › to the caption, mock 6 (M:317) + 8 (M:320) = 14. Two dependencies, both measured: DX does
   not space the templated caption item (TEST-WEB CDP 141023, CI 37310007161: 10.5), and › carries
   margin-inline-end 2.5 (rule above). So 11.5 = 8 (M:320) + 6 (M:317) − 2.5 (margin-inline-end on ›). Only the
   start edge and only under the week bar: 16k-1's caption keeps its 8 px. If DX ever starts spacing templated
   items, › to caption becomes 17.5 and the E2E pin (14 ±1) fails. */
.k-calendar--weekbar.k-calendar--weekbar .k-calendar__caption { margin-inline-start: 11.5px; }

/* W2 Task 10 — KerberMapGrid and the /dev/mapgrid demo (§11.3.2).

   THE MODE IS A LAYOUT, and it is expressed as one: hybrid puts the two projections side by side and
   the other two give the whole width to whichever half is shown (scen 152, 153). Each half is a grid
   AREA rather than a floated block, so switching modes moves no DOM around the one that stays — which
   is the same reason a hybrid → map-only switch is not a new map render (scen 248). */
.k-mapgrid { display: grid; gap: 12px; }
.k-mapgrid--hybrid { grid-template-columns: minmax(320px, 1fr) minmax(320px, 1fr); }
/* #4283: a column can be dragged wider than the table. A plain `1fr` track has an automatic minimum and would
   grow to the table's width (and the page with it); minmax(0, 1fr) keeps the track and lets the grid scroll. */
.k-mapgrid--map,
.k-mapgrid--table { grid-template-columns: minmax(0, 1fr); }
/* The switcher belongs to the component, not to either projection, so its row spans both columns. #4220 v1.1
   (vlasnik 16.10., rješenje B as the owner saw it on the frame; W-68): without a head, the switcher and „Izvoz ▾"
   share that row in ONE wrapper, KerberMapGrid's .k-mapgrid__top — the export RIGHT BESIDE the switcher (gap 8px),
   not at the row's far end. A wrapper because KerberSegment has no slot for extra content and the switcher's width
   depends on the culture; the inner table draws no toolbar row of its own any more (KerberGrid ShowBar=false), so
   the map and the table auto-place into the row under the wrapper and their tops are one line. The switcher's own
   box gets no rule that lays its items out (U1, KerberSegmentCssTests: no gap/display on the consumer's box class);
   `flex: none` only keeps its width beside the export (and gives the placement hook a rule, WebStyleAuditTests). */
.k-mapgrid__top { grid-column: 1 / -1; display: flex; align-items: center; gap: 8px; }
/* The export keeps its own width beside the switcher (the toolbar measures itself; it must not be squeezed). */
.k-mapgrid__export { flex: none; }
.k-mapgrid__modes { flex: none; }
/* web-05 A2 — the map-grid's HEAD (the shell's toolbar row, KerberGridBar) and the row under it span both
   columns for the switcher's reason: they belong to the component, not to either projection. */
.k-mapgrid > .k-grid__bar,
.k-mapgrid > .k-grid__below { grid-column: 1 / -1; }
/* The host's search box in that head: `.k-grid .k-grid__search` does not reach it (the head is not inside a
   .k-grid), so it gets the same width and floor here — web-00 :145 `.search { width: 280px }`. Its focus ring
   is named next to the grid's own, in the Task 9 block above (#3612 F2). */
.k-mapgrid > .k-grid__bar .k-grid__search { width: 280px; min-width: 220px; }
/* web-05 A1 (W-24) — THE MARKED ROW: one click on a row marks it (KerberGrid.IsRowMarked puts
   .k-grid__row--marked on its <tr>). As the mock draws `tr.sel` (web-05:110-111): an accent wash over
   the cells and a 3 px accent bar on the first one — the bar is what keeps the mark from being colour
   alone. Cell-level, like §10.1's error rows, because DevExpress paints the cells. */
.k-grid__dx tr.k-grid__row--marked > td {
    background: rgba(var(--k-accent-rgb), 0.14);
}
.k-grid__dx tr.k-grid__row--marked > td:first-child {
    box-shadow: inset 3px 0 0 var(--k-accent);
}
/* Under ~900 px the two halves stack instead of squeezing a map into a strip. */
@media (max-width: 900px) {
    .k-mapgrid--hybrid { grid-template-columns: minmax(0, 1fr); }
}
.mapgrid-demo { display: flex; flex-direction: column; gap: 12px; padding: 16px var(--k-page-gutter); }
.mapgrid-demo__actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.mapgrid-demo__status { margin: 0; color: var(--k-text-muted); }
.mapgrid-demo__heading { margin: 8px 0 0; font-size: 16px; }
.mapgrid-demo__maps { display: grid; grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); gap: 16px; }
.mapgrid-demo__map h3 {
    font-size: 14px;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-text-muted);
    margin: 0 0 8px;
}

/* ── Notifications menu (§10.1) — W3 Task 5 ──────────────────────────────────────────────────────
   Replaces W1's hand-rolled /log table wholesale: the view is now a KerberGrid, so the only chrome
   left is the page frame and the §11.0 period selector — the same recipe the Tasks menu uses, so the
   two menus are visibly one product. */
.k-notifications {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px var(--k-page-gutter);
}
.k-notifications__loading { color: var(--k-text-muted); }

/* §11.0 time-range selectors — the backwards variant (Current / Last month / From-To). On the
   Notifications menu they sit in the shell bar's ToolbarEnd (web-07 E1, Task 10a); the worker tab and
   the admin selector still draw them as a row of their own above the grid. */
.k-notifications__period {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.k-notifications__period-dates { display: flex; align-items: center; gap: 8px; margin-left: 8px; }
/* #4356: the From/To editors before the tenant's day is known — laid out but not shown. `visibility`, never
   `display`: the bar is right-aligned and the holder stands right of the buttons, so a holder left out (or
   display:none) would shift the buttons left the moment the dates arrive. */
.k-notifications__period-dates--pending { visibility: hidden; }
.k-notifications__period-label {
    color: var(--k-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-size: 12px;
}
.k-notifications__date { width: 150px; }
/* Focus ring on the EDITOR rather than its inner <input> — the recipe the grid's search box and the
   Tasks menu's own date pair use, for the reason documented there. */
.k-notifications__date:has(:focus-visible) {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
    border-radius: var(--k-radius-sm);
}
.k-notifications__date input:focus-visible { outline: none; }

/* web-07 #12 (P8; mock k1 :122 `<span class="live"><i></i>Živo</span>` ending the chip row): THE LIVE MARK after
   the chips in the shell's row below the bar (ToolbarBelow), Current period only. The page's OWN rule, deliberately
   not a member of web-08's `.k-wd__live` selector list (WorkingDayPageRenderTests pins that list and forbids
   `margin-left` on every rule naming it) — two copies of the same mock values, named; a shared shell `.k-live` is
   an FYI for after the pilot. The values are the mock's CASCADE in its chip row: `.live` (:58 inline-flex, center,
   gap 6px, --success, 12/600, uppercase, .5px), overridden by `.chips span` (:52, specificity 0,1,1 over 0,1,0:
   height 30px; padding 0 12px; 1px --border-strong border; radius 15px; gap 7px; color --label), pushed right by
   `.chips .live` (:57 margin-left: auto) — the same reading web-08's chip row got (review 08D-1 m-1). Tokens:
   --border-strong → --k-border-strong, --label → --k-text-label, --success → --k-success. The dot (:59) blinks
   with web-08's `k-wd-blink` (:60 `@keyframes blink { 50% { opacity: .3; } }`), reused, not copied. */
.k-notifications__live {
    display: inline-flex;
    align-items: center;
    height: 30px;
    padding: 0 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: 15px;
    gap: 7px;
    color: var(--k-text-label);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .5px;
    margin-left: auto;
}
.k-notifications__live i {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--k-success);
    animation: k-wd-blink 1.4s ease-in-out infinite;
}
/* Reduced motion: the dot stops (same specificity, later in the sheet); the success colour still says „live". */
@media (prefers-reduced-motion: reduce) {
    .k-notifications__live i { animation: none; }
}

/* THE WHOLE ROW IS THE LINK (scen 106) — every cell is an anchor to the same target, so activating
   the row's ordinary surface navigates. It has to look like the rest of the grid, not like a page
   full of underlined links, so the anchor inherits its colour and fills its cell; the pointer and
   the focus ring are what say it is clickable. A row with no target renders a <span> instead and
   therefore gets none of this (ruling R8). */
.k-notification-cell {
    display: flex;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
    color: inherit;
    text-decoration: none;
}
.k-notification-cell--link { cursor: pointer; }
.k-notification-cell--link:hover .k-notification-cell__text { text-decoration: underline; }
.k-notification-cell--link:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
    border-radius: var(--k-radius-sm);
}
/* …AND THE CELL'S PADDING IS PART OF THE ROW (scen 106, W3 Task 10 — measured in a browser).
   An anchor lays itself out inside the <td>'s CONTENT box, so DevExpress's own cell padding (3.5 px
   × 5.25 px in the shipped theme) was a dead frame around every link: a click a pixel inside the cell
   border landed on the <td> and nothing happened, on a row whose whole point is that clicking it
   navigates. Verified with elementFromPoint before and after.
   AN OVERLAY RATHER THAN ZEROING THE PADDING, deliberately: the padding is the theme's spacing and
   removing it would re-space every notification cell, and hard-coding those two measurements here
   would silently drift on the next DevExpress upgrade. The link's own box stays exactly where it is —
   the ellipsis and the baseline alignment depend on it — and an inert pseudo-element is stretched
   over the cell's whole padding box instead, which is what the click then lands on (a click on
   ::after is a click on its element). The <td> is given a positioning context for it, and only where
   there IS a link: a row with no target (ruling R8) renders a <span> and gets none of this. */
.k-grid__dx td:has(> .k-notification-cell--link) { position: relative; }
.k-notification-cell--link::after { content: ""; position: absolute; inset: 0; }
.k-notification-cell__text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* §10.1's error text, beside the action rather than instead of it (scen 68/70) — on the tabs, and in a menu cell
   without a second line; the web-07 #26 rule below moves it under the action on the menu. */
.k-notification-cell__message { color: var(--k-danger); font-size: 12px; }
/* #1343 W-36 T12 — the second line of a manual entry and the „riješeno ručno" pill of a manually resolved
   alarm 2, as the approved mock web-07 kadar 4 draws them (docs/design/mocks/web-07-obavijesti.html :79-82:
   .act .pill, .pill.late, .act small). Since web-07 #25 (PR 1b) the same line carries, on the Notifications menu,
   EVERY row type's context (NotificationContextLine; the manual line keeps its rows); the location and worker tabs
   still draw only the manual line, until PR 2. The line wraps under the action only in a cell that HAS one
   (--two-line), so every other cell keeps its one-line ellipsis. */
.k-notification-cell--two-line { flex-wrap: wrap; row-gap: 2px; }
.k-notification-cell__context {
    flex-basis: 100%;
    color: var(--k-text-muted);
    font-size: 12px;
    white-space: normal;
    overflow-wrap: anywhere;
}
/* web-07 #26 (plan DOPUNA 2 U4, ARH-C: the error message STAYS, spec §10.1 „highlighted in red with a message") —
   on the Notifications menu the message is its own line UNDER the action and above the second line, in the mock's
   second-line position (docs/design/mocks/web-07-obavijesti.html :82 `.act small { display: block }`), red, 12 px.
   SCOPED TO THE PAGE'S ROOT (ruling R9-1): the location and worker tabs render --two-line too (their manual rows)
   and keep the message beside the action until PR 2 gives them the same rule. On its own line it wraps the way
   the second line does (the two declarations of .k-notification-cell__context above), never out of the cell.
   TWO NAMED DEVIATIONS from U4's literal „a message is its own line" (Task 9), both unreachable today because no
   writer of an IsError row fills Message (AlarmRaiser.cs:325-340; DeviceEventsController.cs:105-118): (a) a message on a row WITHOUT a second line
   stays beside the action — this selector needs --two-line; (b) a row with a message AND a pill wraps the pill
   to the line under the message, not beside the action — the cell's order is text, message, pill, context
   (NotificationCell.razor), and the message takes the whole line. */
.k-notifications .k-notification-cell--two-line .k-notification-cell__message {
    flex-basis: 100%;
    color: var(--k-danger);
    font-size: 12px;
    white-space: normal;
    overflow-wrap: anywhere;
}

/* W-28, VLASNIK 25.9. Q16 = b — THE ACTION COLUMN IS COLOURED AT REST, the one exception to "the anchor
   inherits its colour" above. web-decisions.md W-28: "radnja kao link stupac (W-24; alarmi crveno,
   ostalo cyan kao svaki link stupac …)", and the owner confirmed on 25.9. that W-24's quiet link
   (colour only on hover) does NOT apply here. The mock (docs/design/mocks/web-07-obavijesti.html,
   kadar 1 and 2) paints `table.g td a` in --primary-soft and `tr.alarm td.act a` in --danger; the
   theme's names for those are --k-accent-soft and --k-danger, and --k-accent-soft is also what every
   other in-grid link column already uses (.k-location-incidents__link, .k-worker-incidents__link).
   ONLY THE ACTION CELL: the other five cells stay `inherit`, and every cell stays an anchor, so the
   whole row is still the link (scen 106) — NotificationCell adds these two classes to that one column.
   ALARM means NotificationType.Alarm (the mock's tr.alarm), not IsError. An ERROR row is another
   matter and keeps winning: the .k-row--error rules below target .k-notification-cell__text itself at
   higher specificity, so an error row's action stays red whatever this rule says — which is also why
   a real alarm (the raiser writes it IsError) reads red twice over, never cyan.
   The hover underline is the rule above, unchanged. Specificity rather than order decides: two
   classes beat `.k-notification-cell { color: inherit; }`, the alarm's three beat the cyan's two, and
   the error rows' `.k-grid__dx tr.k-row--error …` (three classes and an element) beats both. */
.k-notification-cell--link.k-notification-cell--action { color: var(--k-accent-soft); }
/* SA view (ARH-C 061425, 121625): an alarm's action that leads nowhere (the <span>, ruling R8) carries only
   --alarm beside the column marker --action-col, and looks like the alarm link — red here, 600 below (mock
   web-07 :78). It never gets --action, so the cyan rule above stays a link's. */
.k-notification-cell--link.k-notification-cell--action.k-notification-cell--alarm,
.k-notification-cell--action-col.k-notification-cell--alarm {
    color: var(--k-danger);
}
/* web-07, the rest of what the approved mock says about these two columns (architect 25.9.):
   the action link's weight — `table.g td a { font-weight: 500 }`, `tr.alarm td.act a { … 600 }` —
   set on the label rather than the anchor, so the error message beside it keeps its own weight;
   and the TYPE cell coloured by type — `.ty.al` --danger, `.ty.inc` --warn, `.ty.task`
   --primary-soft, `.ty.info` --muted, i.e. --k-danger / --k-warning / --k-accent-soft /
   --k-text-muted. An error row's .k-row--error rule repaints only its action cell since
   web-07 #29 (P-v1 po mocku :78), so the type colour holds on an error row too. */
.k-notification-cell--link.k-notification-cell--action .k-notification-cell__text { font-weight: 500; }
.k-notification-cell--link.k-notification-cell--action.k-notification-cell--alarm .k-notification-cell__text,
.k-notification-cell--action-col.k-notification-cell--alarm .k-notification-cell__text {
    font-weight: 600;
}
.k-notification-cell.k-notification-cell--type-alarm { color: var(--k-danger); }
.k-notification-cell.k-notification-cell--type-incident { color: var(--k-warning); }
.k-notification-cell.k-notification-cell--type-task { color: var(--k-accent-soft); }
.k-notification-cell.k-notification-cell--type-info { color: var(--k-text-muted); }
/* web-07 #20 (DIZ-3 web-07 1a, mock :75-77 `.ty`, `.ty svg`): the TYPE cell's uppercase 12px label
   and its icon are now taken as well. The uppercase is CSS only — the label text stays the resource
   (NotificationLabels.TypeText), so no translation is rewritten in capitals. Centred rather than the
   cell's usual baseline (the mock's `.ty { align-items: center }`): an SVG's baseline is its bottom
   edge, so on a baseline the icon would sit above the text. NotificationCell draws the icon on the
   type column only; it inherits the type colour above through stroke="currentColor". */
.k-notification-cell[class*="--type-"] {
    align-items: center;
    gap: 7px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .5px;
}
.k-notification-cell__icon { width: 16px; height: 16px; flex: none; }

/* P-v1 = B, the OWNER's decision (1.10. 20:40:31, #17), as the mock draws it — web-07 :78
   `tr.alarm td.act a`: ONLY the action is red; every other cell stays plain, with no row background.
   .k-row--error stays the row's MARKER (the E2E suite looks for it); on an alarm row the action's red
   already comes from --alarm (:980-982), and on an error row that is not an alarm (only the W3 test
   seed) from this rule. Fix round 1 (R9): the rule keys on the COLUMN marker --action-col, not on the
   --action tone — NotificationCell puts it on both branches, so an action that leads nowhere (the
   <span> in the super admin's System view) stays red too. The error text beside the action is red on
   its own (.k-notification-cell__message above), so it is not listed here. */
.k-grid__dx tr.k-row--error .k-notification-cell--action-col,
.k-grid__dx tr.k-row--error .k-notification-cell--action-col .k-notification-cell__text {
    color: var(--k-danger);
}

/* web-07 #31, PR 2a Task 20 (Q-2-2, ARH-C 150347) — THE SHELL'S LIVE-ARRIVAL MARK (Grid/KerberRowFreshMark):
   the mock's cyan wash and first-cell bar (mock :69-70 `tr.new td` /
   `tr.new td:first-child`, mock k1 `tr.new`), drawn by an ELEMENT inside every cell of the row instead of a
   class on its <tr>. The consumer renders that element with @key = the row's key, so when the row in a cell
   changes Blazor inserts a NEW element, and a new element starts its animation from the beginning: ONE
   keyframe set, no parity (DIZ-1 F1).
   AN OVERLAY, NOT THE <td>'S OWN BACKGROUND: an animation on `td:has(.k-grid__fresh)` would belong to the
   <td>, which DevExpress keeps across a live Reload(), so it would not restart for the next row. The mark is
   an inert layer over the cell's padding box instead. The cell gets a positioning context only while it holds
   one (the precedent: `.k-grid__dx td:has(> .k-notification-cell--link)`), and `isolation` makes the cell its
   own stacking context, so the layer's z-index: -1 puts it ABOVE the cell's background and BELOW its text —
   where the mock's `tr.new td` background is. It takes no clicks (the row's link underneath keeps them) and
   is aria-hidden in the markup. NOT FOR CELLS OF FIXED (sticky) DX COLUMNS (K-3 DIZ-1 P2): the cell's
   `position: relative` would override their sticky position — a consumer with fixed columns is a new K-3.
   THE TIME IS RowFreshness's (6 s on the Notifications page, from the ARRIVAL); the animation only fades
   inside it. THE 6s BELOW AND THE CONSUMER'S freshFor MUST BE EQUAL (K-3 DIZ-1 P1): today the one consumer is
   the Notifications page with 6 s, and a pin holds the two equal; a consumer with another duration is a new K-3.
   NO `forwards` and NO static paint: when the fade ends the layer is transparent and the
   grid's hover shows through. No inline animation-delay (CSP): a mark re-inserted for a row that came back
   into view runs from the start — the named deviation Q-2-3.
   ONE KEYFRAME SET PER LOOK — the wash, and the wash with the edge bar — named after the shell's mark. These
   are the only keyframes of the live-arrival mark: the row-class mark and its parity copies left with Task 20,
   so nothing else in the theme paints a fresh row. */
.k-grid__dx td:has(.k-grid__fresh) {
    position: relative;
    isolation: isolate;
}
.k-grid__fresh {
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    animation: k-grid-fresh-wash 6s ease-out;
}
/* The row's first cell: the 3 px bar on its left edge (KerberRowFreshMark.Edge). */
.k-grid__fresh--edge { animation-name: k-grid-fresh-edge; }
@keyframes k-grid-fresh-wash {
    from { background: rgba(var(--k-accent-rgb), .07); }
    to { background: transparent; }
}
@keyframes k-grid-fresh-edge {
    from { background: rgba(var(--k-accent-rgb), .07); box-shadow: inset 3px 0 0 var(--k-accent-soft); }
    to { background: transparent; box-shadow: none; }
}
/* Reduced motion: no fade; with no static paint the mark is then simply invisible (the .k-walker precedent). */
@media (prefers-reduced-motion: reduce) {
    .k-grid__fresh { animation: none !important; }
}

/* web-07 (mock :74 `td.t { font-variant-numeric: tabular-nums; }`): the TIME column — on the menu
   and on both notification tabs (NotificationCell.IsTimeColumn) — sets every digit to the same
   width, so the moments line up digit under digit. */
.k-notification-cell--time { font-variant-numeric: tabular-nums; }

/* ── Tasks menu (§10.2) — W4 Task 2 ──────────────────────────────────────────────────────────────
   Same chrome recipe /dev/grid uses: a page gutter and the grid filling what is left — the title, the
   period and the Create control are the grid's own toolbar row since web-02 02a (no header row).
   The grid itself needs no new rules — .k-grid__dx already themes DxGrid through its own CSS
   variables, and these are only the cell decorations §10.2 asks for on top. */
.k-tasks {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px var(--k-page-gutter);
}
/* The Create control is an <a> (navigation), painted as the page's primary action. */
.k-tasks__create {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    border-radius: var(--k-radius-md);
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    font-weight: 600;
    text-decoration: none;
}
.k-tasks__create:hover { background: var(--k-accent-hover); }
.k-tasks__create:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
/* web-02 02a T1: the mock's plus in front of the label (M:149), decoration only (aria-hidden). */
.k-tasks__create-glyph { width: 16px; height: 16px; }
.k-tasks__loading { color: var(--k-text-muted); }

/* W-24: the task name is the way into its detail, so it reads as a link — but a quiet one. The cell
   keeps the colour its TaskCell gives it (muted for an optional task, ordinary otherwise), because a
   whole column of accent-blue text would shout over the status icons that are §10.2's actual signal;
   the accent and the underline arrive on hover and on keyboard focus, which is where a link has to
   announce itself. No new colour: both values are existing tokens. */
/* DIZ-1 K1b: the same quiet link for EVERY grid's link column (W-24 amandman 24.9.) — .k-grid__link,
   KerberGridLink's class. .k-tasks__name-link stays as an alias until K2 moves Zadaci onto the shared
   component. The button form (an action with no address) is reset to look exactly like the link. */
.k-tasks__name-link,
.k-grid__link {
    color: inherit;
    text-decoration: none;
}
.k-tasks__name-link:hover,
.k-tasks__name-link:focus-visible,
.k-grid__link:hover,
.k-grid__link:focus-visible {
    color: var(--k-accent);
    text-decoration: underline;
}
.k-grid__link--button {
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    text-align: inherit;
    cursor: pointer;
}
/* #3152 Codex r4175432526: the global `button:hover` (0,1,1) outranks `.k-grid__link--button` (0,1,0) and filled
   the button form with the accent on hover. The mock's link hover is the underline alone (table.g td a:hover), so
   hover restates the resting reset at 0,2,0; colour and underline still come from .k-grid__link:hover above.
   Keyboard focus needs no restatement: no global rule fills a focused button (the pin's „fokus" case is green
   without one). Pin: GridHoverCssTests. */
.k-grid__link--button:hover {
    border: 0;
    background: none;
}

/* DIZ-1 K1b — the chip row (W-26; web-07:51-57, web-05:95-99, web-14:51-57): 30 px pills, CAPS 12/600,
   the count after the label muted; selected = filled accent; the alarm tone (.k-chip--danger, web-07
   :55-56) red at rest and solid red when selected. Tokens only. */
.k-chips { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.k-chip {
    height: 30px;
    padding: 0 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: 15px;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: transparent;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-text-label);
    cursor: pointer;
}
.k-chip__count {
    font-weight: 600;
    color: var(--k-text-muted);
    font-variant-numeric: tabular-nums;
}
.k-chip--on { background: var(--k-accent); border-color: var(--k-accent); color: var(--k-btn-text-on-accent); }
.k-chip--on .k-chip__count { color: var(--k-btn-text-on-accent); }
.k-chip--danger { border-color: rgba(var(--k-danger-rgb), 0.6); color: var(--k-danger); }
.k-chip--danger .k-chip__count { color: var(--k-danger); }
.k-chip--danger.k-chip--on { background: var(--k-danger); border-color: var(--k-danger); color: rgb(var(--k-white-rgb)); }
.k-chip--danger.k-chip--on .k-chip__count { color: rgb(var(--k-white-rgb)); }
.k-chip:focus-visible { outline: var(--k-focus-ring); outline-offset: var(--k-focus-ring-offset); }
/* #3152 Codex r4175432529: the global `button:hover` (0,1,1) outranks the one-class chip rules, so an unselected
   chip looked selected on hover and the alarm chip went cyan with red text. No mock draws a chip hover (the mocks'
   chips are spans: 25 web mocks with `.chips span`, none with a `.chips` :hover), so hover keeps each state's
   resting look; the pointer cursor is the affordance. ORDER MATTERS: `.k-chip:hover` (0,2,0) outranks the resting
   `.k-chip--on` (0,1,0), so the selected state restates itself after it, and the selected alarm chip at 0,3,0.
   Pin: GridHoverCssTests. */
.k-chip:hover { background: transparent; border-color: var(--k-border-strong); }
.k-chip--on:hover { background: var(--k-accent); border-color: var(--k-accent); }
.k-chip--danger:hover { border-color: rgba(var(--k-danger-rgb), 0.6); }
.k-chip--danger.k-chip--on:hover { background: var(--k-danger); border-color: var(--k-danger); }
/* W-22 (a), web-04 M:340: dan u tjednu je oznaka s OBRUBOM kao mock `.tag` / `.tag.p` (M:101–102), ne ispunjeni
   čip filtra (W-26) — odabrani dan mijenja obrub i boju teksta u akcent, pozadina ostaje prozirna. */
.k-chip.k-chip--day { background: transparent; }
.k-chip.k-chip--day.k-chip--on { background: transparent; border-color: var(--k-accent); color: var(--k-accent-soft); }

/* §11.0 time-range selectors, above the grid. */
.k-tasks__period {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.k-tasks__period-dates { display: flex; align-items: center; gap: 8px; margin-left: 8px; }
/* #4356: the From/To editors before the tenant's day is known — laid out but not shown. `visibility`, never
   `display`: the tool row is right-aligned and the holder stands right of the buttons, so a holder left out
   (or display:none) would shift the buttons left the moment the dates arrive. */
.k-tasks__period-dates--pending { visibility: hidden; }
.k-tasks__period-label {
    color: var(--k-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-size: 12px;
}
.k-tasks__date { width: 150px; }
/* Focus ring on the EDITOR rather than its inner <input>, for the reason the grid's search box
   states: a DxDateEdit is an input plus its drop-down button, and ringing half of it draws a box
   around part of the control the operator is in. Written against our own CssClass, never a
   DevExpress class name (docs.devexpress.com/Blazor/401740). */
.k-tasks__date:has(:focus-visible) {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
    border-radius: var(--k-radius-sm);
}
.k-tasks__date input:focus-visible { outline: none; }

/* Status column: an ICON, never a whole-row colour (§10.2's own words). The three semantics are the
   theme's existing status tokens — red X, green check, grey outline clock. */
.k-task-status { display: inline-flex; align-items: center; justify-content: center; }
.k-task-status__glyph { width: 18px; height: 18px; }
.k-task-status--performed { color: var(--k-success); }
.k-task-status--not-performed { color: var(--k-danger); }
.k-task-status--planned { color: var(--k-status-pending); }

/* W-08's fourth status. The token was already in :root (--k-status-in-progress) and unused until
   now — the cyan is the ratified #00B4D8, read from the token rather than repeated as a literal. */
.k-task-status--in-progress { color: var(--k-status-in-progress); }

/* ~20×25 px, ratified (owner 5.9. 21:16). The other three glyphs are square 18×18; the walker is
   4:5, which is exactly its 128×160 viewBox, so it is sized here instead of being re-drawn. */
.k-task-status__walker { width: 20px; height: 25px; }

/* THE WALKER'S ANIMATION, ONCE FOR THE WHOLE APP RATHER THAN ONCE PER ROW. The source drawing
   (Graphics/covjek-hoda.svg) carries these keyframes in its own <style> block; inlined into a grid
   cell that becomes one duplicated stylesheet per visible row, so the component ships the classes
   and the motion lives here. Timings are the source's, unchanged.
   The back limbs are offset by half a stride so the figure reads as walking rather than hopping. */
@keyframes k-walker-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-2px); } }
@keyframes k-walker-arm { 0%, 100% { transform: rotate(28deg); } 50% { transform: rotate(-28deg); } }
@keyframes k-walker-stride { 0%, 100% { transform: rotate(-27deg); } 50% { transform: rotate(27deg); } }
@keyframes k-walker-knee {
    0% { transform: rotate(8deg); }
    25% { transform: rotate(4deg); }
    50% { transform: rotate(12deg); }
    75% { transform: rotate(65deg); }
}

.k-walker__body { animation: k-walker-bob .6s ease-in-out infinite; }
.k-walker__arm { animation: k-walker-arm 1.2s ease-in-out infinite; }
.k-walker__leg { animation: k-walker-stride 1.2s ease-in-out infinite; }
.k-walker__shin { animation: k-walker-knee 1.2s linear infinite; }
.k-walker__back { opacity: .45; }
.k-walker__back .k-walker__arm,
.k-walker__back .k-walker__leg,
.k-walker__back .k-walker__shin { animation-delay: -.6s; }

/* web-08 08D k2-1 + k2-6 (P-08-3; mock web-08 M:58-60 `.live`, drawn at M:273 and M:302): THE LIVE MARK — one
   class for both places the mock draws it, „Radni dan još traje" beside the departure and „Živo" ending the chip
   row (ARH-C 200637 t.6); the chip row adds the mock's chip frame by context (`.k-wd__filters .k-wd__live`,
   M:52). The mock's values verbatim, --success → --k-success; the dot blinks
   (`@keyframes blink { 50% { opacity: .3; } }`, M:60). It sits HERE, ABOVE the reduced-motion block below:
   that block stops the blink with a selector of the same specificity and no `!important`, so it has to come
   later in the sheet to win. */
.k-wd__live {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--k-success);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .5px;
}
.k-wd__live i {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--k-success);
    animation: k-wd-blink 1.4s ease-in-out infinite;
}
@keyframes k-wd-blink { 50% { opacity: .3; } }

/* The source SVG had this opt-out and it does not get lost in the move: a status icon that animates
   forever is exactly what a reduced-motion preference is about, and the cyan colour still carries
   the meaning when the motion stops. */
@media (prefers-reduced-motion: reduce) {
    .k-walker__body,
    .k-walker__arm,
    .k-walker__leg,
    .k-walker__shin { animation: none !important; }
    /* web-08 08D: the live mark's dot stops blinking; the success colour still says „live". */
    .k-wd__live i { animation: none; }
}

/* Ruling R2's muting: presentation only, and expressed as REDUCED EMPHASIS rather than a new colour,
   so a muted planned row still reads as planned (scen 22) instead of acquiring a second meaning. */
.k-task-cell { display: inline-flex; align-items: baseline; gap: 8px; min-width: 0; }
.k-task-cell__text { overflow: hidden; text-overflow: ellipsis; }
.k-task-cell--muted { color: var(--k-text-muted); opacity: 0.72; }
.k-task-optional {
    flex: none;
    padding: 1px 6px;
    border: 1px dashed var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    color: var(--k-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-size: 11px;
}

/* Review column: one control per row, whatever the row's status (scen 11). */
.k-task-review {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--k-radius-sm);
    background: transparent;
    color: var(--k-accent-soft);
    cursor: pointer;
}
.k-task-review:hover {
    background: rgba(var(--k-accent-rgb), 0.1);
    border-color: var(--k-border-strong);
}
.k-task-review:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-task-review__glyph { width: 16px; height: 16px; }

/* ── W4 Task 3: the §10.2 review detail ───────────────────────────────────────────────────────── */

/* The panel itself: a card over the grid, not a page — the review "opens the task's detail view",
   and the grid it was opened from is still right underneath. */
.k-task-detail {
    margin: 0 0 20px;
    padding: 16px 18px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    background: var(--k-surface);
}
.k-task-detail__header {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}
/* web-02 k2/k4 (mock line 94): the occurrence's name is the panel's title, set like one. The mode
   label and the window line that stood beside it are gone — the meta row below says both. */
.k-task-detail__name {
    margin: 0;
    font-size: 18px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-accent);
}
.k-task-detail__empty { margin: 0; color: var(--k-text-muted); }
.k-task-detail__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    margin-left: auto;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--k-radius-sm);
    background: transparent;
    color: var(--k-text-muted);
    cursor: pointer;
}
/* P112 (mock web-02c k1): „Uredi zadatak ›" stands at the right, just before ✕ — it takes the auto margin the
   close button would otherwise take, and the close button keeps its place beside it. */
.k-task-detail__edit { margin-left: auto; }
.k-task-detail__edit + .k-task-detail__close { margin-left: 0; }
.k-task-detail__close:hover { border-color: var(--k-border-strong); color: var(--k-text); }
.k-task-detail__close:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-task-detail__close-glyph { width: 14px; height: 14px; }
/* A group reads as structure, a task as a leaf — the tree's indentation says depth, this says kind. */
.k-task-detail__node--group { font-weight: 600; }
.k-task-detail__node--task { color: var(--k-text-muted); }
/* The subtask a §10.1 alarm-9 row was about, when the detail was opened from one (W3): an outline
   and full-strength text rather than a colour wash, so the mark survives greyscale and does not read
   as one of the two danger/warning states the rest of this panel spends colour on. */
.k-task-detail__node--focus {
    padding: 1px 6px;
    border: 1px solid var(--k-accent);
    border-radius: var(--k-radius-sm);
    color: var(--k-text);
}

/* Mock kadar 4: tekuci korak nosi ISTAKNUT LIJEVI RUB uz hodaca. Odvojeno od --focus
   („poslan si ovamo", §10.1 alarm 9), jer redak moze biti oboje i jedno ne smije
   prepisati drugo: focus nosi obrub cijelog imena, ovo samo lijevi rub.
   #2142: sljedeći na redu izgleda kao tekući. */
.k-task-detail__node--in-progress,
.k-task-detail__node--next {
    border-left: 3px solid var(--k-status-in-progress);
    padding-left: 6px;
}
/* #4342 (vlasnik 19.10.2026.: an incident is only a row; mock web-02d's `.st.inc`, `.incopen`): an incident row
   of the task tree — the red triangle before its name, the name in the text colour (not the leaf's muted one), and
   „otvoren" in the alarm colour; „riješen" in the label colour. Its photos are the step's thumbnail buttons
   (TaskDetailIncidentRecord) and take the step tile's rule, hand cursor included; a photo without an address is
   the media seam's text and gets no pointer and no hover state. */
.k-task-detail__node--incident { color: var(--k-text); }
.k-task-detail__incident-glyph { flex: none; width: 16px; height: 16px; color: var(--k-danger); }
.k-task-detail__incident-record { display: inline-flex; align-items: center; gap: 8px; }
.k-task-detail__incident-thumb { display: inline-block; }
.k-task-detail__incident-state { font-size: 13px; font-weight: 600; }
.k-task-detail__incident-state--open { color: var(--k-danger); }
.k-task-detail__incident-state--resolved { color: var(--k-text-label); }
/* #4342 „UPRAVO" (mock web-02d's `tr.new`, `.upravo`): a row finished, or an incident reported, since the
   previous picture of the same task washes green and carries the word „upravo" for 3 s, ONCE — the mock loops the
   wash only so its still frame shows it. No timer and no server state: the class stays on the row until the next
   picture, and the animation runs once from the moment the class appears. The row is reached through :has() from
   the name span our template owns (the selected row's pattern above), so no DevExpress row API. The word ends
   hidden (`forwards`), the wash ends transparent. Under reduced motion there is no wash, and the word stands still
   and disappears at once after the same 3 s (step-end) — no motion, the same meaning. */
.k-task-detail__tree tr:has(.k-task-detail__node--fresh) > td { animation: k-task-detail-fresh-wash 3s ease-out forwards; }
.k-task-detail__tree tr:has(.k-task-detail__node--fresh) > td:first-child { animation-name: k-task-detail-fresh-edge; }
.k-task-detail__fresh {
    flex: none;
    margin-left: 8px;
    padding: 0 5px;
    border: 1px solid rgba(var(--k-success-rgb), .5);
    border-radius: 3px;
    color: var(--k-success);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    animation: k-task-detail-fresh-word 3s ease-out forwards;
}
@keyframes k-task-detail-fresh-wash {
    from { background: rgba(var(--k-success-rgb), .28); }
    to { background: transparent; }
}
@keyframes k-task-detail-fresh-edge {
    from { background: rgba(var(--k-success-rgb), .28); box-shadow: inset 3px 0 0 var(--k-success); }
    to { background: transparent; box-shadow: none; }
}
@keyframes k-task-detail-fresh-word {
    85% { opacity: 1; }
    100% { opacity: 0; visibility: hidden; }
}
@media (prefers-reduced-motion: reduce) {
    .k-task-detail__tree tr:has(.k-task-detail__node--fresh) > td,
    .k-task-detail__tree tr:has(.k-task-detail__node--fresh) > td:first-child { animation: none; }
    .k-task-detail__fresh { animation-timing-function: step-end; }
}
.k-task-detail__moment { font-variant-numeric: tabular-nums; }

/* A measured value against its bounds. The violated bound is marked TWICE — by colour and by the
   word the component prints — so the mark survives a screen reader as well as a colour. Since web-02
   (mock k2 lines 119-120, 195-201) the word is for the READER only (see the end of this section) and
   the eye gets the mock's colours: a green bracket inside the bounds, value and bracket red outside. */
.k-task-measure { display: inline-flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.k-task-measure__value { font-variant-numeric: tabular-nums; }
.k-task-measure__bounds { font-variant-numeric: tabular-nums; }
.k-task-measure--below-minimum .k-task-measure__value,
.k-task-measure--above-maximum .k-task-measure__value,
.k-task-measure--below-minimum .k-task-measure__bounds,
.k-task-measure--above-maximum .k-task-measure__bounds { color: var(--k-danger); font-weight: 600; }

/* Everything else one element recorded. Blocks are absent, never empty: an element with nothing
   recorded shows an empty cell rather than a column of dashes. */
.k-task-record { display: flex; flex-direction: column; gap: 4px; }
/* web-02 (mock k2 lines 195, 200-202, its `.note`): each recorded fact is ONE line of prose in the
   label colour — „Napomena radnika: „…"" — so the line flows as text, not as a row of flex items
   that would put gaps around the colon and the quotes. */
.k-task-record__line { margin: 0; color: var(--k-text-label); font-size: 13px; white-space: normal; }
.k-task-record__label { color: var(--k-text-label); }
.k-task-record__overrun {
    align-self: flex-start;
    padding: 1px 6px;
    border-radius: var(--k-radius-sm);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}
/* „Nije obavljeno" leads its line in bold and the alarm colour (mock k2 line 202, `.bad`) — a
   verdict word in the sentence, no longer a bordered badge. */
.k-task-record__not-done { color: var(--k-danger); font-weight: 600; }
.k-task-record__overrun { border: 1px solid var(--k-warning); color: var(--k-warning); }
.k-task-record__media { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
/* W-16 (a) (t.5 U3; mock web-02 lines 124-125, `.thumbs` / `.thumbs i`): up to three 28×22 thumbnails in the
   record of a step, each a button that opens the media viewer. The tile is the mock's indigo-grey gradient, here
   from the theme's own tokens (--k-border-strong → --k-accent-indigo, the mock's #2b3350 → #3d4870 family). A
   photo covers its tile; a VIDEO is the bare tile — NO icon and no generated content (owner 134-2 a, pin T12). */
.k-task-record__thumbs { display: inline-flex; gap: 4px; vertical-align: middle; }
.k-task-record__thumb {
    width: 28px;
    height: 22px;
    padding: 0;
    border: 1px solid var(--k-border-strong);
    border-radius: 3px;
    background: linear-gradient(135deg, var(--k-border-strong), var(--k-accent-indigo));
    overflow: hidden;
    cursor: pointer;
}
.k-task-record__thumb-img { display: block; width: 100%; height: 100%; object-fit: cover; }
.k-task-record__thumb--video { background: linear-gradient(135deg, var(--k-border-strong), var(--k-accent-indigo)); }

/* Ruling R8's two seams. The media seam now DELIVERS (S4 Task 8) and only falls back to a stated
   line when there are no bytes to show — still uploading, or gone for good; the map seam is still a
   placeholder. Both fallbacks are styled as what they are: a stated gap, never a broken image or a
   blank map. */
.k-task-media {
    padding: 8px 10px;
    border: 1px dashed var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    max-width: 320px;
}
.k-task-media__placeholder,
.k-task-media__unavailable { margin: 0; display: flex; flex-direction: column; gap: 2px; }
.k-task-media__kind { font-size: 12px; }
.k-task-media__pending { color: var(--k-text-muted); font-size: 11px; }
/* Rejected/Purged: a stated LOSS, not a state that will resolve — muted like the pending line would
   understate it, and an alarm colour would overstate it. */
.k-task-media__gone { color: var(--k-warning); font-size: 11px; }
.k-task-media__image, .k-task-media__video { display: block; max-width: 100%; height: auto; }

/* W-16 — the one media viewer (Media/MediaViewer.razor): a DxPopup over the whole screen with the capture as large
   as the screen allows. Inside the viewer the media seam is the content itself, not a card in a cell, so its frame
   is lifted and its 320px cap becomes the stage's own width (min-width: 0, so the flex item may shrink below a wide
   capture's size instead of overflowing the screen — t.5, Codex #3208 P2); a photo keeps its proportions (object-fit: contain) and is never cropped. The
   download link takes the shape of the other plain actions (.k-wd__export-download). Theme tokens only. */
.k-media-viewer-popup { max-width: 100vw; max-height: 100vh; }
/* #3330: DevExpress BlazingDark (25.2.9) gives every popup `.dxbl-modal { --dxbl-popup-margin: 1.75rem }`, and
   `.dxbl-modal > .dxbl-modal-root > .dxbl-popup { margin: var(--dxbl-popup-margin) }` — on a 100vw × 100vh viewer
   that pushed the right and bottom edges 24.5 px out of the window (close button and download cut, E2E
   TasksSmokeTests.W16_3330). The viewer is the one popup meant to cover the window, so it drops the margin the
   same way DevExpress does for its own full-size dialogs (`.dxbl-popup.dxbl-grid-column-chooser-dialog`). The
   variable is set on the popup itself, so it wins over the value inherited from .dxbl-modal regardless of order. */
.dxbl-modal > .dxbl-modal-root > .dxbl-popup.k-media-viewer-popup { --dxbl-popup-margin: 0; }
.k-media-viewer {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    min-height: 0;
}
.k-media-viewer__stage {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 0;
}
.k-media-viewer__stage .k-task-media {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
    max-width: 100%;
    padding: 0;
    border: 0;
}
.k-media-viewer__stage .k-task-media__image,
.k-media-viewer__stage .k-task-media__video {
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: calc(100vh - 184px);   /* header, the step row, the action row and the popup's own padding */
    object-fit: contain;
}
.k-media-viewer__nav { display: flex; align-items: center; justify-content: center; gap: 12px; }
.k-media-viewer__step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    background: transparent;
    color: var(--k-text);
    cursor: pointer;
}
.k-media-viewer__step:hover:not(:disabled) { border-color: var(--k-accent); color: var(--k-accent); }
.k-media-viewer__step:disabled { color: var(--k-text-muted); cursor: default; }
.k-media-viewer__step:focus-visible { outline: var(--k-focus-ring); outline-offset: var(--k-focus-ring-offset); }
.k-media-viewer__step-icon { display: block; flex: none; }   /* no inline baseline gap inside the 32px step */
.k-media-viewer__counter {
    min-width: 4ch;
    text-align: center;
    color: var(--k-text-muted);
    font-variant-numeric: tabular-nums;
}
.k-media-viewer__actions { display: flex; justify-content: flex-end; width: 100%; }
.k-media-viewer__download {
    display: inline-flex;
    align-items: center;
    padding: 4px 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    color: var(--k-text);
    text-decoration: none;
}
.k-media-viewer__download:hover { border-color: var(--k-accent); color: var(--k-accent); }
.k-media-viewer__download:focus-visible { outline: var(--k-focus-ring); outline-offset: var(--k-focus-ring-offset); }
/* PR-4d (owner 88d, mock web-18 frame 3): the capture's header inside DevExpress's own header — the kind in bold,
   then „ · moment · author" muted like the position counter, digits of equal width like the counter's. */
.k-media-viewer__header { min-width: 0; color: var(--k-text); overflow-wrap: anywhere; }
.k-media-viewer__header-kind { font-weight: 600; }
.k-media-viewer__header-meta { color: var(--k-text-muted); font-variant-numeric: tabular-nums; }

/* web-02 PR 02d-1: the map column of the body (`.k-task-detail__body--map`, below). No frame of its
   own any more — the dashed box was the R8 placeholder's; the map draws its own (`.k-map`), and a run
   with nothing to draw shows no frame at all (plan Review Focus 5). */
.k-task-track {
    margin: 0;
    min-width: 0;
}
/* Mock k2 line 131 `.map .ttl`: 12px, 600, uppercase, tracked, label colour. */
.k-task-track__title {
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-size: 12px;
    font-weight: 600;
    color: var(--k-text-label);
}
.k-task-track__empty {
    margin: 6px 0 0;
    color: var(--k-text-muted);
    font-size: 12px;
}

/* web-02 k2/k4 (PR 02b-1, mock lines 95-96): the header's meta row — label: value pairs on ONE
   line under the name. `order` puts it after the close control, so the ✕ keeps the right end of
   the name's line and the row wraps below both; the DOM keeps the reading order name → meta. */
.k-task-detail__meta {
    order: 1;
    flex-basis: 100%;
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    margin: 0;
    color: var(--k-text-label);
    font-size: 14px;
}
.k-task-detail__meta b { color: var(--k-text); font-weight: 600; }
/* Stanje's value. Two classes in the modifier selectors on purpose: `.k-task-detail__meta b` above
   is (0,1,1), and a lone modifier (0,1,0) would lose to it and paint every state in text colour. */
.k-task-detail__state { font-weight: 600; }
.k-task-detail__meta .k-task-detail__state--not-performed { color: var(--k-danger); }
.k-task-detail__meta .k-task-detail__state--in-progress { color: var(--k-status-in-progress); }
/* #4342 (vlasnik 19.10.2026., W-31 u pilotu; mock web-02d's `.live`): the task detail in progress is
   live, and its meta row ends with the green dot and „Živo". The mock's values, --success → --k-success. A THIRD copy
   of the live mark (`.k-wd__live`, `.k-entity-header__live`), named: merging them is #3401. The dot blinks with
   `k-live-blink`, reused, not copied; under reduced motion it stops and the word still says „live". */
.k-task-detail__live {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--k-success);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}
.k-task-detail__live i {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--k-success);
    animation: k-live-blink 1.4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .k-task-detail__live i { animation: none; }
}

/* web-02 k2 (PR 02b-1 T3, mock lines 119-120, 195): inside its bounds a measure's BRACKET is green and
   the value keeps the text colour; the red of a broken bound is above. Exactly on a bound is inside —
   the read model's verdict, not a rule of this sheet. */
.k-task-measure__bounds--within { color: var(--k-success); }
/* The broken bound's WORD („ispod minimuma") is for a screen reader only: the mock marks the bound
   by colour, and colour alone is not an accessible mark. Clipped to a 1px box rather than
   display:none / visibility:hidden, which would hide it from the reader too. No shared sr-only class
   exists in this sheet, so the rule is the element's own. Since 02b-2 it also clips the record's
   alarm-9 word after the scan distance (TaskDetailRecord), so it is not the measure's alone. */
.k-task-measure__violation {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}
/* A yes/no answer leads its line as an uppercase bold word (mock k2 line 200, „NE"); uppercase by
   CSS, so the resource keeps one spelling and a screen reader does not spell out capitals. A „no" is
   a recorded finding and takes the alarm colour; a „yes" keeps the text colour. */
.k-task-record__answer-yesno { color: var(--k-text); font-weight: 600; text-transform: uppercase; }
.k-task-record__answer-yesno--no { color: var(--k-danger); }
/* web-02 k2 E14 (PR 02b-1 T4, mock line 106 `tr.hov`): the row under the pointer takes the accent at .05.
   DevExpress draws the hover (HighlightRowOnHover); this only tints it, through the same variables
   KerberGrid sets on `.k-grid__dx` — never a DevExpress class name (docs.devexpress.com/Blazor/401740).
   Fluent 25.2.9 reads only `--dxbl-grid-hover-bg` (rows and sortable headers); BlazingDark's
   `--dxbl-grid-hover-bg-static` left with K3-F F2. */
.k-task-detail__tree {
    --dxbl-grid-hover-bg: rgba(var(--k-accent-rgb), 0.05);
}
/* The node the host selected (mock line 104 `tr.sel`): the WHOLE ROW takes the accent wash at .16
   and its first cell the inset 3px accent edge (as `tr.cur td:first-child` in the same mock). The
   class lives on the name span — the one element our cell template owns — and the row is reached
   through :has(), the pattern `.k-grid__dx td:has(…)` already uses, so no DevExpress row API and no
   DevExpress class name. The span itself is not painted, or the name would be washed twice. */
.k-task-detail__tree tr:has(.k-task-detail__node--selected) > td { background: rgba(var(--k-accent-rgb), 0.16); }
.k-task-detail__tree tr:has(.k-task-detail__node--selected) > td:first-child { box-shadow: inset 3px 0 0 var(--k-accent); }
/* A node's name is clickable (it reports the node to the host, SelectedNodeIdChanged).
   web-02 PR 02d-1 N1 N-b (TaskReviewDetail.TreeColumnWidths): beside the map the name column is narrow,
   so a long name is CUT WITH „…" and carries its full text in `title` — the mock keeps every row on one
   line (k2 line 193 `white-space: nowrap`). DevExpress floats the indent and the expand button left
   inside the first cell (25.2.9 `.dxbl-grid-tree-node-expand-controls-container { float: left }`), so
   the node is a FLEX box — its own formatting context, which sits BESIDE that float with AUTO width,
   i.e. the space the float leaves, clamped to its content by `max-width: max-content` so the focus
   outline and the in-progress edge still hug the name. The name inside it shrinks and cuts. NOT
   `width: fit-content` / `max-width: 100%`: a long name then asks for more than the float leaves and
   the box drops BELOW the float, out of its indentation (task review I1, reproduced in Chromium).
   The gap stands for the space that separated the glyph from the name while the node was inline. */
.k-task-detail__node {
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 4px;
    max-width: max-content;
}
.k-task-detail__node-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* web-02 T6 (mock k4, CSS lines 100-103 `table.t`): the tree is the panel's own table, not a grey
   DevExpress box — DevExpress's own variables re-pointed at Kerber's tokens, the KerberGrid recipe
   (docs.devexpress.com/Blazor/401740). DevExpress declares these on `.dxbl-grid`, and CssClass lands
   on that same element (measured, 25.2.9 bUnit: `<dxbl-tree-list class="dxbl-grid
   k-task-detail__tree">`); this sheet loads after the theme, so one class is enough.
   K3-F F5 (ARH-C 110742): the lines are the mock's 1px (mock k4 CSS 101-102 `border-bottom: 1px`) through
   --dxbl-grid-border-width — Fluent 25.2.9 declares 0.0625rem (0.875 px) on `.dxbl-grid`, BlazingDark 1px; DX sizes the
   grid's frame with it too, as it did under BlazingDark. Pin: Web02PregledRenderTests.F5_Stablo_zadatka_crta_celija_je_1px_kao_mock. */
.k-task-detail__tree {
    --dxbl-grid-bg: transparent;
    --dxbl-grid-header-bg: transparent;
    --dxbl-grid-color: var(--k-text);
    --dxbl-grid-border-color: var(--k-border);
    --dxbl-grid-border-width: 1px;
}
/* The column heads as the mock sets them (`table.t th`): 12px, 600, uppercase, tracked, label
   colour. Size, colour and weight through DevExpress's variables, declared ON the cell so they beat
   the root's values without out-specifying the theme's own cell rules; case and tracking, which no
   variable carries, directly. */
.k-task-detail__tree thead th {
    --dxbl-grid-font-size: 12px;
    --dxbl-grid-header-color: var(--k-text-label);
    --dxbl-grid-header-font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}
/* A group's whole row is set in 600 (mock `tr.grp td`), not only its name — reached through :has()
   from the class our cell template owns, as the selected row above is. */
.k-task-detail__tree tr:has(.k-task-detail__node--group) > td { font-weight: 600; }
/* An empty measure cell's em dash (mock k4 line 311) in the cell's text colour, like the mock's
   `td` — the leaf name beside it is muted, the mark is not. */
.k-task-detail__no-measure { color: var(--k-text); }
/* „u tijeku" in the record (mock k4 line 310, `.rec`): plain text in the soft accent at 13px — no
   border, no fill, no capitals; it is the start of a sentence 02b-2 completes with the distance. */
.k-task-record__rec {
    display: inline-flex;
    align-self: flex-start;
    align-items: center;
    gap: 6px;
    color: var(--k-accent-soft);
    font-size: 13px;
}
/* web-02 PR 02b-2 E8/E16 (mock k2 lines 196, 198, 203; k4 line 310): the scan's distance in the same
   `.rec` line, after the map-pin glyph (mock `.rec svg`, 15px, in the line's colour). Red and bold
   (mock `.bad`) only on the read model's flag — alarm 9's verdict, never this sheet's. */
.k-task-record__pin { width: 15px; height: 15px; flex: none; }
.k-task-record__distance { font-variant-numeric: tabular-nums; }
.k-task-record__distance--exceeded { color: var(--k-danger); font-weight: 600; }
/* web-02 PR 02d-1 T1 (mock k2 line 98, `.detail .bd { grid-template-columns: 1fr 420px }`): the
   body under the header — the tree, and beside it the map in a 420 px column. `minmax(0, 1fr)` is the
   mock's 1fr with the grid's own floor removed, so the tree's wide columns scroll inside their
   column instead of pushing the map off the panel. A structure preview (no map) keeps one column. */
.k-task-detail__body {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
    align-items: start;
}
.k-task-detail__body--map { grid-template-columns: minmax(0, 1fr) 420px; }
/* Mock k2 line 126 `.map { border-left: 1px solid var(--border-strong) }`: the map column is set off
   from the tree by a hairline in the strong border token, the gap becoming its inner padding. */
.k-task-detail__body--map > .k-task-track {
    border-left: 1px solid var(--k-border-strong);
    padding-left: 16px;
}
/* Below 1428 px the map goes UNDER the tree (owner „241 a", BRAIN 1446): the tree then has the panel's
   whole width and never scrolls, map or no map (#3380). The edge is MEASURED: the full tree is
   window − 96 px (KV-B R0b, 1084 at 1180, 1344 at 1440); beside the map 436 px less (column + gap),
   so 896 px stand beside the map from 1428 up; TaskReviewDetail's 860 leave room for a classic scrollbar (U1). The
   mock (k2, 1440) keeps the map on the right. Stacked, nothing stands to the map's left, so the
   divider goes with the second column. */
@media (max-width: 1427px) {
    .k-task-detail__body--map { grid-template-columns: minmax(0, 1fr); }
    .k-task-detail__body--map > .k-task-track { border-left: 0; padding-left: 0; }
}
/* The map itself (mock k2 line 126 `.map`, min-height 330px). A provider map sizes itself to its
   container, so the height is set here, on the frame and on KerberMap's canvas (the `.k-wd__map`
   recipe). */
.k-task-track__map {
    /* #3254: the positioning box of the selected group's caption below (it had no position before). */
    position: relative;
    margin-top: 8px;
    min-height: 330px;
}
.k-task-track__map .k-map,
.k-task-track__map .k-map__canvas { height: 100%; min-height: 330px; }
/* #3254 — the selected group's caption „odabrana grupa: ‹ime› · ‹od›–‹do›" (mock k2 line 215's accent label;
   kadar K2, owner 18.10. „2a"): over the map, in the frame's top-LEFT corner — the top-right one is the base
   switch's (.k-map__views, right: 12px, z-index 1), so the caption takes the same layer on the other side.
   12px in the soft accent and with NO background, as the frame the owner chose draws it; pointer-events: none
   so it never takes a click away from the map under it. */
.k-task-track__selection {
    position: absolute;
    left: 12px;
    top: 12px;
    z-index: 1;
    margin: 0;
    font-size: 12px;
    color: var(--k-accent-soft);
    pointer-events: none;
}
/* #4342 (owner ruling 19.10.2026) — the silent-phone notice „Telefon se ne javlja N min" (one line per silent worker
   when the task has more than one open root): over the map's top-RIGHT corner, UNDER the base switch (.k-map__views,
   top 12px, about 40px tall). The warning is the left rule in --k-warning; the text stays in --k-text on the
   surface, because the light theme's --k-warning is a fill colour and too pale for 12px text.
   NO z-index, ON PURPOSE: neither .k-task-track__map nor .k-map builds a stacking context, so a number here would be
   one more layer of the whole page (MapSwitchStackingTests counts every owner). The ORDER does the work instead: the
   notice comes AFTER the map in the markup, and a positioned box with z-index auto is painted in tree order with the
   z-index 0 ones — after the canvas (0, earlier), before the base switch (1) — so it lies over the map and under an
   opened switch. pointer-events: none so it never takes a click away from the map under it. */
.k-task-track__silent {
    position: absolute;
    right: 12px;
    top: 60px;
    max-width: calc(100% - 24px);
    padding: 6px 10px;
    background: var(--k-surface);
    border: 1px solid var(--k-border-strong);
    border-left: 3px solid var(--k-warning);
    border-radius: var(--k-radius-sm);
    font-size: 12px;
    font-weight: 600;
    color: var(--k-text);
    pointer-events: none;
}
.k-task-track__silent-line { margin: 0; }

/* ── W4 Task 10, the a11y pass over W4's screens ─────────────────────────────────────────────────
   The Tasks menu's and the wizard's command buttons are DevExpress BUTTONS, and DevExpress draws a
   button's focus ring from its own variables — not from this sheet's :focus-visible rule, which its
   own `.dxbl-btn:not(.dxbl-disabled):not(:disabled):focus-visible` outranks on specificity anyway. So
   without this block the Save/Exit/Delete row, the structure palette, the template button, both
   modals and the three period selectors focus with DevExpress's own thin purple outline
   (BlazingDark 25.2.9 #A01DE7; under Fluent 25.2.9 a white #fffffe ring, 0.125rem, offset 0.0625rem — core.min.css
   `.dxbl-btn` declares --dxbl-btn-focus-outline-color/-size/-offset) instead of Kerber's accent ring — measured in the browser,
   which is also the only place it shows: W4's focus smoke reads the RESOLVED outline off a control the
   keyboard tabbed to. The wizard's STEP BAR is not in this list: since web-04 (O4) its cards are plain
   <button>s, ringed by `.k-wizard__step:focus-visible { outline: var(--k-focus-ring) }` below.

   VARIABLES, NEVER A DEVEXPRESS CLASS NAME (docs.devexpress.com/Blazor/401740: rules written against
   internal class names "may stop working after you upgrade") — the same recipe the grid's export
   toolbar uses. Set ON THE BUTTONS rather than on an ancestor, because DevExpress defines the same
   variable on the element itself (Fluent 25.2.9: on `.dxbl-btn`; BlazingDark: `.dxbl-btn-standalone`, #A01DE7),
   which an inherited value can never reach. Enumerated by OUR OWN CssClass, so a control this list
   forgets keeps DevExpress's ring — visibly focusable, just not in Kerber's colour.

   EACH SELECTOR NAMES ITS CONTAINER TOO, and that is arithmetic rather than decoration: DevExpress
   sets the variable from a TWO-class rule (`.dxbl-btn-standalone.dxbl-btn-outline-none`), so a
   single-class rule of ours loses on specificity no matter where it sits in the sheet. Two classes tie,
   and this sheet is linked after the DevExpress theme (see App.razor), so the tie goes to Kerber.
   Measured both ways: one class left the ring purple, two turned it accent. That arithmetic is BlazingDark's: Fluent
   25.2.9 declares the variable from ONE class (`.dxbl-btn`, no `.dxbl-btn-standalone…` rule), so two classes now win
   on specificity alone — kept. A DevExpress button OUTSIDE this list keeps Fluent's white ring (K3-F F5, F-v1). */
.k-tasks__period .k-tasks__period-button,
.k-wizard .k-wizard__action,
.k-wizard .k-wizard__modal-stay, .k-wizard .k-wizard__modal-discard,
.k-wizard .k-wizard__modal-cancel, .k-wizard .k-wizard__modal-confirm,
.k-wizard .k-templates__insert {
    --dxbl-btn-focus-outline-color: var(--k-accent);
    --dxbl-btn-focus-outline-size: 2px;
    --dxbl-btn-focus-outline-offset: 2px;
}

/* ── Task wizard (§11.10) — W4 Task 4 (shell) ────────────────────────────────────────────────────
   The page gutter and header row the Tasks menu uses, plus what this screen adds: a step bar of
   cards (W-19/W-38 — the only navigation; plain buttons, O4) and one panel at a time. Nothing here
   restyles a DevExpress class, only places them. */
.k-wizard {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 16px var(--k-page-gutter);
}
.k-wizard__header {
    display: flex;
    align-items: flex-start; /* mock .pagehead M:44 — gumbi uz vrh bloka s podnaslovom (04b) */
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}
.k-wizard__actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* #4705: an inert Save keeps the PRIMARY button's colours — accent fill and border, the text colour that sits on
   the accent — and only fades (the global `button:disabled` opacity above applies: the inert DxButton carries the
   plain `disabled` attribute, WizardSaveExitRenderTests). Fluent 25.2.9 (core.min.css, md5 81c5423f) WRITES these
   three variables on `.dxbl-btn` (0,1,0) and READS them only in `.dxbl-btn.dxbl-disabled.dxbl-btn-<style>` and
   `.dxbl-btn.dxbl-disabled.dxbl-btn-primary` (0,3,0), which copy them into --dxbl-btn-bg/-color/-border-color. So two
   classes of ours (0,2,0) beat the writer and the reader takes our value; every reader requires the disabled class,
   so a working Save is untouched. Variables only, no DevExpress class name (docs.devexpress.com/Blazor/401740);
   WizardSaveDisabledCssTests measures writers and readers in the served sheets. */
.k-wizard .k-wizard__action--save {
    --dxbl-btn-disabled-bg: var(--k-accent);
    --dxbl-btn-primary-disabled-border-color: var(--k-accent);
    --dxbl-btn-disabled-color: var(--k-btn-text-on-accent);
}
.k-wizard__panel {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
    border: 1px solid var(--k-border);
    border-radius: var(--k-radius-md);
}
.k-wizard__field { display: flex; flex-direction: column; gap: 6px; max-width: 420px; }
/* Focus ring on the EDITOR, not its inner input — the reason the Tasks page's date editors give:
   ringing half of a DevExpress editor draws a box around part of the control (never styled through a
   DevExpress class name — docs.devexpress.com/Blazor/401740). */
.k-wizard__name:has(:focus-visible),
.k-wizard__description:has(:focus-visible),
.k-wizard__number:has(:focus-visible),
.k-wizard__choice:has(:focus-visible) {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
    border-radius: var(--k-radius-sm);
}
.k-wizard__name input:focus-visible,
.k-wizard__number input:focus-visible,
.k-wizard__choice input:focus-visible,
.k-wizard__description textarea:focus-visible { outline: none; }
.k-wizard__assignment { margin: 0; font-size: 13px; }
.k-wizard__assignment--fixed { color: var(--k-text); }
.k-wizard__assignment--free { color: var(--k-text-muted); }
/* The honest notes: a step whose form is still to come, and an edit that has nothing to edit. */
.k-wizard__pending, .k-wizard__unavailable { margin: 0; color: var(--k-text-muted); font-size: 12px; }
/* P77 (#3689, 1 (a)): the card that replaces the wizard for a deactivated location (mock frame 3). */
.k-wizard__inactive-card { max-width: 560px; margin: 60px auto; padding: 22px 24px; border: 1px solid var(--k-border-strong); border-left: 3px solid var(--k-warning); border-radius: var(--k-radius-lg); background: var(--k-surface); }
.k-wizard__inactive-card h2 { margin: 0 0 8px; font-size: 18px; color: var(--k-text); }
.k-wizard__inactive-card p { margin: 0 0 16px; color: var(--k-text-label); font-size: 14px; line-height: 1.5; }
/* W7 §11.5: template context — why this wizard has two steps rather than three (ruling P7). */
.k-wizard__template-note { margin: 0; color: var(--k-text-muted); font-size: 12px; }
/* W-19 + W-38 (web-04, DIZ-5): traka koraka je JEDINA navigacija — kartice jednake širine (mock
   `.steps`/`.step`, M:49-54): broj u krugu, naslov verzalom, sažetak ispod (04b). Tri stanja: tekuća
   (naglasak + lijeva traka), dostupna (obična boja, klik), nedostupna (prigušena, `disabled`). */
.k-wizard__steps { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 10px; }
.k-wizard__step {
    display: flex; align-items: center; gap: 12px; min-width: 0; padding: 10px 14px;
    border: 1px solid var(--k-border-strong); border-radius: var(--k-radius-lg);
    background: var(--k-surface); color: var(--k-text-label);
    font: inherit; font-size: 13px; font-weight: 600; text-transform: uppercase;
    letter-spacing: var(--k-label-tracking); text-align: left; cursor: pointer;
}
.k-wizard__step:focus-visible { outline: var(--k-focus-ring); outline-offset: 2px; }
.k-wizard__step-number {
    flex: none; display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 28px; border: 2px solid var(--k-text-label); border-radius: 50%; font-size: 13px;
}
.k-wizard__step-text { display: flex; flex-direction: column; min-width: 0; }
.k-wizard__step-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.k-wizard__step--current { border-color: var(--k-accent); color: var(--k-accent-soft); box-shadow: inset 3px 0 0 var(--k-accent); }
.k-wizard__step--current .k-wizard__step-number { border-color: var(--k-accent); background: var(--k-accent); color: var(--k-bg); }
.k-wizard__step:disabled { cursor: default; color: var(--k-text-muted); border-color: var(--k-border); opacity: 1; }
.k-wizard__step:disabled .k-wizard__step-number { border-color: var(--k-border); }
/* Krug snimka (04a): kartice su od 04a obični <button>, pa ih tek sada pogađaju globalni `button:hover`
   (0,1,1 — ispuna --k-accent-hover, i na NEDOSTUPNOJ kartici) i `button:disabled` (opacity .4). Mock nema
   hover: pravila s kontejnerom (0,3,0) vraćaju karticu — bez ispune; dostupna dobiva suptilan rub
   naglaska; tekuća zadržava rub naglaska (lijevu traku i krug hover ne dira); nedostupna se ne mijenja.
   Prozirnost nedostupne kartice je samo na tekstu, pa rub kartice i kruga ostaju puni --k-border (mock). */
.k-wizard .k-wizard__step:hover { background: var(--k-surface); }
.k-wizard .k-wizard__step:not(:disabled):not(.k-wizard__step--current):hover { border-color: var(--k-accent); color: var(--k-text); }
.k-wizard .k-wizard__step--current:hover { border-color: var(--k-accent); }
.k-wizard .k-wizard__step:disabled:hover { border-color: var(--k-border); color: var(--k-text-muted); }
.k-wizard__step:disabled .k-wizard__step-text { opacity: .6; }
.k-wizard__step:disabled .k-wizard__step-number { color: var(--k-text-muted); }
@media (max-width: 720px) { .k-wizard__steps { grid-auto-flow: row; } }
/* 04b (web-04, DIZ-5): naslov s imenom i podnaslov (mock `.pagehead`/`.sub`, M:44-46) te sažetak kao
   drugi redak kartice (mock `.step small`, M:54) — obična slova, prigušeno; prelama se kao u mocku
   (`display: block`, bez `nowrap`), pa na uskom zaslonu ne gubi tekst trotočkom (snimka 04b, 360 px). */
.k-wizard__heading { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.k-wizard__subtitle { margin: 0; color: var(--k-text-muted); font-size: 13px; }
.k-wizard__step-summary {
    display: block; overflow-wrap: anywhere;
    color: var(--k-text-muted); font-size: 12px; font-weight: 400; text-transform: none; letter-spacing: 0;
}

/* ── Step 1's root parameters (W4 Task 5) ────────────────────────────────────────────────────────
   §5.2's properties come in groups (planning, repetition, geolocation, steps, ordering, exit), so the
   panel is a column of <fieldset>s and each of those a row of fields that wraps. Nothing here styles a
   DevExpress class name (docs.devexpress.com/Blazor/401740) — the editors are sized through the
   CssClass each one is given. */
.k-wizard__fields { display: flex; flex-wrap: wrap; gap: 12px 24px; }
.k-wizard__group {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin: 0;
    padding: 12px 16px 16px;
    border: 1px solid var(--k-border);
    border-radius: var(--k-radius-sm);
}
.k-wizard__group-title {
    padding: 0 4px;
    color: var(--k-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-size: 12px;
}
/* A checkbox carries its own label, so it is a row rather than a label-above-control column. */
.k-wizard__field--check { flex-direction: row; align-items: center; }
/* Step 3's weekly form (§5.5) is seven checkboxes on one line, so it is a field that holds a row of
   fields rather than one control — the column max-width the others get would wrap it into a stack. */
.k-wizard__field--weekdays { max-width: none; }
.k-wizard__number { max-width: 200px; }
.k-wizard__choice { max-width: 280px; }
.k-wizard__description { max-width: 420px; }
/* Ruling R4's field-level hint. Advisory, not an error state: the authoritative gate is Save, so this
   points at what will block it rather than claiming the field is broken. */
.k-wizard__hint { margin: 0; color: var(--k-warning); font-size: 12px; }
/* W-22 E45 (mock web-04 M:338 `.hint.err`): the start/end pair's complaint stands under End and IS an
   error — red, unlike R4's advisory hints above (warning). */
.k-wizard__hint.k-wizard__hint--error { color: var(--k-danger); }
/* W-22 E45 red edge of End: on the editor's ROOT (CssClass), never through a DevExpress class name
   (docs.devexpress.com/Blazor/401740); two classes because DevExpress themes carry more specific rules.
   box-shadow only, NO outline: outline is the focus ring's (`.k-wizard__choice:has(:focus-visible)`
   above), and a focused invalid End must keep that ring; nor border-color, because the DevExpress
   editor's own border is the theme's internal CSS, undocumented, so a colour set here may never show. */
.k-wizard__choice.k-wizard__choice--invalid {
    box-shadow: 0 0 0 1px var(--k-danger), 0 0 0 4px rgba(var(--k-danger-rgb), .18);
    border-radius: var(--k-radius-sm);
}
/* W-21 (a) (web-04 04c, DIZ-5): korak 1 kao dva stupca kartica — mock `.cols`/`.sec`/`.row` (M:56-59).
   Sekcija je JEDNA komponenta (WizardSection.razor). Polja u sekciji zauzimaju svoju ćeliju — granica
   420/280/200 px (gore) vrijedi samo izvan sekcija (podgrupa, korak 2). */
.k-wizard__panel--cols { padding: 0; border: 0; }
.k-wizard__cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; align-items: start; }
.k-wizard__col { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.k-wizard__section {
    display: flex; flex-direction: column; gap: 12px; min-width: 0; padding: 14px 18px 16px;
    background: var(--k-surface); border: 1px solid var(--k-border-strong); border-radius: var(--k-radius-lg);
}
.k-wizard__section-title {
    margin: 0; padding-bottom: 8px; border-bottom: 1px solid var(--k-border-strong);
    color: var(--k-accent); font-size: 14px; font-weight: 600; text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}
.k-wizard__section-summary { margin: 0; color: var(--k-text-muted); font-size: 13px; }
.k-wizard__section-hint { margin: 0; color: var(--k-text-muted); font-size: 12px; }
/* W-22 E43 (mock web-04 M:340 `.hint` in --label; #4016): the "Sljedeće" preview line reads in the
   label colour, not muted. Two classes so it outranks the general section-hint above. */
.k-wizard__section-hint.k-wizard__section-hint--next { color: var(--k-text-label); }
.k-wizard__row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 16px; align-items: end; }
.k-wizard__row--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.k-wizard__section .k-wizard__field, .k-wizard__section .k-wizard__number,
.k-wizard__section .k-wizard__choice, .k-wizard__section .k-wizard__description { max-width: none; }
/* W-06: crvena zvjezdica uz oznaku obaveznog polja (isti oblik kao .k-login__req, CSS:417; zajednički
   stil = ljuska G3, DIZ-1 — kad ga bude, ovo pravilo prelazi na njega). */
.k-wizard__req { margin-left: 3px; color: var(--k-danger); font-style: normal; }
.k-wizard__radios { max-width: none; }
@media (max-width: 960px) {
    .k-wizard__cols, .k-wizard__row, .k-wizard__row--three { grid-template-columns: minmax(0, 1fr); }
}
/* W-19 (a) (web-04, DIZ-5 04d1): mock `.split` (M:82) i `.addbar`/`.icons` (M:83-89). */
.k-structure__split { display: grid; grid-template-columns: 470px minmax(0, 1fr); gap: 14px; align-items: start; }
.k-structure__left { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.k-structure__editor-pane { min-width: 0; margin-top: 28px; }
.k-structure__addbar { display: flex; flex-direction: column; gap: 8px; }
.k-structure__addbar-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.k-structure__addbar-title {
    color: var(--k-text-label); font-size: 12px; font-weight: 600; text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}
.k-structure__template-link {
    all: unset; cursor: pointer; color: var(--k-accent-soft); font-size: 12px; font-weight: 600;
    text-transform: uppercase; letter-spacing: var(--k-label-tracking);
}
.k-structure__template-link:focus-visible, .k-structure__add:focus-visible { outline: var(--k-focus-ring); outline-offset: 2px; }
.k-structure__menu { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.k-structure__add {
    display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 8px 4px;
    border: 1px solid var(--k-border-strong); border-radius: var(--k-radius-md); background: var(--k-bg);
    color: var(--k-text-label); font: inherit; font-size: 11px; line-height: 1.15; text-align: center; cursor: pointer;
    letter-spacing: normal; /* globalni `button` nosi --k-label-tracking; mock M:87 ga nema (recenzija m1) */
}
.k-structure__add:disabled { cursor: default; opacity: .45; }
.k-structure__add--subgroup { border-color: var(--k-accent); color: var(--k-accent-soft); }
.k-structure__icon { width: 20px; height: 20px; color: var(--k-accent-soft); }
/* Naziv pločice se prelama unutar pločice (mock: tekst izravno u `span`, M:271-281); u flex stupcu s
   align-items: center dugi naziv („Skeniraj osobnu ili vozačku") inače može izaći preko ruba uske pločice. */
.k-structure__add-label { max-width: 100%; overflow-wrap: break-word; }
/* Pločice i link su obični <button>, pa ih pogađa globalni `button:hover` (0,1,1 — ispuna
   --k-accent-hover), isti nalaz kao kod kartica koraka u 04a. Mock nema hover: pravila s kontejnerom
   (0,3,0) vraćaju izgled mirovanja. */
.k-structure .k-structure__add:hover { background: var(--k-bg); border-color: var(--k-border-strong); }
.k-structure .k-structure__add--subgroup:hover { border-color: var(--k-accent); }
.k-structure .k-structure__template-link:hover { background: none; }
@media (max-width: 1100px) {
    .k-structure__split { grid-template-columns: minmax(0, 1fr); }
    .k-structure__editor-pane { margin-top: 0; }
}

/* The Save gate's answer (W4 Task 9). An ERROR state, unlike the hints above: the authoritative
   gate has spoken and the task was not saved, so the color says so. */
.k-wizard__save-errors { display: flex; flex-direction: column; gap: 4px; }
.k-wizard__save-error { margin: 0; color: var(--k-danger); font-size: 13px; }

/* §11.10's Exit warning and the Delete confirm (W4 Task 9) — a plain overlay, not a DevExpress
   popup (two sentences and two buttons need no positioning engine; see TaskWizard.razor). */
.k-wizard__modal-backdrop {
    position: fixed; inset: 0; z-index: 1000;
    background: var(--k-scrim);
    display: flex; align-items: center; justify-content: center;
}
.k-wizard__modal {
    background: var(--k-surface); border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius); padding: 20px; max-width: 440px; margin: 16px;
    display: flex; flex-direction: column; gap: 16px;
}
/* Mock web-04 .dlg (frame 3): the Exit warning is 520px. Two classes, so its max-width replaces the shell's 440px
   whatever the rule's place in the sheet. */
.k-wizard__modal.k-wizard__modal--exit { width: 520px; max-width: calc(100vw - 32px); }
.k-wizard__modal-text { margin: 0; }
/* B13 / W-04 (web-decisions :78): the Delete confirm's RED TITLE. 16/700 like every other delete confirm (the K2c
   confirm shell, mock web-10; the named exception to the 17/700 dialog title); the red outlined button is
   k-btn--danger-outline's (TaskWizard.razor), only the title is the wizard's own. */
.k-wizard__modal-title { margin: 0; font-size: 16px; font-weight: 700; }
.k-wizard__modal-title--danger { color: var(--k-danger); }
/* W-04 (web-decisions :78; mock web-04, frame 3): the Exit warning's title is CAPS cyan. Its 16/700 is the base rule's;
   two classes, so the colour does not depend on where the rule sits in the sheet. */
.k-wizard__modal-title.k-wizard__modal-title--exit { color: var(--k-accent); text-transform: uppercase; letter-spacing: .5px; }
.k-wizard__modal-actions { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; }

/* ── Step 2's structure editor (W4 Task 6) ───────────────────────────────────────────────────────
   §11.10: "the whole structure fits on a single screen". Since 04d1 (W-19 (a)) the panel is split:
   on the left the add bar, then the structure tree (04d2) — root first, its leaves, then each
   subgroup with its leaves; on the right whichever property screen is open. Nothing here styles a
   DevExpress class name (docs.devexpress.com/Blazor/401740): the tiles and the tree's rows are plain
   buttons styled by their own classes.

   Pločice trake „Dodaj u strukturu" nose ikone iz mocka (M:271-281, W-19), crtane rukom u
   StructureIcon.razor; raspored trake i podijeljenog prikaza je u bloku 04d1 iza koraka 1 (gore). */
/* Ruling R5's takeover notice: an announcement, not a failure — the operator got what they asked for
   and is being told what it cost. */
.k-structure__notice { margin: 0; color: var(--k-text); font-size: 13px; }
/* Naziv retka stabla (i E2E WizardSmokeTests ga traži po klasi). Veličinu nasljeđuje od retka (14px,
   mock `.tree .r`, M:91) — do 04d2 je bio 13px u panelu grupe. */
.k-structure__task-name { font-size: inherit; }
.k-structure__drag-hint { margin: 0; color: var(--k-text-muted); font-size: 12px; }
/* W-19 (a) stablo (mock `.tree`, M:90-105; DIZ-5 04d2): ravni retci s ručkom, ikonom, nazivom i
   oznakama; uvlaka listova korijena i podgrupa; označen redak cyan; cilj ispuštanja isprekidan. */
.k-structure__tree {
    margin: 0; padding: 0; list-style: none; overflow: hidden;
    border: 1px solid var(--k-border-strong); border-radius: var(--k-radius-lg);
}
.k-structure__row {
    display: grid; grid-template-columns: 22px 24px minmax(0, 1fr) auto; align-items: center; gap: 8px;
    padding: 8px 10px; border-bottom: 1px solid var(--k-border); font-size: 14px;
}
.k-structure__row:last-child { border-bottom: 0; }
.k-structure__row--root { background: rgba(var(--k-white-rgb), .03); font-weight: 600; }
.k-structure__row--group { font-weight: 600; }
.k-structure__row--indent { padding-left: 34px; }
.k-structure__row--indent2 { padding-left: 58px; }
.k-structure__row--selected { background: rgba(var(--k-accent-rgb), .14); box-shadow: inset 3px 0 0 var(--k-accent); }
.k-structure__row .k-structure__icon { width: 18px; height: 18px; color: var(--k-text-muted); }
.k-structure__row--root .k-structure__icon, .k-structure__row--group .k-structure__icon { color: var(--k-accent-soft); }
.k-structure__handle { color: var(--k-border-strong); letter-spacing: -2px; }
.k-structure__row[draggable="true"] .k-structure__handle::before { content: "⋮⋮"; }
.k-structure__row[draggable="true"] .k-structure__handle { cursor: grab; }
.k-structure__open { all: unset; min-width: 0; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.k-structure__open:focus-visible { outline: var(--k-focus-ring); outline-offset: 2px; }
/* Gumb retka je obični <button>, pa ga pogađa globalni `button:hover` (0,1,1 — ispuna
   --k-accent-hover), isti nalaz kao kod pločica 04d1: pravilo s kontejnerom (0,3,0) vraća mirovanje. */
.k-structure .k-structure__open:hover { background: none; }
.k-structure__meta { margin-left: 6px; color: var(--k-text-muted); font-weight: 400; }
.k-structure__meta::before { content: "· "; }
.k-structure__tags { display: flex; gap: 6px; }
.k-structure__tag {
    padding: 2px 6px; border: 1px solid var(--k-border-strong); border-radius: var(--k-radius-sm);
    color: var(--k-text-label); font-size: 10px; font-weight: 700; text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}
.k-structure__tag--accent { border-color: var(--k-accent); color: var(--k-accent-soft); }
.k-structure__tag--optional { border-style: dashed; color: var(--k-text-muted); }
.k-structure__drop {
    margin: 6px 10px 6px 58px; padding: 4px 10px; border: 1px dashed var(--k-accent);
    border-radius: var(--k-radius-md); color: var(--k-accent-soft); font-size: 12px;
}

/* §11.5's template source (§11.10 step 2: "template insertion also happens here — inserted as a copy").
   A boxed row like the palette, because it is the same kind of thing — another way of adding into the
   group the target line names — and not a property screen. */
.k-templates {
    display: flex;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: 8px;
    padding: 12px;
    border: 1px solid var(--k-border);
    border-radius: var(--k-radius-sm);
}
.k-templates__title { margin: 0; flex-basis: 100%; font-size: 14px; }
.k-templates__empty { margin: 0; color: var(--k-text-muted); font-size: 12px; }
/* The list was read when the screen opened; a template can be gone by the time it is inserted. */
.k-templates__unavailable { margin: 0; flex-basis: 100%; color: var(--k-warning); font-size: 12px; }

/* The two property screens the structure opens: a subgroup's §5.2 parameters, and a task's §5.3 + §5.4
   configuration. Both sit in the right-hand column beside the structure (W-19 a) — the structure is the
   context that gives them meaning. web-04 04e (DIZ-5): the box is the mock's `.editor` (M:107-111). */
.k-subgroup, .k-task {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 14px 18px 16px;
    background: var(--k-surface);
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-lg);
}
.k-subgroup__header, .k-task__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}
/* Mock `.editor .eh h2` (M:109): the editor's title in the accent colour, upper case. */
.k-subgroup__title, .k-task__title {
    margin: 0; color: var(--k-accent); font-size: 14px; font-weight: 600; text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}
.k-subgroup__scope { margin: 0; color: var(--k-text-muted); font-size: 12px; }
/* D12 (M:110): where the step lives, beside the type — plain case, muted. */
.k-task__where {
    margin-left: 8px; color: var(--k-text-muted); font-size: 12px; font-weight: 400; text-transform: none;
    letter-spacing: 0;
}
/* D16 (M:111): the editor's sub-heading ("Trajanje i ponavljanja"). */
.k-task__subhead {
    margin: 14px 0 0; color: var(--k-text-label); font-size: 12px; font-weight: 600; text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}
.k-task__section {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin: 0;
    padding: 12px 16px 16px;
    border: 1px solid var(--k-border);
    border-radius: var(--k-radius-sm);
}
.k-task__fields { display: flex; flex-direction: column; gap: 6px; }
.k-task__no-settings { margin: 0; color: var(--k-text-muted); font-size: 12px; }
/* §5.4/2's scan-ID state line (#754): "follows the company policy" is a statement of what the task
   does, not a warning, so it takes the muted text rather than the hint colour. Its counterpart, the
   "return to the policy" button, sits in a column flexbox and would stretch to the row otherwise. */
.k-task__id-scan-policy { margin: 0; color: var(--k-text-muted); font-size: 12px; }
.k-task__id-scan-return { align-self: flex-start; }
.k-task__group, .k-task__address { max-width: 280px; }
.k-task__name { max-width: 420px; }
.k-task__description, .k-task__question, .k-task__note { max-width: 420px; }
.k-subgroup__name { max-width: 420px; }
.k-subgroup__description { max-width: 420px; }
/* Focus on the EDITOR, not its inner input — Step 1's rule, for Step 2's editors. */
.k-subgroup__name:has(:focus-visible),
.k-subgroup__description:has(:focus-visible),
.k-task__name:has(:focus-visible),
.k-task__description:has(:focus-visible),
.k-task__question:has(:focus-visible),
.k-task__note:has(:focus-visible),
.k-task__address:has(:focus-visible),
.k-task__group:has(:focus-visible) {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
    border-radius: var(--k-radius-sm);
}
.k-subgroup__name input:focus-visible,
.k-task__name input:focus-visible,
.k-task__address input:focus-visible,
.k-task__group input:focus-visible,
.k-subgroup__description textarea:focus-visible,
.k-task__description textarea:focus-visible,
.k-task__question textarea:focus-visible,
.k-task__note textarea:focus-visible { outline: none; }

/* ── W3 Task 3: placeholder route contracts (plan R4) ───────────────────────────────────────────
   Seven detail routes plus two lists, all rendering the same three-part page: a heading, the
   identity of whatever the URL named, and the note saying the screen itself is still to come.
   Deliberately plain — a placeholder that looked designed would invite somebody to keep it. */
.k-placeholder {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px var(--k-page-gutter);
}
.k-placeholder__heading { margin: 0; font-size: 20px; }
.k-placeholder__identity { margin: 0; font-size: 16px; font-weight: 600; }
.k-placeholder__line { margin: 0; color: var(--k-text-muted); font-variant-numeric: tabular-nums; }
.k-placeholder__note, .k-placeholder__empty { margin: 0; color: var(--k-text-muted); }
.k-placeholder__list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 0;
    padding: 0;
    list-style: none;
}
.k-placeholder__row { display: flex; align-items: baseline; gap: 12px; }
.k-placeholder__link { color: var(--k-accent-soft); }
.k-placeholder__flag { color: var(--k-text-muted); font-size: 13px; }

/* ── Dashboard (§10.0) — W3 Task 6 ───────────────────────────────────────────────────────────────
   The landing page: a row of counter tiles over three mini-lists. Same page frame as every other
   menu (gutter + header), and nothing here invents a colour — the four tiles are one surface with
   one accent, because §10.0 gives them equal weight and the design reference has no per-tile
   palette. The value is the loud part; the label is the quiet one. */
.k-dashboard {
    display: flex;
    flex-direction: column;
    gap: 20px;
    padding: 16px var(--k-page-gutter);
}
.k-dashboard__title { margin: 0; font-size: 20px; }
.k-dashboard__loading { margin: 0; color: var(--k-text-muted); }

/* Auto-fit rather than four fixed columns: on a narrow screen the tiles wrap instead of shrinking
   their numbers into unreadability, and on a wide one they stay one row. */
.k-dashboard__tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 12px;
}
.k-tile {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 16px 18px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius);
    background: var(--k-surface);
    color: inherit;
    text-decoration: none;
}
.k-tile:hover { border-color: var(--k-accent); background: rgba(var(--k-accent-rgb), 0.05); }
.k-tile:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
/* W8 (T12): the system dashboard's three static tiles — a div, not a link (P8), so no hover
   invitation either: the base tile's hover accent would promise a navigation that isn't there. */
.k-tile--static:hover { border-color: var(--k-border-strong); background: var(--k-surface); }
.k-tile__value {
    font-size: 34px;
    line-height: 1;
    font-weight: 600;
    color: var(--k-accent-soft);
    font-variant-numeric: tabular-nums;
}
.k-tile__label {
    color: var(--k-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-size: 12px;
}

/* The three mini-lists, side by side where there is room and stacked where there is not. */
.k-dashboard__lists {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 12px;
    align-items: start;
}
.k-dashboard__list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 14px 16px;
    border: 1px solid var(--k-border);
    border-radius: var(--k-radius);
    background: var(--k-surface);
}
.k-dashboard__list-title { margin: 0; font-size: 14px; }
.k-dashboard__empty { margin: 0; color: var(--k-text-muted); font-size: 13px; }
.k-dashboard__rows {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 0;
    padding: 0;
    list-style: none;
}
.k-dashboard__row { border-top: 1px solid var(--k-border); padding-top: 6px; }
.k-dashboard__row:first-child { border-top: none; padding-top: 0; }

/* THE WHOLE ROW IS THE LINK (scen 46), so it must look like a row and not like a page of underlined
   links: the anchor inherits its colour and fills its line, and the pointer, the hover underline and
   the focus ring are what say it is clickable. A row that leads nowhere renders the __line-only
   sibling instead and therefore gets none of this (ruling R3's dangling half).
   K3a′ N2: own 14px (mock `.list a` web-03:96), not the 15px body (D3); the time keeps its 12px. */
.k-dashboard__link,
.k-dashboard__line-only {
    display: flex;
    align-items: baseline;
    gap: 10px;
    min-width: 0;
    padding: 4px 0;
    color: inherit;
    text-decoration: none;
    font-size: 14px;
}
.k-dashboard__link { cursor: pointer; }
.k-dashboard__link:hover .k-dashboard__line { text-decoration: underline; }
.k-dashboard__link:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
    border-radius: var(--k-radius-sm);
}
.k-dashboard__time {
    flex: none;
    color: var(--k-text-muted);
    font-size: 12px;
    font-variant-numeric: tabular-nums;
}
.k-dashboard__line { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── Global search omnibox (§10.8) — W3 Task 9 ───────────────────────────────────────────────────
   Two pieces: the trigger in the topbar's account column, and the dialog itself. The dialog's frame
   is DevExpress's DxPopup (BlazingDark theme), so only its body is styled here. */
/* Ekran 7, korak 6b: the trigger is "⌕ Pretraga [Ctrl][K]" (web-30 `.searchbtn`: 32px high, 0 10px,
   gap 8px, 13px, muted, border-strong) — AGAINST web-00's 30×30 icon, by the owner's "da" over
   web-30/30b on 24.9. The background stays transparent: web-30's --surface-2 has no token here. */
.k-topbar__search {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    height: 32px;
    padding: 0 10px;
    background: transparent;
    border: 1px solid var(--k-border-strong);
    color: var(--k-text-muted);
    font-size: 13px;
    font-weight: 400;
    letter-spacing: 0;
    white-space: nowrap;
}
.k-topbar__search:hover { background: transparent; border-color: var(--k-accent); color: var(--k-accent-soft); }
.k-topbar__search:focus-visible {
    outline: 2px solid var(--k-accent);
    outline-offset: 2px;
}
.k-topbar__search-icon { display: block; flex: none; }
.k-topbar__search-label { line-height: 1; }
/* web-30 `.searchbtn .kbd` — the same cap as the omnibox legend's .k-omnibox__key. */
.k-topbar__search-key {
    padding: 0 5px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    font-family: inherit;
    font-size: 11px;
    line-height: 16px;
    color: var(--k-text-label);
}
/* NARROW SCREEN — NOT FROM THE MOCK: web-30/30b draw no narrow topbar. Korak 6b's own decision: below
   1440px the word and the keys go and the button is web-00's 30×30 icon again; the accessible name is
   the aria-label, so nothing is lost to a screen reader. 1440 IS MEASURED, not the sheet's 1100 (Codex
   P2 on #2255): the topbar's three columns never shrink below their content, and the full trigger
   (153px against the icon's 23px) makes that content 1408px wide — at 1100 the full trigger pushed the
   logout past the window up to 1408px. With the icon the topbar needs 1285px, which is main's own
   width and a separate issue. */
@media (max-width: 1439px) {
    .k-topbar__search { width: 30px; height: 30px; padding: 0; }
    .k-topbar__search-label,
    .k-topbar__search-key { display: none; }
}

/* Wide enough for a location name plus its group heading, capped so the dialog never becomes a
   second page. The body scrolls rather than the window: three full groups is 30 rows. */
.k-omnibox-popup { width: min(560px, calc(100vw - 32px)); }
.k-omnibox {
    display: flex;
    flex-direction: column;
    gap: 12px;
    max-height: min(60vh, 520px);
    overflow-y: auto;
}
.k-omnibox__message { margin: 0; color: var(--k-text-muted); font-size: 13px; }
/* Ekran 7, korak 6: THE ROWS SCROLL, NOT THE PANEL — so the box above and the key legend below stay
   in view at 30 rows (web-30 A). min-height: 0 is what lets a flex child shrink under the panel's
   max-height; the panel keeps its own overflow only as the fallback for a very short viewport. */
.k-omnibox__groups { display: flex; flex-direction: column; gap: 14px; min-height: 0; overflow-y: auto; }
.k-omnibox__group { display: flex; flex-direction: column; gap: 6px; }
/* Korak 6: the heading is indented by the row's own 8px, so title and row text share one edge
   (web-30 A draws both at 13px). Size stays: the badge rule below cites THIS 12px. Korak 6b: the
   colour is web-30's --label through --k-text-label (was --k-text-muted), the token's one source. */
.k-omnibox__group-title {
    padding: 0 8px;
    margin: 0;
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-text-label);
}
.k-omnibox__hits { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
/* A hit is a full-width row that happens to be a link — same reasoning as the dashboard's rows:
   it must read as a row, not as a page of underlined text.
   #2058 (DM6 ruling (1)): the row is a FLEX line of two boxes — the name, which is the ONLY thing
   the ellipsis may shorten, and the out-of-service word, which never shrinks. With the ellipsis on
   the row itself the word came LAST in one nowrap line, so a long name (~80+ characters at the
   popup's width) pushed it past the edge and an inactive location read as an active one. */
.k-omnibox__hit {
    display: flex;
    align-items: baseline;
    padding: 6px 8px;
    color: var(--k-text);
    text-decoration: none;
    border-radius: var(--k-radius-sm);
    overflow: hidden;
    white-space: nowrap;
}
/* min-width: 0 is what lets a flex item shrink below its text's natural width — without it the name
   refuses to shorten and the ellipsis never appears. */
.k-omnibox__hit-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.k-omnibox__hit:hover { background: rgba(var(--k-accent-rgb), 0.08); color: var(--k-accent-soft); }
.k-omnibox__hit:focus-visible {
    outline: 2px solid var(--k-accent);
    outline-offset: -2px;
}
/* W8 (T13): the system search's hits — a span, not a link (their target is a tenant screen the super
   admin has no tenant context to open), so the row keeps its shape and loses the invitation: the base
   hit's hover accent would promise a navigation that isn't there. Same decision as .k-tile--static. */
.k-omnibox__hit--static { cursor: default; }
.k-omnibox__hit--static:hover { background: transparent; color: var(--k-text); }
/* Korak 6 — THE SELECTED ROW (web-30 A `.hit.sel`): a wash plus a 2px bar on the left edge, read off
   the selection HOOK because the row carries no class for it (SearchOmnibox.Group). AFTER both hover
   rules on purpose: same specificity, so the mouse passing over the selected row cannot erase it. */
.k-omnibox__hit[data-kerber-omnibox-selected] {
    background: rgba(var(--k-accent-rgb), 0.14);
    box-shadow: inset 2px 0 0 var(--k-accent);
}
/* Korak 6 — the KIND dot (web-30 A `.dot`). Decoration, not information: the group heading already
   SAYS the kind in words. An inline box inside the row, so the row's nowrap/ellipsis and the badge's
   place at the end (#2058) are untouched. Location is the base colour, the other two override it.
   THAT HOLDS FOR A BLOCK ROW ONLY: after #2210 (not merged yet) the row is display: flex with
   align-items: baseline, the dot becomes a flex item, and vertical-align below has no effect. */
.k-omnibox__hit[data-kerber-omnibox-hit]::before {
    content: "";
    display: inline-block;
    width: 6px;
    height: 6px;
    margin-right: 9px;
    border-radius: 50%;
    vertical-align: middle;
    background: var(--k-accent-soft);
}
/* #2196: the hook's value is `{kind}:{id}` (e.g. `worker:3`), so the kind is matched as a PREFIX that
   includes the colon — an exact `='worker'` would match nothing, and `^='worker'` without the colon
   would also catch a future kind that merely starts with the same letters. */
.k-omnibox__hit[data-kerber-omnibox-hit^='worker:']::before { background: var(--k-success); }
.k-omnibox__hit[data-kerber-omnibox-hit^='task:']::before { background: var(--k-warning); }
/* Korak 6 — the KEY LEGEND under the rows (web-30 A `.foot` + `.kbd`). Drawn only with rows on screen,
   which is when the keys do anything. Korak 6b: the key text is web-30's --label through
   --k-text-label (korak 6 used --k-text while that colour had no token). */
.k-omnibox__keys {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 14px;
    margin: 0;
    padding: 8px 8px 0;
    border-top: 1px solid var(--k-border);
    color: var(--k-text-muted);
    font-size: 12px;
}
.k-omnibox__keys > span { display: inline-flex; align-items: center; gap: 4px; }
.k-omnibox__key {
    padding: 0 5px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    font-family: inherit;
    font-size: 11px;
    line-height: 16px;
    color: var(--k-text-label);
}
/* §10.8's out-of-service mark is a WORD beside the name, never a colour on the row: a colour is not
   readable to a colour-blind operator, is not announced by a screen reader and does not survive a
   printout. So this rule spaces and quiets the word — it does not encode the fact. Muted, not
   coloured: a neutral grey tier, as .k-omnibox__group-title's is (korak 6b: --k-text-label). */
/* 12px and not 0.85em (design's ruling, measured): .k-omnibox__hit sets NO font-size, so a relative
   size here inherits from outside the panel — from the DevExpress popup — and the badge would resize
   with something we do not own. 0.85em was also the ONLY em font-size in this file (154 px, 12 rem,
   1 em). 12px is not a new number: .k-omnibox__group-title already spells "quieter text in this
   panel" as 12px, and this badge belongs to that class. Korak 6b moved the heading's colour to
   --k-text-label; the badge stays --k-text-muted, one tier quieter, because it qualifies a name
   rather than heading a group. */
.k-omnibox__hit-state { margin-left: 8px; color: var(--k-text-muted); font-size: 12px; flex-shrink: 0; }

/* ── Locations menu (§10.3) — W5 Task 2 ──────────────────────────────────────────────────────────
   The page chrome around a KerberMapGrid: a gutter, a header, the host's own narrowing controls, and
   the cell decorations §10.3's four columns need. The map+table layout itself is .k-mapgrid's. */
.k-locations {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px var(--k-page-gutter);
}
.k-locations__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}
/* The narrowing controls belong to the HOST, not to the grid (ADR 0010) — so they sit above the
   MapGrid rather than in the table's own toolbar. */
.k-locations__filters { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.k-locations__search { width: 280px; max-width: 100%; }
.k-locations__loading { margin: 0; color: var(--k-text-muted); }
.k-locations__empty { margin: 0; color: var(--k-text-muted); }
.k-locations__error { margin: 0; color: var(--k-danger); }

.k-loc-cell { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* web-05 B1 (REV-D 093040): the mock's .st cell (web-05-lokacije.html M:114-117, M:213-214) — the
   STATE is the 9 px dot, green with its glow for a check-in and grey for nobody, while the text stays
   neutral ("Nema prijave" muted, as the mock's td.muted). Only the NAME is cut: " · HH:mm +N" is the
   point of the cell and never shrinks (white-space: pre keeps its leading space at the flex edge);
   the whole text is in the cell's title. */
.k-loc-checkin { display: flex; align-items: center; min-width: 0; }
.k-loc-checkin--off { color: var(--k-text-muted); }
.k-loc-checkin__dot { flex: none; width: 9px; height: 9px; margin-right: 7px; border-radius: 50%; background: var(--k-text-muted); }
.k-loc-checkin--on .k-loc-checkin__dot { background: var(--k-success); box-shadow: 0 0 6px color-mix(in srgb, var(--k-success) 60%, transparent); }
.k-loc-checkin__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.k-loc-checkin__rest { flex: none; white-space: pre; }
.k-loc-type { color: var(--k-text); }
/* #4298 (GLOBALNO — svi birači datuma weba i navigator rasporeda, ako crta
   .dxbl-calendar): kalendar ne pokazuje broj tjedna. DxDateEdit 25.2.9 nema svojstvo skrivanja (XML: samo
   WeekNumberRule), a Fluent stupac crta klasom .dxbl-calendar-week-number i display ne postavlja. Mjera markupa
   (bUnit DxCalendar 25.2.9): redak zaglavlja tr.dxbl-calendar-days-of-week nosi iznad tog stupca jedan PRAZAN td,
   a dane kao th — zato se skriva i taj td, a th dana ostaju. */
.dxbl-calendar .dxbl-calendar-week-number,
.dxbl-calendar .dxbl-calendar-days-of-week > td {
    display: none;
}

/* web-05 B1 (D6): the type word as a PILL — the mock's .pill (web-05-lokacije.html, kadar 1), its
   geometry kept, its colours taken from the theme tokens rather than from the mock. */
.k-loc-pill {
    display: inline-block;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .5px;
    text-transform: uppercase;
    padding: 2px 7px;
    border-radius: var(--k-radius-sm);
    border: 1px solid var(--k-border-strong);
    color: var(--k-text-label);
}

/* §10.3'S FAVOURITES STAR. The two states differ by SHAPE (filled vs outline, decided in the markup)
   as well as by colour, so they are still distinguishable without colour vision — the same discipline
   §10.2's status icons follow. */
.k-loc-star {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 2px;
    border: none;
    border-radius: var(--k-radius-sm);
    background: transparent;
    cursor: pointer;
    line-height: 0;
}
.k-loc-star__glyph { width: 18px; height: 18px; }
.k-loc-star--on { color: var(--k-warning); }
.k-loc-star--off { color: var(--k-text-muted); }
/* #4254 (mock web-05 :118 `.star` draws no hover): the global button:hover (0,1,1) outranks
   .k-loc-star (0,1,0) and filled the star with the accent; this hover rule (0,2,0) restates the resting fill
   and border. Pin: GridHoverCssTests.Zvjezdica_lokacije_na_hover_mijenja_samo_boju. */
.k-loc-star:hover {
    color: var(--k-accent-soft);
    background: transparent;
    border: none;
}
.k-loc-star:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
/* #4254: the star column is 36 px (mock web-05 :211); with the grid's 12 px side padding the 22 px star overflowed
   to the right and the cell (overflow: hidden) cut 2 px off the focus ring's right side. 7 + 22 + 7 = 36 centres the
   star, and the ring (2 px + 2 px offset) stays 3 px inside the cell. Pin:
   GridHoverCssTests.Zvjezdica_lokacije_fokusni_obrub_stane_u_stupac_36px. */
[data-k-mapgrid='locations'] td.dxbl-grid-command-cell { --dxbl-grid-text-cell-padding-x: 7px; }

/* ── Workers menu (§10.4) — W6 Task 3 ────────────────────────────────────────────────────────────
   The page chrome around a KerberMapGrid — the Locations menu's shape (same gutter, same header,
   same host-owned narrowing controls), because it is the same §11.3.2 screen kind over different
   rows. The map+table layout itself is .k-mapgrid's. */
.k-workers {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px var(--k-page-gutter);
}
.k-workers__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}
/* The narrowing controls belong to the HOST, not to the grid (ADR 0010) — so they sit above the
   MapGrid rather than in the table's own toolbar. */
.k-workers__filters { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.k-workers__search { width: 280px; max-width: 100%; }
.k-workers__loading { margin: 0; color: var(--k-text-muted); }
.k-workers__empty { margin: 0; color: var(--k-text-muted); }
.k-workers__error { margin: 0; color: var(--k-danger); }
/* GPS (i): the last-position caveat under the grid (mock web-06 .gfoot) — muted, small, never an alarm. */
.k-workers__caveat { margin: 8px 0 0; color: var(--k-text-muted); font-size: .85em; }

/* A check-in is a STATE word, tinted rather than shouted; "no check-in" is muted so a full list
   reads as a list and not as an alarm board — the Locations check-in column's own treatment. */
.k-worker-cell { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.k-worker-checkin--on { color: var(--k-success); font-weight: 600; }
.k-worker-checkin--off { color: var(--k-text-muted); }
.k-worker-lastpos__main { white-space: nowrap; }
.k-worker-lastpos__detail { color: var(--k-text-muted); font-size: .85em; }
.k-worker-lastpos--never { color: var(--k-text-muted); }

/* ── Location operational view shell (§10.3) — W5 Task 3 ─────────────────────────────────────────
   Header + seven-tab strip + one body slot. The tabs are plain links (they ARE addresses); the
   active one is marked by an accent underline, not by colour alone. Tab bodies land here in
   Tasks 4–10. */
.k-location-view {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px var(--k-page-gutter);
}
.k-location-view__header { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.k-location-view__loading { margin: 0; color: var(--k-text-muted); }
.k-location-view__not-found { margin: 0; color: var(--k-text-muted); }
.k-location-view__tabs {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
    border-bottom: 1px solid var(--k-border);
}
.k-location-view__tab {
    padding: 8px 12px;
    /* K3c rez B: web-05-lokacije.html:128 .tabs span */
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-text-muted);
    text-decoration: none;
    border-bottom: 2px solid transparent;
    white-space: nowrap;
}
.k-location-view__tab:hover { color: var(--k-text); }
.k-location-view__tab--active {
    color: var(--k-text);
    font-weight: 600;
    border-bottom-color: var(--k-accent);
}
.k-location-view__tab:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-location-view__stub { color: var(--k-text-muted); }
/* Scen 32: the failed tab's own block — the shell around it stays untinted. */
.k-location-view__tab-error {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
.k-location-view__tab-error-text { margin: 0; color: var(--k-danger); }
.k-location-view__tab-retry {
    padding: 4px 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    background: var(--k-surface);
    color: var(--k-text);
    cursor: pointer;
}
.k-location-view__tab-retry:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* ── Location General tab (§10.3 tab 1) — W5 Task 4, web-05 PR E2 ────────────────────────────────
   Mock k2 (web-05-lokacije.html, .cols/.sec/.kv/.li/.qrbox): THREE CARDS IN THREE COLUMNS — Podaci
   (a caption/value grid), Radna mjesta above Dokumenti (rows: name, a small line under it, a link on
   the right), and the QR on white. The mock's tokens map one to one: --primary → --k-accent,
   --primary-soft → --k-accent-soft, --label → --k-text-label, --muted → --k-text-muted. */
.k-location-general {
    display: grid;
    grid-template-columns: 1.2fr 1fr 1fr;
    gap: 14px;
    align-items: start;
}
/* Narrower than three readable cards: one column, in the same order. */
@media (max-width: 1100px) {
    .k-location-general { grid-template-columns: 1fr; }
}
.k-location-general__loading,
.k-location-general__not-found { margin: 0; color: var(--k-text-muted); }
.k-location-general__column {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;
}
.k-location-general__card {
    background: var(--k-surface);
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius);
    padding: 14px 18px 16px;
}
.k-location-general__title {
    margin: 0 0 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--k-border-strong);
    font-size: 14px;
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    color: var(--k-accent);
}
.k-location-general__fields {
    display: grid;
    grid-template-columns: 130px 1fr;
    gap: 6px 12px;
    margin: 0;
    font-size: 14px;
}
.k-location-general__caption {
    padding-top: 2px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    color: var(--k-text-label);
}
.k-location-general__value { margin: 0; min-width: 0; color: var(--k-text); overflow-wrap: anywhere; }
.k-location-general__empty { margin: 0; color: var(--k-text-muted); }
.k-location-general__list {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
}
.k-location-general__row {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid var(--k-border);
    font-size: 14px;
}
.k-location-general__row:last-child { border-bottom: 0; }
.k-location-general__row-main { display: flex; flex-direction: column; min-width: 0; }
.k-location-general__position,
.k-location-general__document-name { color: var(--k-text); overflow-wrap: anywhere; }
.k-location-general__row-meta { font-size: 12px; color: var(--k-text-muted); }
.k-location-general__row-link {
    flex: none;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    color: var(--k-accent-soft);
    text-decoration: none;
}
.k-location-general__row-link:hover { text-decoration: underline; }
.k-location-general__row-link:focus-visible,
.k-location-general__button:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-location-general__qr-layout { display: flex; align-items: flex-start; gap: 14px; }
/* THE QR SITS ON WHITE, in the dark theme's middle — the .k-qr-sheet rule's reason: a code drawn in
   the theme's colours is not the code the printer and the phone camera will see. */
.k-location-general__qr-box {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    box-sizing: border-box;
    width: 180px;
    padding: 12px;
    border-radius: var(--k-radius-lg);
    background: #fff;
}
/* The QR is a scanned artefact, so it is never smoothed: a resampled module edge is what a phone
   camera fails on. */
.k-location-general__qr {
    width: 156px;
    height: 156px;
    image-rendering: pixelated;
}
.k-location-general__qr-name {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    text-align: center;
    color: var(--k-bg);
    overflow-wrap: anywhere;
}
.k-location-general__qr-actions { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
/* Mock .btn.sec.sm. */
.k-location-general__button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 28px;
    padding: 0 10px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    background: transparent;
    color: var(--k-text);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    text-decoration: none;
    white-space: nowrap;
}
.k-location-general__button:hover { border-color: var(--k-accent); }
.k-location-general__hint { margin: 0; font-size: 12px; color: var(--k-text-muted); }
/* #4421 — "Trenutno" (mock web-05b-lokacija-trenutno.html, .sec.now): the one card of the tab with an
   accent edge, a small caption over the list and over today's tasks, one row per checked-in worker with
   the shared status dot and the name as a link, and today's tasks under a strong hairline. */
.k-location-general__now {
    border-color: var(--k-accent);
    box-shadow: 0 0 0 1px rgba(var(--k-accent-rgb), .25);
}
.k-location-general__now-caption {
    margin: 0 0 4px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    color: var(--k-text-label);
}
.k-location-general__now-list { margin: 0; padding: 0; list-style: none; }
.k-location-general__now-row {
    margin: 0;
    padding: 7px 0;
    border-bottom: 1px solid var(--k-border);
    font-size: 14px;
    color: var(--k-text);
    overflow-wrap: anywhere;
}
.k-location-general__now-row:last-child { border-bottom: 0; }
.k-location-general__now-row--empty { color: var(--k-text-muted); }
/* The status dot's spacing, on a class of this section: the shared status-dot primitive keeps its one rule. */
.k-location-general__now-dot { margin-right: 6px; vertical-align: 1px; }
.k-location-general__now-worker { font-weight: 500; color: var(--k-accent-soft); text-decoration: none; }
.k-location-general__now-worker:hover { text-decoration: underline; }
.k-location-general__now-worker:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-location-general__now-tasks {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--k-border-strong);
}
.k-location-general__now-line { margin: 0; font-size: 14px; color: var(--k-text); }
.k-location-general__now-hint { margin-top: 10px; }

/* ── Location Notifications tab (§10.3 tab 2) — W5 Task 5 ────────────────────────────────────────
   The tab is a host: the grid inside it is the SAME KerberGrid the §10.1 menu uses and carries its
   own styling (the red error row included), so all this block owns is the loading line and the block
   the grid sits in. Nothing here restyles a notification — a row that looked different inside a
   location than in the global feed would contradict the tab's whole point. */
.k-location-notifications {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.k-location-notifications__loading { margin: 0; color: var(--k-text-muted); }
/* web-07 2b T27 — THE OWNER'S LAYOUT P114 (11.10. 00:57 „P114 da", ARH-C 005821; replaces mock k3's „u jednom retku",
   which today's fields cannot fill: 1063 px of tools beside ~480 px of chips in a 1310 / 1384 px bar, T26 v2):
   on BOTH notification tabs the bar is TWO rows — row 1 the type chips (ToolbarLead), row 2 the tools on a line of
   their own: the period (buttons + dates) from the LEFT edge, the search and „Izvoz" against the RIGHT edge. Scoped to
   the two tab hosts only; the menu (§10.1) and every other KerberGrid keep the shell's `.k-grid__tools` (right, r.1293).
   (0,2,0) each: beats `.k-grid__tools` (0,1,0); `.k-grid .k-grid__search` (0,2,0) sets only the width. */
.k-location-notifications .k-grid__tools,
.k-worker-notifications .k-grid__tools { flex-basis: 100%; margin-left: 0; }
.k-location-notifications .k-grid__search,
.k-worker-notifications .k-grid__search { margin-left: auto; }
/* The SAME `flex: none` as `.k-grid__export` (r.1324), but at (0,2,0): `.k-grid__export` is the CssClass of the very
   `dxbl-toolbar` DevExpress styles at (0,1,0), so at equal specificity source order decides, and once the search takes
   `margin-left: auto` the toolbar STRETCHES over the free space with its button left behind it (P114 simulation v1 /
   v2, REV-D 010528). Not a duplicate — mutant M27c removes it and the export leaves the right edge. */
.k-location-notifications .k-grid__export,
.k-worker-notifications .k-grid__export { flex: 0 0 auto; }

/* ── Location Tasks tab (§10.3 tab 3) — W5 Task 6 ────────────────────────────────────────────────
   A host, like the tab above it: the grid, the §11.0 selector row, the status icons and the review
   panel are all the §10.2 menu's own components and carry their own rules (.k-tasks__period and
   .k-task-* above). All this block owns is the column the tab's parts stack in and its loading line
   — a task styled differently inside a location than in the menu would contradict scen 50. */
.k-location-tasks {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.k-location-tasks__loading { margin: 0; color: var(--k-text-muted); }

/* ── Location Calendar tab (§10.3 tab 4) — W5 Task 7 ─────────────────────────────────────────────
   A host, like the two tabs above it: the calendar inside is W2's own KerberCalendar and keeps its own
   rules (.k-calendar further up) — the shift backdrop, the appointment template and the unavailable
   banner are all W2's, and a calendar styled differently inside a location than on any other surface
   would contradict scen 65. All this block owns is the column the tab's parts stack in. */
.k-location-calendar {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* ── Location Check-ins & check-outs tab (§10.3 tab 5) — W5 Task 8 ───────────────────────────────
   A host, like the tabs above it: the grid inside is the SAME KerberGrid every other Kerber surface
   uses and carries its own styling. All this block owns is the column the tab's parts stack in, its
   two controlled lines, and the one thing that IS this tab's own — the working-day control. */
.k-location-checkins {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.k-location-checkins__loading,
.k-location-checkins__empty { margin: 0; color: var(--k-text-muted); }
/* The em-dash of an open day reads as a value, not as a heading: same size as a moment, quieter. */
.k-location-checkins__moment { color: var(--k-text); }
/* One control per row, sized and lit like §10.2's review control — a location's grids should not
   sprout a different affordance for the same gesture. */
.k-location-checkins__working-day {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 28px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    color: var(--k-accent-soft);
}
.k-location-checkins__working-day:hover {
    background: rgba(var(--k-accent-rgb), 0.1);
    border-color: var(--k-border-strong);
}
.k-location-checkins__working-day:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-location-checkins__glyph { width: 16px; height: 16px; }

/* ── Location Incidents tab (§10.3 tab 6) — W5 Task 9 ────────────────────────────────────────────
   A host, like the tabs above it: the grid inside is the SAME KerberGrid every other Kerber surface
   uses. All this block owns is the column the tab's parts stack in, its two controlled lines, and the
   two cells that carry meaning of their own — the §9 state and the row's link. */
.k-location-incidents {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.k-location-incidents__loading,
.k-location-incidents__empty { margin: 0; color: var(--k-text-muted); }
/* The em-dash of an open incident reads as a value, not as a heading: same size as a moment, quieter. */
.k-location-incidents__moment,
.k-location-incidents__category { color: var(--k-text); }
.k-location-incidents__photos { color: var(--k-text-muted); }
/* The §9 state is told apart by a WORD first (the cell's text) and by colour only in support of it —
   never by colour alone. */
.k-location-incidents__state--open { color: var(--k-warning); }
.k-location-incidents__state--resolved { color: var(--k-success); }
/* web-09 H3 (mock .st, M:161-162): the state's glyph in front of the word — the open bubble in the
   warning colour, the resolved tick in the success colour. It only supports the word, never replaces it. */
.k-location-incidents__state-icon {
    display: inline-flex;
    width: 20px;
    height: 20px;
    align-items: center;
    justify-content: center;
    margin-right: 4px;
    vertical-align: middle;
}
.k-location-incidents__state-icon svg { width: 17px; height: 17px; }
.k-location-incidents__state-icon--open { color: var(--k-warning); }
.k-location-incidents__state-icon--resolved { color: var(--k-success); }
/* web-09 H8 (mock .thumbs, M:160): the row's own thumbnails in front of the count, 26x20 each. The
   browser fetches the whole image (there is no thumbnail endpoint), so the cell scales it down. */
.k-location-incidents__thumbs {
    display: inline-flex;
    gap: 4px;
    margin-right: 6px;
    vertical-align: middle;
}
.k-location-incidents__thumbs:empty { display: none; }
.k-location-incidents__thumb {
    width: 26px;
    height: 20px;
    border: 1px solid var(--k-border-strong);
    border-radius: 3px;
    object-fit: cover;
}
/* The row's door into the incident: a plain link, lit like every other in-grid link in the app. */
.k-location-incidents__link { color: var(--k-accent-soft); text-decoration: none; }
.k-location-incidents__link:hover { text-decoration: underline; }
.k-location-incidents__link:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* ── Incident detail (§9) — W5 Task 9 ────────────────────────────────────────────────────────────
   The one screen a §10.1 incident row and a §10.3 tab-6 row both land on: a header, the description, and
   the R8 media seam's own block (.k-task-media) below it — since web-09 PR-3a in the left of two columns. */
/* The page's left/right edge: the shell is gutterless (.k-page), so every page root carries
   `16px var(--k-page-gutter)` itself, as .k-wd does — without it the incident sat on x = 0
   (web-decisions.md:167, gutter 28 px; mock web-09 .pad). */
.k-incident {
    display: flex;
    flex-direction: column;
    gap: 20px;
    max-width: var(--k-page-max);
    padding: 16px var(--k-page-gutter);
}
.k-incident__loading,
.k-incident__not-found { margin: 0; color: var(--k-text-muted); }
.k-incident__header {
    display: flex;
    align-items: baseline;
    gap: 12px;
    flex-wrap: wrap;
}
.k-incident__title { margin: 0; font-size: 20px; }
.k-incident__state--open { color: var(--k-warning); }
.k-incident__state--resolved { color: var(--k-success); }
.k-incident__caption {
    margin: 0;
    font-size: 12px;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    color: var(--k-text-muted);
}
.k-incident__location-link { color: var(--k-accent-soft); text-decoration: none; }
.k-incident__location-link:hover { text-decoration: underline; }
.k-incident__location-link:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-incident__section { display: flex; flex-direction: column; gap: 8px; }
/* The description is voice-first free text (§9): it keeps the line breaks the worker dictated. */
.k-incident__description { margin: 0; color: var(--k-text); white-space: pre-wrap; }
/* web-09 PR-4a (mock web-09 M:121-122, `.photos` / `.ph`; owner 186, 7.10.2026): the incident's photos, ONE TILE
   PER PHOTO, five columns to a row, 4:3 each (IncidentPhotoGrid). A photo covers its tile; no empty place is drawn,
   and an incident with no photo gets the muted sentence .k-incident__empty instead of the grid. The
   tile is the mock's indigo-grey gradient from the theme's own tokens (--k-border-strong → --k-accent-indigo, the
   mock's #2b3350 → #3d4870 family), as .k-task-record__thumb has it. Not drawn, on purpose: the capture time on a
   tile (M:124, E1) and the ::after sheen (M:123). */
.k-incident__photo-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; }
.k-incident__photo {
    aspect-ratio: 4 / 3;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    background: linear-gradient(135deg, var(--k-border-strong), var(--k-accent-indigo));
    overflow: hidden;
}
.k-incident__photo-img { display: block; width: 100%; height: 100%; object-fit: cover; }
.k-incident__empty { margin: 0; color: var(--k-text-muted); }

/* ── Incident detail header — web-09 PR-1 (C1, C2, C3, C9–C11) ──────────────────────────────────────
   The header as the approved mock docs/design/mocks/web-09-incident.html draws it in kadar 1 (open) and
   kadar 2 (resolved), by its selectors `.win .hd h2`, `.state`/`.state.open`/`.state.done` and
   `.win .hd .meta`. Placed AFTER the W5 block on purpose: the title and header rules above stay as W5
   wrote them and this block, being later at the same specificity, is what the page draws. */
.k-incident__header { align-items: center; }
.k-incident__title {
    font-size: 18px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-accent);
}
/* C2 — the state pill: the word in its state's colour, a hairline of the same colour and a 12 % wash of
   it (mock `.state.open` / `.state.done`). The wash is mixed from the token itself, so no colour literal
   enters the sheet and the pill follows the token if the token ever moves. */
.k-incident__state {
    display: inline-block;
    padding: 3px 8px;
    border: 1px solid;
    border-radius: var(--k-radius-sm);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    line-height: normal;
}
.k-incident__state--open {
    border-color: var(--k-warning);
    background: rgba(var(--k-warning-rgb), .12);
}
.k-incident__state--resolved {
    border-color: var(--k-success);
    background: rgba(var(--k-success-rgb), .12);
}
/* C3 — ONE meta row of „Oznaka: vrijednost" items that wraps (mock `.win .hd .meta`): captions in the
   label tier, values in the text tier. The row carries no class of its own (commit B kept the markup
   free of new k- classes), so it is found by what it holds: the direct children stamped
   data-kerber-incident-meta. It sits 6px under the title, as in the mock, inside the page's 20px gap. */
.k-incident > div:has(> [data-kerber-incident-meta]) {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 18px;
    margin-top: -14px;
    color: var(--k-text-label);
    font-size: 14px;
}
.k-incident [data-kerber-incident-meta] b { color: var(--k-text); font-weight: 600; }
/* C9 — „(web)" is a qualifier of the name, one tier quieter than it (mock: the suffix in --muted). */
.k-incident [data-kerber-incident-resolved-by] > span { color: var(--k-text-muted); }
/* C10 + Q2a (owner) — the working day's range on TWO lines, „{od} –" over „{do}": the stamped range is
   one inline box beside „radni dan" whose child blocks (no class of their own) stack; an open day has
   one block. Top-aligned so the first line sits on the meta row's line. */
.k-incident [data-kerber-incident-working-day] { display: inline-block; vertical-align: top; }
.k-incident [data-kerber-incident-working-day] > span { display: block; }

/* ── Incident resolution — web-09 PR-2 (D5–D8, G1–G4, G7) ───────────────────────────────────────────
   The "Rješavanje" box as the approved mock docs/design/mocks/web-09-incident.html draws it (`.res`,
   `.res .t`, `.btn.ok` in kadar 1 and 2) and its confirmation (`.dlg`, kadar 3). Every colour is a theme
   token; the washes are rgba() over the -rgb tokens, and no colour is written as a literal. The green
   button is a plain <button> painted from --k-success (FIX106: no DxButton render style), its text the
   dark on-accent token (the mock writes that dark green as a literal, so the token closest in role stands
   in for it). */
.k-incident__res {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 14px;
    padding: 12px 14px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-lg);
    background: var(--k-bg);
}
.k-incident__res-note { font-size: 13px; color: var(--k-text-muted); }
.k-incident__res-button {
    padding: 6px 14px;
    border: 1px solid var(--k-success);
    border-radius: var(--k-radius-md);
    background: var(--k-success);
    color: var(--k-btn-text-on-accent);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
.k-incident__res-button:hover:not([disabled]) { background: rgba(var(--k-success-rgb), .85); }
.k-incident__res-button:focus-visible,
.k-incident__confirm-cancel:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-incident__res-button[disabled] { opacity: .6; cursor: default; }
/* k2 — the record: the check and "Riješen {kad} · {ime}" in the success colour (mock `.st.ok`). */
.k-incident__res-done {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--k-success);
    font-weight: 600;
}
.k-incident__res-icon { width: 17px; height: 17px; flex: none; }
/* G7 — the outcome lines: AlreadyResolved is information (a success wash), Refused/Conflict/Failed are a
   refusal (a danger wash), both as quiet bands under the box or inside the confirmation. */
.k-incident__res-notice,
.k-incident__res-message {
    margin: 0;
    padding: 8px 12px;
    border: 1px solid;
    border-radius: var(--k-radius-sm);
    font-size: 13px;
    color: var(--k-text);
}
.k-incident__res-notice {
    border-color: var(--k-success);
    background: rgba(var(--k-success-rgb), .08);
}
.k-incident__res-message {
    border-color: var(--k-danger);
    background: rgba(var(--k-danger-rgb), .06);
}
/* k3 — the confirmation (mock `.dlg`): 460 px set on the popup, capped on a narrow screen. */
.k-incident__confirm-popup { max-width: 95vw; }
.k-incident__confirm { display: flex; flex-direction: column; gap: 14px; }
.k-incident__confirm-text { margin: 0; font-size: 14px; color: var(--k-text-label); }
.k-incident__confirm-actions { display: flex; gap: 10px; justify-content: flex-end; }
.k-incident__confirm-cancel {
    padding: 6px 14px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    background: var(--k-surface);
    color: inherit;
    font: inherit;
    cursor: pointer;
}
.k-incident__confirm-cancel[disabled] { opacity: .6; cursor: default; }

/* ── Incident detail body and map — web-09 PR-3a (D1, F1, F7) ─────────────────────────────────────────
   The two columns of the approved mock docs/design/mocks/web-09-incident.html: `.win .bd` M:116 (1fr and a
   440 px map column), `.l` M:117, `.r` M:141-142. They sit on a wrapper of their own, not on .k-incident,
   which stays the page's flex column. The map frame is `.map` M:129 (at least 380 px tall, filling the
   column); its caption `.map .ttl` M:132 sits in the top-left corner OVER the canvas — later in the markup
   and WITHOUT a z-index, because the theme's z-index owners are a closed set (MapSwitchStackingTests). The
   no-fix panel is `.map .nogps` M:138-140; the mock's #0d1220 frame and #5B6482 note have no token of their
   own, so the frame takes --k-surface (as .k-map does) and the note --k-text-muted. One column below
   1100 px, as the working-day split does. */
.k-incident__body {
    display: grid;
    grid-template-columns: 1fr 440px;
    gap: 20px;
    align-items: stretch;
}
.k-incident__main { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
.k-incident__side { display: flex; flex-direction: column; min-width: 0; }
.k-incident__map {
    position: relative;
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 380px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-lg);
    overflow: hidden;
    background: var(--k-surface);
}
/* The frame above owns the border; the map inside fills it. #4635 (PEČAT REV-B U2): the frame is a flex
   column and the map FLEXES rather than taking height: 100%, which under the frame's overflow: hidden would
   cut off the accuracy strip below it. The canvas keeps its 380 px, so beside the strip the frame grows to
   about 418 px instead of shrinking the canvas (REV 112604 t.3). */
.k-incident__map .k-map { flex: 1 1 auto; border: 0; border-radius: 0; }
.k-incident__map .k-map__canvas { height: 100%; min-height: 380px; }
/* #4635 (owner 24.10., layout B; mock tocnost-uz-kartu-incidenta-v2 `.strip`/`.glyph`): „±n m" VISIBLE in a
   strip under the canvas, inside the frame, aria-hidden beside the screen-reader description. The ring glyph
   is a CSS circle (no SVG), drawn only above 0 m; neither carries a z-index (MapSwitchStackingTests). */
.k-incident__map-accuracy {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 14px;
    border-top: 1px solid var(--k-border-strong);
    font-size: 13px;
    color: var(--k-text);
}
.k-incident__map-accuracy-ring {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 1px dashed rgba(var(--k-accent-rgb), .8);
    background: rgba(var(--k-accent-rgb), .12);
    flex: none;
}
.k-incident__map-title {
    position: absolute;
    left: 12px;
    top: 10px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    color: var(--k-text-label);
    pointer-events: none;
}
.k-incident__nogps {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 0 24px;
    text-align: center;
    font-size: 14px;
    color: var(--k-text-muted);
}
.k-incident__nogps-icon { width: 34px; height: 34px; }
.k-incident__nogps-text { color: var(--k-text-muted); }
.k-incident__nogps-note { font-size: 12px; color: var(--k-text-muted); }
/* nit 3: the fix's screen-reader description (the frame's aria-describedby) — clipped to a 1px box rather
   than display:none / visibility:hidden, which would hide it from the reader too; .k-task-measure__violation's
   rule, since no shared sr-only class exists in this sheet. No z-index (a closed set, MapSwitchStackingTests). */
.k-incident__map-fix {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}
@media (max-width: 1100px) {
    .k-incident__body { grid-template-columns: 1fr; }
}

/* ── Location Visits tab (§10.3 tab 7) — W5 Task 10 ──────────────────────────────────────────────
   A host, like the tabs above it: the grid inside is the SAME KerberGrid every other Kerber surface
   uses. What this block owns is the column the tab's parts stack in, its controlled lines, the two
   per-row commands, and the edit dialog — the wizard's plain overlay (two handfuls of fields and two
   buttons need no positioning engine), with the wizard's exact backdrop. */
.k-location-visits {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.k-location-visits__loading,
.k-location-visits__empty { margin: 0; color: var(--k-text-muted); }
/* The controlled failure lines (scen 102/104): a statement, not a crash — coloured like every other
   inline error in the app. */
.k-location-visits__error { margin: 0; color: var(--k-danger); font-size: 13px; }
/* The em-dash of an open visit reads as a value, not as a heading: same size as a moment, quieter. */
.k-location-visits__moment { color: var(--k-text); }
/* C10 „Upiši odlazak" (N2, K-2): the mock's BARE link (.act under .g td a, M:71/M:181) — no frame,
   no fill, the soft accent at 600, underlined on hover. Still a <button> (it runs a command, not a
   navigation), so the browser's button chrome is reset; keyboard focus and [disabled] stay. */
.k-location-visits__action {
    display: inline;
    padding: 0;
    margin: 0;
    border: 0;
    background: transparent;
    font: inherit;
    font-weight: 600;
    color: var(--k-accent-soft);
    white-space: nowrap;
    text-decoration: none;
    cursor: pointer;
}
.k-location-visits__action:hover:not([disabled]) { text-decoration: underline; }
.k-location-visits__action:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-location-visits__action[disabled] { opacity: 0.5; cursor: default; }
/* web-11 P1 — the mock's merged cells (docs/design/mocks/web-11-posjete.html, k1, styles M:213-218).
   C3: an open visit's „u objektu" in the success colour (the mock's green .live), its time on site on
   a quieter second line — the same second-line style as C6's „OIB {broj}".
   N3 (K-2): drawn as the mock's .live (M:58-59) — an 8 px dot before it, capitals and the mock's
   letter spacing. The WORD in the markup stays „u objektu" (resx); only its drawing changes. The
   mock's blinking belongs to liveness, outside P1, so the dot is still. */
.k-location-visits__onsite {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--k-success);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.k-location-visits__onsite::before {
    content: "";
    width: 8px;
    height: 8px;
    flex: none;
    border-radius: 50%;
    background: currentColor;
}
.k-location-visits__sub { display: block; font-size: 12px; color: var(--k-text-muted); }
.k-location-visits__stack { display: inline-flex; flex-direction: column; }
/* C4 (.who) and C7 (.veh): icon + text on one line; the icon is the muted 16 px glyph. */
.k-location-visits__who,
.k-location-visits__vehicle { display: inline-flex; align-items: center; gap: 6px; }
.k-location-visits__glyph { width: 16px; height: 16px; flex: none; color: var(--k-text-muted); }
/* „samo vozilo": a statement about the visit, not a name — muted (the mock's .muted). */
.k-location-visits__muted { color: var(--k-text-muted); }
/* W-24: the name is the way into the edit dialog, so it reads as a link — a QUIET one, the Tasks
   name link's weighting (.k-tasks__name-link): the cell's own colour at rest, the accent and the
   underline on hover and keyboard focus. A <button>, because it opens a dialog rather than an
   address, so the browser's button chrome is reset here. */
.k-location-visits__name-link {
    padding: 0;
    border: 0;
    background: transparent;
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}
/* web-11 P1 G: „samo vozilo" is the same quiet link-button, MUTED at rest (the base rule's
   `color: inherit` would otherwise win over .k-location-visits__muted, which comes earlier); placed
   BEFORE :hover/:focus-visible at equal specificity, so hover and focus still take the accent. */
.k-location-visits__name-link.k-location-visits__muted { color: var(--k-text-muted); }
.k-location-visits__name-link:hover,
.k-location-visits__name-link:focus-visible {
    color: var(--k-accent);
    text-decoration: underline;
}
.k-location-visits__name-link:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
/* C7: the registration drawn AS a plate (the mock's .plate, M:216). */
.k-location-visits__plate {
    display: inline-block;
    padding: 1px 6px;
    border: 1px solid var(--k-text-label);
    border-radius: var(--k-radius-sm);
    background: rgba(var(--k-white-rgb), 0.07);
    color: var(--k-text);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 1px;
}
.k-location-visits__modal-backdrop {
    position: fixed; inset: 0; z-index: 1000;
    background: var(--k-scrim);
    display: flex; align-items: center; justify-content: center;
}
/* web-11 P4 — the edit dialog drawn as the mock's k2 (.dlg.form.w, docs/design/mocks/web-11-posjete.html
   M:186-227). D2: 680 px wide, three parts — header, body, footer — with a rule between each; the
   frame itself is padding-free so the rules run edge to edge. Every value is a --k-* token or the
   mock's own measure. */
.k-location-visits__modal {
    width: 680px; max-width: calc(100vw - 32px); margin: 16px;
    background: var(--k-surface); border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius); box-shadow: var(--k-shadow-dialog);
    display: flex; flex-direction: column;
    max-height: calc(100vh - 32px); overflow-y: auto;
}
/* D1 (mock .fh, M:187-189): the title in capitals and the accent, the ✕ quiet at the far right. */
.k-location-visits__modal-head {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 14px 20px;
    border-bottom: 1px solid var(--k-border-strong);
}
.k-location-visits__modal-title {
    margin: 0;
    font-size: 17px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-accent);
}
/* The ✕ is a real <button> (it closes the dialog), so the browser's button chrome is reset. */
.k-location-visits__dismiss {
    padding: 0 4px;
    border: 0;
    background: transparent;
    font: inherit;
    font-size: 20px;
    line-height: 1;
    color: var(--k-text-muted);
    cursor: pointer;
}
.k-location-visits__dismiss:hover { color: var(--k-text); }
.k-location-visits__modal-body {
    display: flex; flex-direction: column; gap: 14px;
    padding: 16px 20px 20px;
}
/* D3 (mock .kv, M:193-194): label column 150 px, the stored facts beside it. */
.k-location-visits__facts {
    display: grid;
    grid-template-columns: 150px 1fr;
    gap: 8px 14px;
    margin: 0;
    font-size: 14px;
}
/* The mock's dt is plain weight; said here because a base style outside this block drew it bold
   (web-11 P4 K-2 snapshot). */
.k-location-visits__facts dt { color: var(--k-text-muted); font-weight: 400; }
.k-location-visits__facts dd { margin: 0; color: var(--k-text); font-weight: 500; }
/* D4/D7 (mock .fsec, M:221-223): a framed group whose title sits INSIDE the frame, as the mock's h5
   does — a floated legend leaves the border unbroken; the first row of fields clears it. */
.k-location-visits__group {
    min-width: 0;
    margin: 0;
    padding: 12px 14px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-lg);
}
.k-location-visits__group-title {
    float: left;
    width: 100%;
    display: flex; justify-content: space-between; align-items: center; gap: 12px;
    margin: 0 0 10px;
    padding: 0;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-accent-soft);
}
.k-location-visits__group-title small {
    color: var(--k-text-muted);
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
}
.k-location-visits__group .k-location-visits__fields { clear: both; }
.k-location-visits__group .k-location-visits__fields + .k-location-visits__fields { margin-top: 14px; }
/* D8 (mock .fsec.off, M:224): the Osoba group of a vehicle-only visit — faded, its frame dashed.
   data-off is the group's own marker (present only when the group is disabled). */
.k-location-visits__group[data-off] { opacity: 0.5; border-style: dashed; }
.k-location-visits__fields {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 10px;
}
/* D6 (mock .two/.three, M:219-220): pairs side by side; the vehicle's three in one row, the
   registration a little wider. Below a phone's width every row stacks. */
.k-location-visits__two { grid-template-columns: 1fr 1fr; }
.k-location-visits__three { grid-template-columns: 1.2fr 1fr 1fr; }
@media (max-width: 600px) {
    .k-location-visits__two,
    .k-location-visits__three { grid-template-columns: 1fr; }
    .k-location-visits__facts { grid-template-columns: auto 1fr; }
}
.k-location-visits__field { display: flex; flex-direction: column; gap: 6px; }
/* mock .fld label (M:196): 12 px, 600, capitals, the label colour. */
.k-location-visits__label {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    color: var(--k-text-label);
}
/* D12 (mock .ff, M:190, M:315): D11 „Upiši odlazak · sada" alone on the LEFT, then Odustani, then
   Spremi — the auto margin pushes the pair right whether or not D11 is there (a closed visit has
   none). */
.k-location-visits__modal-actions {
    display: flex; align-items: center; justify-content: flex-end; gap: 10px; flex-wrap: wrap;
    padding: 12px 20px 16px;
    border-top: 1px solid var(--k-border-strong);
}
.k-location-visits__depart { margin-right: auto; }
/* The mock's .btn (M:32-33): 36 px, capitals, 600. Spremi is the primary gesture (filled accent);
   Odustani and D11 are the quiet .btn.sec. */
.k-location-visits__depart,
.k-location-visits__save,
.k-location-visits__cancel {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 36px;
    padding: 0 18px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    white-space: nowrap;
    cursor: pointer;
}
.k-location-visits__save { background: var(--k-accent); border-color: var(--k-accent); color: var(--k-btn-text-on-accent); }
.k-location-visits__depart,
.k-location-visits__cancel { background: transparent; color: var(--k-text); }
.k-location-visits__depart[disabled],
.k-location-visits__save[disabled] { opacity: 0.5; cursor: default; }
.k-location-visits__dismiss:focus-visible,
.k-location-visits__depart:focus-visible,
.k-location-visits__save:focus-visible,
.k-location-visits__cancel:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* ── Working-day screen (§10.3.1) — W5 Task 14 ───────────────────────────────────────────────────
   THE SPLIT IS THE SCREEN (scen 109): the route on one side, the day's events on the other, side by
   side where there is room and stacked where there is not — the map is a frame with a minimum height
   of its own, because a provider map collapses to nothing in an auto-height flex child.
   Everything here is a --k-* token; the two measured comparisons and the status glyphs bring their
   own colours from W4's blocks, so this file adds no second opinion about what "below minimum" or
   "not performed" looks like. */
/* web-08 08B-G (ARH-B 154235, ISPRAVAK ARH-C 154534): the page's left/right edge is the same
   `16px var(--k-page-gutter)` every other page root carries — the shell is gutterless (.k-page), so
   without it the day sat on x = 0. Vertical 16 px (mock :22 `.pad` 20) is every page's, named. */
.k-wd {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 16px var(--k-page-gutter);
}
.k-wd__loading,
.k-wd__not-found,
.k-wd__chooser-hint { margin: 0; color: var(--k-text-muted); }
.k-wd__error { margin: 0; color: var(--k-danger); }
.k-wd__title { margin: 0; font-size: 22px; }
/* web-08 #11 (mock :105 `.dhead`): a ROW — the day's block (`.k-wd__head-main`) on the left, the tools
   (`.k-wd__actions`) on the right, bottoms aligned. It wraps rather than overflows; see the narrow-window
   rule at the end of this section. */
.k-wd__header {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--k-border);
}
/* Oblik cinjenica: vidi kraj odsjecka (#11) — tamosnja pravila nadjacavaju mrezu i stupac ispod;
   `margin: 0` na `dl` ostaje ziv OVDJE, ne brisati. */
.k-wd__facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 8px 20px;
    margin: 0;
}
.k-wd__fact { display: flex; flex-direction: column; gap: 2px; }
.k-wd__caption {
    font-size: 12px;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    color: var(--k-text-muted);
}
.k-wd__value { margin: 0; color: var(--k-text); }
/* §10.3.1's PDF export (ruling D4): the action, the state it is in, and — only when there is one — the
   download beside it. One row, so "what can I do with this day" is a single line rather than a panel. */
/* Dvije SKUPINE u jednom retku (Codex :259): redak nosi razmake, skupine nose znacenje.
   `.k-wd__actions` preuzima tocno ono sto je `.k-wd__export` imao, pa se raspored ne mijenja. */
.k-wd__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.k-wd__share { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.k-wd__export { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.k-wd__export-action,
.k-wd__export-download,
.k-wd__link,
.k-wd__help {
    display: inline-flex;
    align-items: center;
    padding: 4px 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    background: transparent;
    color: var(--k-text);
    cursor: pointer;
}
.k-wd__export-action:hover:enabled,
.k-wd__export-download:hover,
.k-wd__link:hover,
.k-wd__help:hover { background: rgba(var(--k-accent-rgb), 0.1); }
/* Ruling D4's live day: the button stays VISIBLE and reads as unavailable rather than disappearing. */
.k-wd__export-action:disabled { color: var(--k-text-muted); cursor: not-allowed; }
/* web-08 08C-2 K-3 (mock :274 `.btn.sec.dis`, transparent): the wash above answers only `:hover:enabled`,
   so a disabled export would take the global `button:hover` fill (0,1,1); this rule (0,3,0) keeps its
   resting background. web-08 08C-3 (DOPUNA 2): `button:hover` recolours the border too
   (`border-color: var(--k-accent-hover)`), and this button's is visible — so the border keeps its resting colour,
   the shared rule's `1px solid var(--k-border-strong)` (`:disabled` declares no border of its own). */
.k-wd__export-action:disabled:hover { background: transparent; border-color: var(--k-border-strong); }
.k-wd__export-download {
    border-color: var(--k-accent);
    color: var(--k-accent-soft);
}
.k-wd__export-action:focus-visible,
.k-wd__export-download:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-wd__export-state { color: var(--k-text-muted); font-size: 13px; }
/* A file that could not be opened — the app's failure colour, and never the export's own state. */
.k-wd__export-error { color: var(--k-danger); font-size: 13px; }
.k-wd__location-link { color: var(--k-accent-soft); text-decoration: none; }
.k-wd__location-link:hover { text-decoration: underline; }
.k-wd__location-link:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
/* web-08 #12 (mock :112 `.split`): the map takes 46 %, the events the rest. */
.k-wd__split {
    display: grid;
    grid-template-columns: 46% 1fr;
    gap: 16px;
    align-items: start;
}
/* web-08b 08b-1 C-1 (mock web-08b :184 `.split.full`): a whole manual record draws no map half, so the events take
   the full width. Same weight as `.k-wd__split`, so it must stay AFTER it; below 1100 px both are one column. */
.k-wd__split--full { grid-template-columns: 1fr; }
@media (max-width: 1100px) {
    .k-wd__split { grid-template-columns: 1fr; }
}
.k-wd__map {
    min-height: 420px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-lg);
    overflow: hidden;
}
.k-wd__map .k-map,
.k-wd__map .k-map__canvas { height: 100%; min-height: 420px; }
/* §10.3.1's TRANSPORT (scen 205), attached UNDER the map inside the same frame — a route and the
   controls that replay it are one object, and a strip floating beside them would read as a second
   thing. Play/pause, the timeline, the moment being replayed, and ruling R3's four speeds. */
.k-wd__playback {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    border-top: 1px solid var(--k-border-strong);
}
/* web-08 08D k2-5 (mock M:144 `.play.dis { opacity: .45; }`; P-3): a live day's strip, its controls `disabled`.
   It fades ONCE, as the mock's does — the theme's `button:disabled { opacity: 0.4 }` would fade the transport
   and the speeds a second time inside it (.45 × .4), so the strip's own buttons reset that. The hover side is
   the export's precedent (`:disabled:hover`, below with each control), not `pointer-events`. */
.k-wd__playback--live { opacity: .45; }
.k-wd__playback--live button:disabled { opacity: 1; }
/* Oblik i hover: vidi kraj odsjecka (#21) — tamosnje pravilo nadjacava ovo i hover nize. */
.k-wd__transport {
    display: inline-flex;
    align-items: center;
    padding: 4px 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    background: transparent;
    color: var(--k-text);
    cursor: pointer;
}
.k-wd__scrub { flex: 1 1 160px; min-width: 120px; accent-color: var(--k-accent); }
/* Tabular figures, because this readout changes twice a second while a playback runs and digits of
   different widths would make the whole strip twitch. */
.k-wd__playback-time {
    color: var(--k-text);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.k-wd__speeds { display: inline-flex; gap: 4px; }
.k-wd__speed {
    padding: 2px 8px;
    border: 1px solid var(--k-border);
    border-radius: var(--k-radius-sm);
    background: transparent;
    color: var(--k-text-muted);
    font-size: 12px;
    cursor: pointer;
}
/* The active speed, like the active category: a class AND aria-pressed, never colour alone. */
.k-wd__speed--on {
    background: var(--k-accent);
    border-color: var(--k-accent);
    color: var(--k-btn-text-on-accent);
}
.k-wd__transport:hover,
.k-wd__speed:hover { background: rgba(var(--k-accent-rgb), 0.1); }
/* aktivno stanje pod pokazivačem ostaje aktivno (§10.9 kontrast; uzor .k-chip--on:hover) */
.k-wd__speed--on:hover { background: var(--k-accent); border-color: var(--k-accent); }
.k-wd__transport:focus-visible,
.k-wd__scrub:focus-visible,
.k-wd__speed:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
/* web-08 08D k2-5 (P-3, the export's `:disabled:hover` precedent): a disabled control keeps its RESTING look
   under the pointer — the speed's wash above and the global `button:hover` / `input:hover` would light it up.
   (0,3,0) over those; the active speed after the plain one, same specificity, so it keeps its accent. */
.k-wd__speed:disabled:hover { background: transparent; border-color: var(--k-border); }
.k-wd__speed--on:disabled:hover { background: var(--k-accent); border-color: var(--k-accent); }
.k-wd__scrub:disabled:hover { border-color: var(--k-border-strong); }
/* web-08 08C-1 K-1 (mock :146 `.tbox { background: var(--surface) }`, --surface → --k-surface): .k-wd__detail is
   the mock's .tbox — it holds the chips, the day table and its footer — so the table's surface is declared HERE,
   on the tree's own parent, and the tree itself goes transparent (`.k-wd__tree` below).
   web-08 08C-3 K-1 (mock :146 `.tbox { border: 1px solid var(--border-strong); border-radius: 10px }`): the frame
   is MOVED here from the grid, not added — `.k-wd__tree` below switches DX's own 1 px frame off, so the table's
   inner width stays this box minus 2 px (box-sizing is border-box for every element, Fluent 25.2.9 core.min.css as
   BlazingDark
   `*,::after,::before{-webkit-box-sizing:border-box;box-sizing:border-box}`) and the widths 08B-G sized the columns
   against do not move. No `overflow: hidden`: the tree is transparent, so the radius rounds the surface by itself,
   and clipping would cut the chips' focus rings.
   web-08 08C-4 K-1 (mock :146 `.tbox { display: flex; flex-direction: column }`, no gap): the space between the
   wrapper's three children is theirs — the chips' 8 px bottom margin (mock :147) above the table, the footer's line
   straight under it (mock :179 `margin-top: auto`). The old `gap: 12px` predates the mock (a column that only stacked
   blocks); a flex column's gap is vertical only, so dropping it does not touch the table's width. */
.k-wd__detail { display: flex; flex-direction: column; min-width: 0; background: var(--k-surface);
   border: 1px solid var(--k-border-strong); border-radius: 10px; }
/* The category selector: a segmented control, its current state carried by a class AND by
   aria-pressed, so "which category am I looking at" is never told by colour alone.
   web-08 08C-3 I-1 (mock :147 `.tbox .chips { margin: 10px 12px 8px }`): inside the framed surface, not on its edge.
   A flex child of .k-wd__detail beside the tree, so the inset does not touch the table's width.
   Review 08D-1 n-2 (mock M:51 `.chips { display: flex; gap: 6px; margin: -4px 0 12px; align-items: center; }`):
   the row centres its items, so on a live day the 30 px framed „Živo" (below) does not stretch the filters. */
.k-wd__filters { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 12px 8px; align-items: center; }
/* Review 08D-1 N-2 (TEST-WEB 014823 over f42db9360: `.k-wd__bulk` and `.k-wd__live` BOTH had margin-left: auto, so
   they split the free space — bulk → „Živo" 50.5 px at 1440, 106.8 px at 900; mock kadar 2, TEST-WEB 012340: `.xp`
   and `.live` stand TOGETHER at the right edge, „Živo" last). ARH-C 015002/015036, REV-D 015041: the two are ONE
   group, the row's last child. The GROUP takes the push to the right (M:57 `.chips .live { margin-left: auto; }`,
   M:164 `.tbox .xp { margin-left: auto; … }`) and the row's 6 px between its members (M:51 `.chips { … gap: 6px;
   … align-items: center; }`); neither member keeps a margin-left of its own. So when the row wraps (1180) the break
   falls BETWEEN the chips and the group, which stays together at the right edge; on a closed day (no „Živo") the
   group holds the bulk pair alone and still ends the row. */
.k-wd__filters-tail {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
/* web-08 08D k2-6 (mock M:57 `.chips .live { margin-left: auto; }`): the live mark ends the row on the right — that
   push is the group's above since review 08D-1 N-2.
   Review 08D-1 m-1: in THIS row the mock's `.chips span` (M:52 `height: 30px; padding: 0 12px; border: 1px solid
   var(--border-strong); border-radius: 15px; … gap: 7px; … color: var(--label);`) hits `<span class="live">` (M:302)
   as well, and M:57 overrides only the margin — so here the mark is framed like a chip and its TEXT is --label
   (--label → --k-text-label, --border-strong → --k-border-strong); the dot keeps --k-success (`.k-wd__live i`,
   M:59 — an `i`, not a span). A CONTEXT rule on the one `.k-wd__live` (above, with the walker), not a second
   class: the departure fact's mark (M:273, `.facts` has no span rule) stays frameless. No `box-sizing` here
   (review 08D-1 m-N1): the mock's M:9 `* { box-sizing: border-box; }` is already what Fluent 25.2.9 (as BlazingDark) gives
   every element (see `.k-wd__detail` above), so the 30 px is OUTSIDE, frame included, without repeating it. */
.k-wd__filters .k-wd__live {
    height: 30px;
    padding: 0 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: 15px;
    gap: 7px;
    color: var(--k-text-label);
}
.k-wd__filter,
.k-wd__retry {
    display: inline-flex;
    align-items: center;
    padding: 4px 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    background: transparent;
    color: var(--k-text);
    cursor: pointer;
}
.k-wd__filter:hover,
.k-wd__retry:hover { background: rgba(var(--k-accent-rgb), 0.1); }
/* aktivno stanje pod pokazivačem ostaje aktivno — kao .k-wd__speed--on:hover gore */
.k-wd__filter--on:hover { background: var(--k-accent); border-color: var(--k-accent); }
.k-wd__filter--on {
    background: var(--k-accent);
    border-color: var(--k-accent);
    color: var(--k-btn-text-on-accent);
}
.k-wd__filter:focus-visible,
.k-wd__retry:focus-visible,
.k-wd__candidate:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
/* Spec D2's chooser: one card per candidate working day, each carrying its own two moments. */
.k-wd__candidates { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.k-wd__candidate {
    display: grid;
    grid-template-columns: auto auto;
    gap: 2px 12px;
    text-align: left;
    padding: 10px 14px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-lg);
    background: var(--k-surface);
    color: var(--k-text);
    cursor: pointer;
}
.k-wd__candidate:hover { background: rgba(var(--k-accent-rgb), 0.1); }
/* web-08 08C-1 K-1 (mock :146 / :149 `table.t th { font-weight: 600; color: var(--label) }`, --label →
   --k-text-label): Fluent 25.2.9 core.min.css declares `--dxbl-grid-header-bg:
   var(--dxds-color-surface-transparent-rest)` and `--dxbl-grid-header-color` (#fffffe) on `.dxbl-grid` (BlazingDark: the
   grid's grey `var(--dxbl-grid-bg)` and `inherit`) — the tree's root is
   `dxbl-tree-list.dxbl-grid.k-wd__tree`, so these land on the same element and win by order (this sheet is
   linked after the theme), as `.k-grid__dx`'s do. The surface comes from `.k-wd__detail` above.
   web-08 08C-3 K-1: the grid's own frame (`.dxbl-grid{…border-radius:var(--dxbl-grid-border-radius);
   border:var(--dxbl-grid-border-width) var(--dxbl-grid-border-style) var(--dxbl-grid-border-color)…}`, Fluent 0.0625rem,
   BlazingDark 1px) is OFF
   — `.k-wd__detail` carries the mock's — by the same tie on order. Not through `--dxbl-grid-border-width`: DX
   draws the cells' lines with it too. Those lines take the mock's `td` colour (mock :150 `border-bottom: 1px
   solid var(--border)`) through DX's own `--dxbl-grid-border-color`, as `.k-grid__dx` does.
   web-08 08C-4 (review 08C-3 m-1): DX spends `--dxbl-grid-border-radius` (Fluent 0.25rem on `.dxbl-grid`, BlazingDark
   0.1875rem) on the grid's
   inner parts too (`…>colgroup+thead>tr:first-child>th:first-child{border-top-left-radius:var(--dxbl-grid-border-radius)}`,
   `th:last-child` on the right, the scroll viewer), so the variable itself goes to 0 — the header's tint keeps no
   rounded corner inside the square table.
   K3-F F5 (ARH-C Q-F2: a width calc keeps OUR value): the four content columns and their headers keep
   --dxbl-grid-text-cell-padding-x 0.375rem (5.25 px), the padding WorkingDayPage's 08B-G width arithmetic sized them on
   (text + 2 × 5.25). Fluent 25.2.9 core.min.css declares 0.4375rem on `.dxbl-grid` — this element (no SizeMode, so its
   `.dxbl-sm`/`.dxbl-lg` values do not apply) — and loses the tie by order. The first column keeps its 10 px on the cell
   (rules below). Pin: FluentDxblVarsReadTests.F5_stablo_radnog_dana_drzi_vodoravnu_ispunu_sirinskog_proracuna.
   K3-F F5 (ARH-C 110742): the cells' LINES are the mock's 1px (mock :149/:150 `border-bottom: 1px`) through
   --dxbl-grid-border-width, which Fluent 25.2.9 declares on `.dxbl-grid` as 0.0625rem (0.875 px; BlazingDark 1px). The
   same variable sizes DX's frame, which stays off through `border: 0` here (same element, later). Pin:
   WorkingDayPageRenderTests.E08C_K1_Day_table_box_reads_as_mock_tbox.
   W-13 (1), issue #3986: the row under the pointer takes the accent at .05 — DevExpress draws the hover
   (HighlightRowOnHover on the page's DxTreeList), this only tints it through `--dxbl-grid-hover-bg`, the variable
   `.k-task-detail__tree` and KerberGrid set (the task review's E14 recipe). */
.k-wd__tree {
    width: 100%;
    border: 0;
    border-radius: 0;
    --dxbl-grid-border-radius: 0;
    --dxbl-grid-border-color: var(--k-border);
    --dxbl-grid-bg: transparent;
    --dxbl-grid-header-bg: transparent;
    --dxbl-grid-header-color: var(--k-text-label);
    --dxbl-grid-header-font-weight: 600;
    --dxbl-grid-text-cell-padding-x: 0.375rem;
    --dxbl-grid-border-width: 1px;
    --dxbl-grid-hover-bg: rgba(var(--k-accent-rgb), 0.05);
}
/* web-08 #29 (mock :153-155): the block's colour bar and the story's top line. The row carries
   `k-wd__block--c{i}` / `k-wd__row--top` (WorkingDayRowClass, through DxTreeList.CustomizeElement);
   the colour of c{i} is --k-wd-c{i}, mirrored below from TaskPalette — the ONLY place in this sheet
   that spells a task colour, and the only lines TaskPaletteTests' scanner (E37) exempts. */
/* WD-PALETTE-BEGIN */
/* zrcalo `TaskPalette` (ARH-C 20261002-194215); mijenja se samo zajedno, a čuva ga E29 */
/* Kerber.Domain.WorkingDay.TaskPalette: TaskColours[i] → --k-wd-c{i}, OffTaskGrey → --k-wd-off-task-grey. */
.k-wd {
    --k-wd-c0: #1f6feb;
    --k-wd-c1: #e03131;
    --k-wd-c2: #2f9e44;
    --k-wd-c3: #9c36b5;
    --k-wd-c4: #f08c00;
    --k-wd-c5: #0c8599;
    --k-wd-c6: #c2255c;
    --k-wd-c7: #5f3dc4;
    --k-wd-off-task-grey: #8a8f98;
}
/* WD-PALETTE-END */
/* Mock :155 `tr[style*="--c"] td:first-child { box-shadow: inset 4px 0 0 var(--c) }`. The first cell of a
   DxTreeList row (25.2.9, measured in bUnit) is the one holding the status and the name. */
.k-wd__tree tr.k-wd__block--c0 > td:first-child { box-shadow: inset 4px 0 0 var(--k-wd-c0); }
.k-wd__tree tr.k-wd__block--c1 > td:first-child { box-shadow: inset 4px 0 0 var(--k-wd-c1); }
.k-wd__tree tr.k-wd__block--c2 > td:first-child { box-shadow: inset 4px 0 0 var(--k-wd-c2); }
.k-wd__tree tr.k-wd__block--c3 > td:first-child { box-shadow: inset 4px 0 0 var(--k-wd-c3); }
.k-wd__tree tr.k-wd__block--c4 > td:first-child { box-shadow: inset 4px 0 0 var(--k-wd-c4); }
.k-wd__tree tr.k-wd__block--c5 > td:first-child { box-shadow: inset 4px 0 0 var(--k-wd-c5); }
.k-wd__tree tr.k-wd__block--c6 > td:first-child { box-shadow: inset 4px 0 0 var(--k-wd-c6); }
.k-wd__tree tr.k-wd__block--c7 > td:first-child { box-shadow: inset 4px 0 0 var(--k-wd-c7); }
/* web-08 Review Focus 1 (ARH-C R08B-8): a block whose root has no colour in the scene (a day without GPS,
   a run that left no stretch of route) is never without a bar. Its colour is mock :251's slate
   (--k-wd-block-free, ARH-C 20261003-063036), not the map's off-task grey the legend calls „Izvan zadatka". */
.k-wd__tree tr.k-wd__block--grey > td:first-child { box-shadow: inset 4px 0 0 var(--k-wd-block-free); }
/* ARH-C 20261003-063036 (mock :165 `tr.sel td` / `tr.sel td:first-child`): THE SELECTED ROW — every cell a
   12 % accent wash, the first cell a 3 px accent bar. A row of a BLOCK keeps its block's bar instead (mock
   :156 `tr.sel[style*="--c"] td:first-child`), so the accent bar's selector leaves block rows out rather
   than racing the bar rules above on order. The old accent INSIDE the name cell (a bar between the icon
   and the name) is gone, rule and class. */
.k-wd__tree tr.k-wd__row--sel > td { background: rgba(var(--k-accent-rgb), 0.12); }
.k-wd__tree tr.k-wd__row--sel:not([class*="k-wd__block--"]) > td:first-child { box-shadow: inset 3px 0 0 var(--k-accent); }
/* web-08 (mock :166 `tr.dim td { color: var(--muted) }`, natpis :261 „sistemski događaji prigušeni"; vlasnik 15.10.
   ): a SYSTEM EVENT's row is muted as a whole row, not only its icon (`k-wd__row--dim`, WorkingDayRowClass).
   The name button and the moments set `--k-text` themselves, so they are muted by name; the name keeps its hover
   accent (`:not(:hover)`). The icon already reads --k-text-muted (`.k-wd__st--system`). */
.k-wd__tree tr.k-wd__row--dim > td { color: var(--k-text-muted); }
.k-wd__tree tr.k-wd__row--dim .k-wd__name-text:not(:hover) { color: var(--k-text-muted); }
.k-wd__tree tr.k-wd__row--dim .k-wd__moment { color: var(--k-text-muted); }
/* W-13 (1)(2), issue #3986: the SELECTED row stays at its 12 % wash under the pointer, so a selected row never
   reads as merely hovered. DevExpress's hover paints the ROW, not the cells — Fluent 25.2.9 core.min.css
   `.dxbl-grid-table.dxbl-grid-row-hover-enabled>tbody>tr:not(…):not(…):not(…):not(…):hover
   { background-color: var(--dxbl-grid-hover-bg) }` — and the wash above paints the CELLS, which lie over the row
   (CSS 2.1 §17.5.1, table layers), so the two would add up (≈ 16 %). No specificity race: the selected row takes
   the variable down to transparent on itself, and DevExpress's own rule then paints nothing there. */
.k-wd__tree tr.k-wd__row--sel { --dxbl-grid-hover-bg: transparent; }
/* Završna recenzija M-2 (mock :150 `table.t td { padding: 8px 10px }`): the first cell's content starts 6 px
   clear of the 4 px bar (10 − 4), not ≈ 1.25 px. DX pads a cell with `padding: var(--dxbl-grid-text-cell-padding-y)
   var(--dxbl-grid-text-cell-padding-x)` (0.375rem = 5.25 px on `.k-wd__tree` above, BlazingDark's value; Fluent 25.2.9
   0.4375rem) under a selector of fourteen
   classes, so this re-points DX's own variable on that cell instead of out-ranking it. Every row's first cell,
   as in the mock, so a bar-less top row and a block row keep their icons in one column. */
.k-wd__tree .dxbl-grid-table > tbody > tr > td:first-child { --dxbl-grid-text-cell-padding-x: 10px; }
/* Presuda R08B-11 N-1 (mock :149 `table.t th { padding: 9px 10px }`): the header „Status · Naziv" starts at the
   same 10 px as its cells. DX pads a header cell with the same variable (`…>thead>tr>th:not(.dxbl-grid-header-indent-cell)
   :not(.dxbl-grid-empty-header){padding:var(--dxbl-grid-text-cell-padding-y) var(--dxbl-grid-text-cell-padding-x)}`). */
.k-wd__tree .dxbl-grid-table > thead > tr > th:first-child { --dxbl-grid-text-cell-padding-x: 10px; }
/* web-08 08C-1 S1 + K-1 (mock :149 `table.t th { font-size: 12px; text-transform: uppercase; letter-spacing: .5px;
   padding: 9px 10px }`): EVERY header cell, not only the first. The 9 px re-points DX's own
   `--dxbl-grid-text-cell-padding-y` (Fluent 25.2.9 core.min.css: 0.37503125rem ≈ 5.25 px on `.dxbl-grid`; BlazingDark
   0.25003125rem ≈ 3.5 px) through the same padding rule N-1 cites; the body's cells keep DX's (Fluent's since K3-F F5,
   F-v1 — E08C_S1 holds that no tree rule but this one sets it). The font size ties DX's `.dxbl-grid .dxbl-grid-table>thead>tr>th
   { font-size: var(--dxbl-grid-font-size) }` (0,2,3) and wins by ORDER alone, as the top line below does. The
   tracking is the sheet's label token (0.5px). web-08 08C-3 M-3 (mock :149 `border-bottom: 1px solid
   var(--border-strong)`): the line under the header is DX's (`…>thead>tr:last-child>th{border-bottom-width:
   var(--dxbl-grid-border-width)}`), coloured through that same (0,2,3) rule's `border-color: inherit`; this rule
   ties it and gives the bottom edge the mock's colour, by order. */
.k-wd__tree .dxbl-grid-table > thead > tr > th {
    --dxbl-grid-text-cell-padding-y: 9px;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    border-bottom-color: var(--k-border-strong);
}
/* web-08 08C-3 M-4 (mock :149 `table.t th { background: rgba(255,255,255,.02) }`): DX paints the header cell from
   its variable — Fluent 25.2.9 core.min.css `.dxbl-grid .dxbl-grid-table>thead .dxbl-grid-header-row>th:not(.dxbl-grid-empty-cell)
   {background-color:var(--dxbl-grid-header-bg)}` (0,4,2), i.e. the tree's transparent (BlazingDark mixed 10 % black
   into it) — where the mock lightens it. Same selector with the tree's class, the same (0,4,2),
   wins by order. */
.k-wd__tree .dxbl-grid-table > thead .dxbl-grid-header-row > th:not(.dxbl-grid-empty-cell) {
    background-color: rgba(var(--k-white-rgb), 0.02);
}
/* web-08 08C-4 K-1 (mock :149/:150: `th` and `td` draw only `border-bottom`): no vertical line between columns. DX
   draws one left of every cell — `.dxbl-grid .dxbl-grid-table>tbody>tr>td,…,.dxbl-grid .dxbl-grid-table>thead>tr>th{…
   border-width:0;border-top-width:var(--dxbl-grid-border-width);border-left-width:var(--dxbl-grid-border-width);…}`
   (Fluent 25.2.9 core.min.css as BlazingDark, 0,2,3; the only DX rule that gives a cell that left width — the other two
   set 0). DxTreeList 25.2.9 has no grid-lines
   parameter, and `--dxbl-grid-border-width` would take the horizontal lines with it, so this ties DX's rule on the
   cells and wins by order. Each column now keeps the 1 px 08B-G counted for that line (a safe-side floor; E40). */
.k-wd__tree .dxbl-grid-table > tbody > tr > td,
.k-wd__tree .dxbl-grid-table > thead > tr > th { border-left-width: 0; }
/* Mock :153 `tr.top td { border-top: 2px solid var(--border-strong) }` (--border-strong → --k-border-strong).
   DX draws a row's line as each cell's border-top-width under `.dxbl-grid .dxbl-grid-table>tbody>tr>td`
   (0,2,3) and zeroes it on its filler cell; this rule is 0,4,3 so it beats that one, and leaves the filler
   alone. It only TIES with DX's first-row rule `.dxbl-grid .dxbl-grid-table>tbody:nth-child(2)>tr:first-child>td
   { border-top-width: 0 }` (0,4,3, Fluent 25.2.9 core.min.css as BlazingDark) and wins that one by ORDER alone: kerber-theme.css is
   linked after the theme (App.razor:22-23). Moving this sheet before the theme loses the first row's line. */
.k-wd__tree .dxbl-grid-table > tbody > tr.k-wd__row--top > td:not(.dxbl-grid-empty-cell) {
    border-top: 2px solid var(--k-border-strong);
}
/* Mock web-08 (W-08), prvi podskup: brojke uz cipove, masovno sirenje, oznaka izvan zadatka i
   podnozje tablice. Boje i razmaci uzimaju POSTOJECE tokene teme — nijedan nov token. */
.k-wd__filter-count { margin-left: 6px; color: var(--k-text-muted); font-variant-numeric: tabular-nums; }
.k-wd__filter--on .k-wd__filter-count { color: inherit; }
/* web-08 08D N3 (ARH-C 001107, REV-D 001001; mock M:164 `.tbox .xp { margin-left: auto; display: inline-flex;
   gap: 10px; font-size: 12px; color: var(--primary-soft); text-transform: uppercase; letter-spacing: .5px;
   font-weight: 600; }`): „Raširi sve / Skupi sve" is a TEXT LINK pair at the row's end, declaration for
   declaration (--primary-soft → --k-accent-soft, .5px → --k-label-tracking). The mock's M:52 `.chips span` would
   also frame `.xp` and its two spans; ARH-C 001107 rules the text link, so no frame here. Before „Živo" (M:302).
   The `.xp`'s margin-left: auto is NOT here: review 08D-1 N-2 (TEST-WEB 014823) moved it to the group
   `.k-wd__filters-tail` that holds this pair and „Živo" — two autos split the free space between them. */
.k-wd__bulk {
    display: inline-flex;
    gap: 10px;
    font-size: 12px;
    color: var(--k-accent-soft);
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-weight: 600;
}
/* Each action is a <button> (keyboard, the global focus ring) stripped back to the link's text: the global
   `button` fill, frame, padding and type give way to the wrapper's. */
.k-wd__bulk-action {
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    color: inherit;
    cursor: pointer;
}
/* #3105: the global `button:hover` (0,1,1) fills every text button with the accent. Cancelled LOCALLY here (0,2,0),
   as 08C-2 K-3 did for `.k-wd__name-text` — the mock's link has no hover fill. */
.k-wd__bulk-action:hover { background: none; }
.k-wd__outside { margin-left: 8px; color: var(--k-text-muted); font-size: 12px; }
/* web-08 #30 (mock :163 `.cnt`): sazetak bloka iza naziva korijena i podgrupe. --muted → --k-text-muted. */
.k-wd__cnt { margin-left: 8px; color: var(--k-text-muted); font-weight: 400; font-size: 12px; }
/* web-08 #31 (mock :178 `.tag`): „neobavezno" iza naziva korijena, prije sazetka (mock :253). Verzal je CSS,
   tekst ostaje TasksOptional. --border-strong → --k-border-strong, --muted → --k-text-muted; bez display
   (inline span kao .k-wd__cnt). */
.k-wd__tag { font-size: 10px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase; padding: 1px 6px; border-radius: 4px; border: 1px dashed var(--k-border-strong); color: var(--k-text-muted); margin-left: 8px; white-space: nowrap; }
/* Presuda R08B-4: naziv i sazetak u ISTOM retku (mock :241/:243). `.k-wd__name` je stupac, pa dijele
   jedno njegovo dijete — obican blok u kojem gumb (inline-block) i sazetak (inline) teku jedan iza
   drugoga, po osnovnoj liniji. Presuda R08B-10 (mock :250): oznaka „izvan zadatka" je u istom retku,
   iza naziva, kao sazetak (inline). Zapis koraka od 08C-c stoji u „Trajanje / zapis". */
.k-wd__name-line { display: block; min-width: 0; }
/* #1343 W-36 T9: rucni upis dana — pilula i „upisao {tko} {kad} · „{razlog}"" u zaglavlju (odlomak ispod
   cinjenica) i drugi redak retka 26/27. Razlog do 500 znakova: rijec BEZ razmaka se u
   DxTreeList celiji sama ne prelama (DevExpress, R-7), pa redak nosi overflow-wrap. Postojeci tokeni teme. */
.k-wd__manual { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; margin: 0; }
.k-wd__manual-line {
    display: block;
    color: var(--k-text-muted);
    font-size: 12px;
    white-space: normal;
    overflow-wrap: anywhere;
}

/* Mock web-08 (W-08), drugi podskup: natpis nad kartom i legenda boja. Natpis se PRELAMA
   umjesto da skracuje format vremena (arhitekt 20.9., presuda A). Boja kvadratica dolazi iz
   SCENE, ne iz teme — legenda i ruta moraju nositi istu vrijednost. */
.k-wd__mapcaption { margin: 0 0 8px; color: var(--k-text-muted); font-size: 12px; }
/* web-08 08F T7 (W-33) — the selected task's callout CONTENT (mock web-08 r.127-128 `.bub`, `.bub b`, r.229): the
   title „naziv · od–do" on its own line in the card's text colour at 13 px and bold, the second line „odabrano u
   tablici · N GPS točaka · N fotografija" at 12 px in the label colour. The card's frame, tail, placement and
   stacking are the shared W-20 `.k-map__callout` and are NOT repeated or extended here (MapCalloutLookTests O6);
   tokens only. The classes are named after the mock's `.bub` and carry NO 'callout' in their name: every theme
   selector with 'callout' in it must be W-20's own `.k-map__callout` (KerberCalendarWeb16Tests (6)). */
.k-wd__bub-title { display: block; color: var(--k-text); font-size: 13px; font-weight: 600; }
.k-wd__bub-line { display: block; color: var(--k-text-label); font-size: 12px; }
/* Mock web-08 (W-08), treci podskup: (?) uz cjelodnevno pracenje i gumb Link. Oboje su
   KONTROLE, ne ukras — `?` je gumb jer `title` nije dohvatljiv tipkovnicom. */
/* `?` i „Link" dijele „sec" osnovu iznad; ovdje ostaje samo ono po cemu se razlikuju:
   `?` je okrugao i prigusen, „Link" je kompaktan (mockov `sm`). Hover za oboje dolazi iz istog
   pravila kao za izvoz — ne iz globalnog `button:hover`, koji bi dao akcentnu ispunu. */
.k-wd__help { margin-left: 6px; padding: 0 6px; border-radius: 999px;
   color: var(--k-text-muted); font: inherit; font-size: 11px; line-height: 1.6; }
.k-wd__help-text { margin: 4px 0 0; color: var(--k-text-muted); font-size: 12px; max-width: 70ch; }
.k-wd__link { margin-left: 8px; padding: 2px 10px; font-size: 12px; }
/* Zamjena pri odbijenom kopiranju (Codex :264): poruka IZNAD polja, oboje ispod trake i desno
   poravnato — tocno kako je mock odobren. `max-width: 100%` i `min-width: 0` su arhitektov
   uvjet uz odobrenje: polje se skuplja umjesto da gura vodoravni klizac. */
.k-wd__share-manual { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.k-wd__share-msg { color: var(--k-warning); font-size: 12px; }
.k-wd__link-manual { width: 420px; max-width: 100%; min-width: 0; }
.k-wd__legend { display: flex; flex-wrap: wrap; gap: 12px; list-style: none;
   margin: 8px 0 0; padding: 0; color: var(--k-text-muted); font-size: 12px; }
.k-wd__legend-item { display: inline-flex; align-items: center; gap: 6px; }
.k-wd__legend-swatch { width: 14px; height: 3px; border-radius: 2px; }
/* web-08 08C-3 I-1 (mock :179 `.tfoot { padding: 8px 12px; font-size: 12px; color: var(--muted); border-top: 1px
   solid var(--border-strong) }`): inside the framed surface, under its own line. Size and colour were already the
   mock's. A flex child of .k-wd__detail beside the tree, so the inset does not touch the table's width.
   web-08 08C-4 K-1 (mock :179 `.tfoot { margin-top: auto }`): straight under the table, its line the only thing
   between (the old 10 px predates the framed surface). `auto` is 0 today — the split's `align-items: start` does not
   stretch the wrapper — and would seat the footer on the box's floor if it ever did. */
.k-wd__foot { display: flex; justify-content: space-between; gap: 12px;
   margin: auto 0 0; padding: 8px 12px; border-top: 1px solid var(--k-border-strong);
   color: var(--k-text-muted); font-size: 12px; }
.k-wd__moment { color: var(--k-text); white-space: nowrap; }
.k-wd__name {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    /* Presuda R08B-11 N-3: only the LEFT 6 px (icon → name, mock :169 `.st { margin-right: 6px }`) and the 2 px
       that keep the name on the icon's line. The right 6 px and the radius framed the old in-cell highlight. */
    padding: 2px 0 2px 6px;
}
/* §10.3.1.1's HIGHLIGHT (the one row the map is emphasising) is drawn on the ROW, `tr.k-wd__row--sel`
   above (mock :165, ARH-C 20261003-063036): a tinted wash and bar rather than a colour on the text — the
   name column already carries a type chip, a recorded reason and W4's detail block, and re-colouring all
   of that would fight every one of them. */
/* The event's name IS the control (see the template's note): a button stripped back to the text it
   was, so the table reads as a table and the affordance is the pointer and the focus ring. */
.k-wd__name-text {
    align-self: flex-start;
    max-width: 100%;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    text-align: left;
    color: var(--k-text);
    cursor: pointer;
}
/* web-08 08C-2 K-3 (mock :241, the name is plain text in its cell): the name is a <button>, so the
   global `button:hover` (0,1,1) would fill it with the accent — a cyan pill in every row. This rule
   (0,2,0) keeps the background the name has at rest. */
.k-wd__name-text:hover { color: var(--k-accent-soft); background: none; }
.k-wd__name-text:focus-visible {
    outline: 2px solid var(--k-accent);
    outline-offset: 2px;
    border-radius: var(--k-radius-sm);
}
/* §5.4's type marker on an atomic row — a quiet chip carrying the type's own word (the wizard's
   vocabulary), not an invented glyph. */
.k-wd__type {
    align-self: flex-start;
    padding: 1px 6px;
    border: 1px solid var(--k-border);
    border-radius: var(--k-radius-sm);
    font-size: 11px;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    color: var(--k-text-muted);
    /* web-08 lom1180 O1 (vlasnik 187 A, ARH-C 121612 D3): the chip sits in the name block, which inherits
       `.k-wd__tree .k-wd__status-name { overflow-wrap: anywhere }` — on a deep row at ≈ 1180 px that broke the
       type's word letter by letter. The chip breaks only at its spaces; a word longer than the room is cut with
       „…" (the full word is in its `title`). Not `nowrap`: „SKENIRAJ OSOBNU ILI VOZAČKU" (173 px) must still wrap
       at its spaces on d3 at 1440 (165 px of room). Pin E42_2. */
    overflow-wrap: normal;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Scen 156: the absence of a recorded reason, said out loud rather than left as an empty cell. */
.k-wd__no-reason { color: var(--k-text-muted); font-style: italic; font-size: 13px; }
.k-wd__status { display: inline-flex; align-items: center; }
/* web-08 #27 (mock :239-240 `td > .st` ispred naziva): status i naziv u JEDNOJ celiji, ikona lijevo.
   Blok naziva ostaje svoj stupac (`.k-wd__name`, flex column) i uzima ostatak sirine. Prazan
   `.k-wd__status` (redak bez ikone) ne zauzima mjesto: nema ni sirine ni razmaka. */
.k-wd__status-name { display: flex; align-items: flex-start; min-width: 0; }
.k-wd__status-name > .k-wd__status { padding-top: 2px; }
.k-wd__status-name > .k-wd__name { flex: 1 1 auto; }
/* Zavrsna recenzija I-1: od #27 su status i naziv u PRVOJ celiji retka, a to je DX-ova celija stabla —
   Fluent 25.2.9 core.min.css (kao i BlazingDark) joj daje `.dxbl-grid-tree-node-expand-controls-cell { white-space: nowrap }` (i
   svakoj celiji `overflow: hidden`), pa su naziv, sazetak, „izvan zadatka" i zapis rezani na rubu stupca.
   Ovo vraca prelamanje na elementu koji ih sve nosi; DX-ov spremnik uvlake i ▸ zadrzava svoj nowrap. */
.k-wd__tree .k-wd__status-name { white-space: normal; overflow-wrap: anywhere; }
/* K3-F N7 (ARH-C 204436 F-v2, #3291) — THE TREE'S EXPAND TOGGLE TAKES 18 px, per mock web-08:162
   `table.t .tw { display:inline-block; width:18px }`, the toggle directly before `.st` (mock :241): the status starts
   at td padding 10 + 18 = 28 px. Fluent 25.2.9 core.min.css (md5 81c5423fb482491e04814e73212c99df) gives
   `.dxbl-grid-tree-node-expand-button-placeholder{min-width:20px;width:20px;display:inline-block}` (no variable) and
   `.dxbl-grid-tree-node-expand-controls-cell .dxbl-grid-tree-node-expand-controls-container{…margin-right:
   var(--dxbl-grid-text-cell-padding-x);float:left}` — on the first cell that variable is our 10px (above), so the
   status began 10 + 20 + 10 = 40 px in (BlazingDark 31.25). The expand button: `….dxbl-grid-tree-node-expand-button{…
   padding:var(--dxbl-btn-padding-y) var(--dxbl-grid-expand-btn-padding-x);margin:calc(-1 * var(--dxbl-grid-expand-btn-
   padding-y)) calc(-1 * var(--dxbl-grid-expand-btn-padding-x))…}` (no width) around `svg.dxbl-image{width:var(--dxbl-
   image-width)}` = var(--dxds-spacing-200) = 1.25rem: its box is the image + 2 × padding-x and the negative margins
   give that padding back, so the row loses only the image's width. Its box is therefore 18 px + 2 × padding-x: it
   takes 18 px, like the placeholder, and its hover circle keeps Fluent's padding.
   INTERNAL DX CLASSES, NO VARIABLE — a named departure, like F2's export bar — and ONLY under .k-wd__tree. The
   container's margin goes, never the cell's padding variable (still 10px on the first cell); white-space stays
   the I-1 rule just above; the per-level indent (`.dxbl-grid-tree-node-indent`, Fluent 20px) is set back to BlazingDark 16px just below (N8).
   Pin: FluentDxblVarsReadTests.N7_toggle_stabla_RD_18px_samo_pod_k_wd_tree;
   E2E: WorkingDaySmokeTests.N7_status_pocinje_28px_od_celije_i_dug_tekst_u_jednom_retku. */
.k-wd__tree .dxbl-grid-tree-node-expand-controls-cell .dxbl-grid-tree-node-expand-controls-container { margin-right: 0; }
.k-wd__tree .dxbl-grid-tree-node-expand-button-placeholder { min-width: 18px; width: 18px; }
.k-wd__tree .dxbl-grid-tree-node-expand-controls-cell .dxbl-grid-tree-node-expand-controls-container .dxbl-grid-tree-node-expand-button {
    width: calc(18px + 2 * var(--dxbl-grid-expand-btn-padding-x));
}
/* K3-F N8 (NALAZ Lom1180 × #3585, ARH-C 190001 Q-F2, REV-D4 190339) — THE TREE'S PER-LEVEL INDENT KEEPS BLAZINGDARK'S 16 px. Fluent 25.2.9 core.min.css (md5 81c5423f) gives `.dxbl-grid-tree-node-indent{min-width:20px;width:20px}`, BlazingDark 25.2.9 blazing-dark.bs5.min.css (md5 eeb825f8) `{min-width:16px;width:16px}`; under Fluent each tree level took 4 px more from the name block, so on a d3 row at 1180 px the type chip „UNESI TEKST" (80.5 px) no longer fitted its 76.97 px and wrapped (pin WorkingDayLom1180SmokeTests.Uski_stupci_na_1180). INTERNAL DX CLASS, NO VARIABLE (405705) — a named departure like N7, ONLY under .k-wd__tree. Pin: FluentDxblVarsReadTests.N8_uvlaka_stabla_BD_16px_samo_pod_k_wd_tree. */
.k-wd__tree .dxbl-grid-tree-node-indent { min-width: 16px; width: 16px; }
/* W-33 („koraci uvučeni s vodilicom", mock web-08 :157-161): THE INDENT GUIDE — a 1 px line in --k-border-strong
   down the indent of every block row under a top row, drawn as pseudo-elements of the row's first cell (the
   block's bar stays its box-shadow, untouched). Classes from WorkingDayRowClass, only under „Sve" and „Zadaci":
   --d1 (one level down: level-1 line), --d2 (two or more: level-1 and level-2 lines), --last (the last child of
   its parent: its own level's line ends at the middle of the row), --d1-end (under a subgroup that is the last of
   its block: the level-1 line has already ended). The full cell height, so the lines of consecutive rows join.
   OFFSETS FROM DX 25.2.9's DOM, NOT THE MOCK's 22 / 46 px: the first cell holds one zero-width empty indent and
   one 16 px .dxbl-grid-tree-node-indent per level (rule above), with the white space DX writes between them
   (≈ 2.6 px at the cell's font); after the cell's 10 px padding level 1's indent spans 12.6–28.6 px and level 2's
   31.2–47.2 px (headless Edge, Fluent core + this sheet), so the lines stand on their middles at 20 and 39 px.
   Pins: WorkingDayPageRenderTests.W33_*. */
.k-wd__tree tr.k-wd__row--d1 > td:first-child,
.k-wd__tree tr.k-wd__row--d2 > td:first-child { position: relative; }
.k-wd__tree tr.k-wd__row--d1 > td:first-child::before,
.k-wd__tree tr.k-wd__row--d2 > td:first-child::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 20px;
    width: 1px;
    background: var(--k-border-strong);
}
.k-wd__tree tr.k-wd__row--d2 > td:first-child::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 39px;
    width: 1px;
    background: var(--k-border-strong);
}
.k-wd__tree tr.k-wd__row--d1.k-wd__row--last > td:first-child::before { bottom: 50%; }
.k-wd__tree tr.k-wd__row--d2.k-wd__row--last > td:first-child::after { bottom: 50%; }
.k-wd__tree tr.k-wd__row--d1-end > td:first-child::before { content: none; }
/* web-08 #28 (mock :169-171 `.st`, `.st svg`, `.st.inc`/`.st.sys`): ikona vrste retka za incident i
   sistemski dogadaj. Kvacica i X su TaskStatusIcon (`.k-task-status--*`), ne ovdje. Boje su tokeni
   teme (mock --warn → --k-warning, --muted → --k-text-muted), nijedan heks. */
.k-wd__st { display: inline-flex; width: 20px; height: 20px; align-items: center; justify-content: center; }
.k-wd__st-glyph { width: 17px; height: 17px; }
.k-wd__st--incident { color: var(--k-warning); }
.k-wd__st--system { color: var(--k-text-muted); }
/* Recenzija M-4: kvacica i X (TaskStatusIcon) u tablici dana dobivaju istu kutiju kao mock `.st`
   (20×20, svg 17 px), da naziv retka s ✓/✗ pocinje gdje i naziv incidenta. SAMO ovdje: ikonu crtaju i
   zadaci, kartice lokacije/radnika i pregled, pa globalnih 18 px ostaje. Hodac zadrzava svoj omjer 4:5. */
.k-wd__status > .k-task-status:not(.k-task-status--in-progress) { width: 20px; height: 20px; }
.k-wd__status > .k-task-status:not(.k-task-status--in-progress) .k-task-status__glyph { width: 17px; height: 17px; }
.k-wd__measure { display: inline-flex; align-items: center; }
/* web-08 08C-c / 08B-5 (mock :151 `td.n { white-space: normal }`, :244): u „Trajanje / zapis" od 08C-c stoji i
   zapis koraka (TaskDetailRecord) iza mjere i metara. Stupac je uzak (116 px), pa se celija prelama: ono sto ne
   stane uz mjeru ide u svoj redak (`flex-wrap`), proza zapisa se lomi, a rijec bez razmaka ne reze se na rubu
   DX-ove celije (`overflow: hidden`). Sirina stupca se ne mijenja (E40_Table_min_widths_fit_1180). */
.k-wd__measure--duration { flex-wrap: wrap; white-space: normal; overflow-wrap: anywhere; }
/* web-08 lom1180 (vlasnik 187 A „do 1279 px uži stupci + oznaka vrste u svoj red"; ARH-C 121612 D1 1279, D2 66):
   up to 1279 px the dated moments and Koraci give the name 58 px. At 1180 the table is 589 px (E40's chain);
   110 + 110 + 116 + 66 = 402 leaves the name 187 (129 before), so a d3 chip has ≈ 83 px and „UNESI TEKST" (79.1)
   keeps one line. Widths = content + 10.5 px of DX cell padding (Saira hmtx advance sums, no kerning):
   - Početak / Završetak 110: the worst moment „08.08.2028. 08:08" 97.4 → 107.9 (header ZAVRŠETAK 75.3).
   - Koraci 66: the widest unbreakable „(min 1000)" 53.7 → 64.2; „412 (min 300)" stacks value over bounds
     (TaskMeasureView's `flex-wrap`).
   - Trajanje / zapis stays 116: 08C-b's three thumbnails 3 × 28 + 2 × 4 + 6 = 98 → 108.5.
   WHY `!important` (and only here): DxTreeList 25.2.9 renders a column's Width as `<col data-dx-style="width: …">`,
   which DX's preload-script.js (DxDataStyleAttribute) writes as the col's INLINE style (`style.cssText`, no
   important). Under `table-layout: fixed` (blazing-dark 25.2.9 `.dxbl-grid .dxbl-grid-table`) that col IS the
   column's width, and no selector specificity beats an inline declaration — an author `!important` does (CSS
   Cascade 4 §6.1). The selectors are POSITIONAL (DxTreeListColumn has no CssClass): col 1 Naziv, 2 Početak,
   3 Završetak, 4 Trajanje / zapis, 5 Koraci — pinned against the rendered colgroup by E42_3, this block by E42_1,
   the name's gain by E42_4. ≥ 1280 px (Playwright's default window, 1440) sees the Razor widths unchanged. */
@media (max-width: 1279px) {
    .k-wd__tree .dxbl-grid-table > colgroup > col:nth-child(2),
    .k-wd__tree .dxbl-grid-table > colgroup > col:nth-child(3) { width: 110px !important; }
    .k-wd__tree .dxbl-grid-table > colgroup > col:nth-child(5) { width: 66px !important; }
}

/* Mock web-08 (W-08), PR 08A: zaglavlje kao redak (#11) i ikone gumba (#9, #21).
   Lijevi blok zaglavlja nosi naslov, cinjenice, objasnjenje pracenja, redak „u tijeku" i (T9) odlomak
   rucnog zapisa — jedan stupac s istim razmakom od 8px koji je zaglavlje imalo dok je bilo stupac. Raste
   do alata i smije se suziti (`min-width: 0`), pa redak nikad ne gura vodoravni klizac. */
.k-wd__head-main { display: flex; flex-direction: column; gap: 8px; flex: 1 1 auto; min-width: 0; }
/* Zamjena pri odbijenom kopiranju ostaje ISPOD trake i desno poravnata (Codex :264): u retku zaglavlja
   zauzima cijeli redak, a njezino vlastito `align-items: flex-end` je i dalje gura udesno. */
.k-wd__share-manual { width: 100%; }
/* Alati ostaju DESNO i kad se redak prelomi (mock :197 `.dhead .tools`): sami u novom retku bi uz
   `space-between` stali lijevo; `margin-left: auto` ih gura udesno u oba slucaja. */
.k-wd__actions { margin-left: auto; }
/* Usko: zaglavlje se vraca u stupac na istoj granici na kojoj se podjela slaze jedno ispod drugog.
   `nowrap` je ovdje NUZAN (TEST-WEB #3021, praznina ~150 px na 1024): VISEREDNI flex spremnik ne
   rasteze stavku prije mjerenja (css-flexbox §9.8), pa se visina lijevog bloka racunala na njegovoj
   fit-content sirini — gdje se cinjenice slazu jedna ispod druge — i ostajala kad se blok rastegne.
   Izmjereno u headless Chromeu: 211 → 76 px; `flex: none` na bloku ne mijenja nista. */
@media (max-width: 1100px) {
    .k-wd__header { flex-direction: column; align-items: stretch; flex-wrap: nowrap; }
}
/* Ikone u gumbima (mock :35 `.btn` gap 8px, :133 `.pb svg` 16px): velicina klasom, nikad inline
   `style` (CSP). Boja je `currentColor`, pa onemogucen izvoz posivi i ikonu. */
.k-wd__icon { width: 16px; height: 16px; flex: none; }
.k-wd__export-action { gap: 8px; }
/* Gumb reprodukcije (#21, mock :132-133 `.play .pb`): krug 36 px u boji akcenta s ikonom 16 px u
   sredini. Pozadina, obrub, boja ikone i hover su ISTI tokeni kao primarni gumb teme (`button`,
   `.k-tasks__create`): --k-accent, --k-btn-text-on-accent, --k-accent-hover. Ovo pravilo stoji IZA
   `.k-wd__transport:hover` gore i zato ga nadjacava — akcentni krug ne smije na hoveru postati
   prozirna akcentna mrlja. Fokus prsten ostaje postojeci `.k-wd__transport:focus-visible`. */
.k-wd__transport {
    justify-content: center;
    flex: none;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 1px solid var(--k-accent);
    border-radius: 50%;
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
}
.k-wd__transport:hover {
    border-color: var(--k-accent-hover);
    background: var(--k-accent-hover);
}
/* web-08 08D k2-5 (P-3): a live day's disabled transport keeps the resting accent circle under the pointer. */
.k-wd__transport:disabled:hover {
    border-color: var(--k-accent);
    background: var(--k-accent);
}
/* Podnaslov (#3, mock :107 `.dhead h1 small`): ciji je dan i gdje, tise od naslova uz njega. Stoji
   UNUTAR `h1.k-wd__title`, a globalni `h1` daje `text-transform: uppercase` i `letter-spacing` — oba se
   nasljeduju, pa ih podnaslov ponistava tocno kako mock pise (zavrsna recenzija 08A, I-1). */
.k-wd__subtitle {
    margin-left: 10px;
    font-size: 14px;
    font-weight: 500;
    color: var(--k-text-muted);
    text-transform: none;
    letter-spacing: 0;
}
/* Lokacija u podnaslovu je prigusena kao cijeli `small` (mock :107 `--muted`), a ne akcentna poveznica.
   (0,2,0) jace je i od `.k-wd__location-link` i od globalnog `a:hover`; podcrtavanje na hoveru i fokus
   prsten iz `.k-wd__location-link:hover` / `:focus-visible` ostaju. */
.k-wd__subtitle .k-wd__location-link { color: inherit; }
/* Cinjenice (#11, mock :108 `.facts`, `.facts b`): JEDAN red koji se prelama, oznaka i vrijednost u
   istom retku, oznaka podebljana u boji teksta i NE verzalom, vrijednost prigusena. `.k-wd__caption` i
   `.k-wd__value` dijele i kartice D2 biraca (WorkingDayPage.razor:106-109), pa se ovdje cilja SAMO
   unutar `.k-wd__facts` — (0,2,0) nadjacava zajednicko (0,1,0) bez obzira na redoslijed. */
.k-wd__facts { display: flex; flex-wrap: wrap; gap: 18px; font-size: 13px; color: var(--k-text-muted); }
.k-wd__facts .k-wd__fact { flex-direction: row; align-items: baseline; gap: 4px; }
.k-wd__facts .k-wd__caption {
    font-size: inherit;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
    color: var(--k-text);
}
.k-wd__facts .k-wd__value { color: inherit; }
/* „?" uz pracenje stoji UNUTAR oznake i ima `font: inherit`, pa bi preuzeo njezin 600; mock :109
   `.facts .q` nije podebljan. */
.k-wd__facts .k-wd__help { font-weight: 400; }
/* „(sustav)" uz odlazak (#36, mock :174 `.note`, :196): biljeska uz vrijednost u razini oznake (mock `--label`
   = `--k-text-label`), 13 px. */
.k-wd__note { color: var(--k-text-label); font-size: 13px; }
/* „N m od točke" (#33, mock :175 `.rec`, :242): zapis koraka u stupcu „Trajanje / zapis" — mock `--primary-soft`
   = `--k-accent-soft`, 13 px. Bez tona za Exceeds (Q3). */
.k-wd__rec { color: var(--k-accent-soft); font-size: 13px; }
/* Zapis incidenta (#33/#35, mock :151 `td.n { white-space: normal }`, :176-177 `.thumbs`/`.thumbs i`): sličice
   spremljenih fotografija (najviše 3; W-16 28×22 umjesto mockovih 26×20 — Q11) i stanje (`.k-wd__note`). Zapis se
   prelama u stupcu od 116 px. Sličica NIJE kontrola (U1/S4): bez kursora, bez :hover. Prazan okvir (Client, bez
   adrese) crta mockov gradijent (M:177 `.thumbs i`) t.5-ovim tokenskim izrazom s `.k-task-record__thumb` — isti
   element mocka (web-08 :177 = web-02 :125), isti izraz.
   `overflow-wrap: anywhere` (DX ćelija je `overflow: hidden`; isti razlog kao `.k-wd__tree .k-wd__status-name`)
   lomi ime dulje od stupca umjesto da ga odreže. UVJET: zapis je JEDINA flex stavka retka incidenta u
   `.k-wd__measure` (incident nema trajanje ni metre; pin E33_E35_Only_incident_rows_carry_the_record), pa
   `anywhere` lomi samo riječ dulju od cijelog stupca. Uz drugu stavku u istom retku zapis bi se suzio ispod
   širine riječi i lomio je usred nje (pouka „NEOBAVE/ZNO", TEST-WEB 081827 N2). */
.k-wd__record { white-space: normal; overflow-wrap: anywhere; }
.k-wd__thumbs { display: inline-flex; gap: 4px; vertical-align: middle; margin-right: 6px; }
.k-wd__thumb { width: 28px; height: 22px; border-radius: 3px; border: 1px solid var(--k-border-strong); background: linear-gradient(135deg, var(--k-border-strong), var(--k-accent-indigo)); object-fit: cover; display: inline-block; }

/* ── Worker view shell (§10.4) — W6 Task 4 ───────────────────────────────────────────────────────
   Header + five-tab strip + one body slot, the §10.3 shell's treatment for the same job: the tabs
   are plain links (they ARE addresses), and the active one is marked by an accent underline rather
   than by colour alone. Tab bodies land here in Tasks 5–9. */
.k-worker-view {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px var(--k-page-gutter);
}
.k-worker-view__header { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.k-worker-view__loading { margin: 0; color: var(--k-text-muted); }
.k-worker-view__not-found { margin: 0; color: var(--k-text-muted); }
.k-worker-view__tabs {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
    border-bottom: 1px solid var(--k-border);
}
.k-worker-view__tab {
    padding: 8px 12px;
    /* K3c rez B: web-06-radnici.html:127 .tabs span */
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-text-muted);
    text-decoration: none;
    border-bottom: 2px solid transparent;
    white-space: nowrap;
}
.k-worker-view__tab:hover { color: var(--k-text); }
.k-worker-view__tab--active {
    color: var(--k-text);
    font-weight: 600;
    border-bottom-color: var(--k-accent);
}
.k-worker-view__tab:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
/* The failed tab's own block — the shell around it stays untinted. */
.k-worker-view__tab-error {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
.k-worker-view__tab-error-text { margin: 0; color: var(--k-danger); }
.k-worker-view__tab-retry {
    padding: 4px 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    background: var(--k-surface);
    color: var(--k-text);
    cursor: pointer;
}
.k-worker-view__tab-retry:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* ── Worker General tab (§10.4 tab 1) — W6 Task 5, web-06 PR E6a ─────────────────────────────────
   Mock k2 (web-06-radnici.html, .cols/.sec/.kv/.pill/.now): ONE COLUMN PER CARD, side by side —
   Podaci (a caption/value grid whose last row is the working positions with their "glavna"/"mobilna"
   tags), Trenutno (the green edge) and, from E6b, Zadnjih 7 dana. The grid takes as many columns as
   the tab draws cards: the first is the mock's 1.1fr, every further one 1fr (grid-auto-flow: column),
   so 1 card = Podaci alone, 2 = 1.1fr 1fr, 3 = the mock's 1.1fr 1fr 1fr — no reserved empty column and
   no rule a later card has to undo. The mock's tokens map one to one: --primary → --k-accent,
   --primary-soft → --k-accent-soft, --label → --k-text-label, --muted → --k-text-muted.
   zajedničko s .k-location-general — sjedinjuje se poslije spoja #2934 (card, title, fields, caption,
   value: the same rules, repeated here until that PR lands rather than coupled to an unmerged one). */
.k-worker-general {
    display: grid;
    grid-auto-flow: column;
    grid-template-columns: 1.1fr;
    grid-auto-columns: 1fr;
    gap: 14px;
    align-items: start;
}
/* Narrower than three readable cards: one column, the cards stacked in the same order. */
@media (max-width: 1100px) {
    .k-worker-general {
        grid-auto-flow: row;
        grid-template-columns: 1fr;
    }
}
.k-worker-general__loading,
.k-worker-general__not-found { margin: 0; color: var(--k-text-muted); }
.k-worker-general__column {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;
}
.k-worker-general__card {
    background: var(--k-surface);
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius);
    padding: 14px 18px 16px;
}
/* Mock .now: the open working day's green edge. */
.k-worker-general__card--now {
    border-color: rgba(var(--k-success-rgb), 0.5);
    box-shadow: inset 4px 0 0 var(--k-success);
}
.k-worker-general__title {
    margin: 0 0 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--k-border-strong);
    font-size: 14px;
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    color: var(--k-accent);
}
.k-worker-general__fields {
    display: grid;
    grid-template-columns: 140px 1fr;
    gap: 6px 12px;
    margin: 0;
    font-size: 14px;
}
.k-worker-general__caption {
    padding-top: 2px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    color: var(--k-text-label);
}
.k-worker-general__value { margin: 0; min-width: 0; color: var(--k-text); overflow-wrap: anywhere; }
.k-worker-general__empty { margin: 0; color: var(--k-text-muted); }
.k-worker-general__list {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
}
.k-worker-general__position-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.k-worker-general__position { color: var(--k-text); }
/* Mock .pill (.main = accent border, .off = dashed and muted — the "mobilna" tag). */
.k-worker-general__tag {
    display: inline-block;
    padding: 2px 7px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    color: var(--k-text-label);
}
.k-worker-general__tag--main { border-color: var(--k-accent); color: var(--k-accent-soft); }
.k-worker-general__tag--mobile { border-style: dashed; color: var(--k-text-muted); }
.k-worker-general__link { color: var(--k-accent-soft); text-decoration: none; }
.k-worker-general__link:hover { text-decoration: underline; }
.k-worker-general__link:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-worker-general__hint { margin: 6px 0 0; font-size: 12px; color: var(--k-text-muted); }

/* ── Worker Notifications tab (§10.4 tab 2) — W6 Task 6 ──────────────────────────────────────────
   A host, like its §10.3 sibling: the grid inside it is the SAME KerberGrid the §10.1 menu uses and
   carries its own styling (the red error row included), and the §11.0 selector row above it is the
   menu's own (.k-notifications__period, reused rather than re-skinned — the theme's DevExpress
   focus-ring rule is written against those class names). All this block owns is the column the tab's
   two parts stack in and its loading line. Nothing here restyles a notification: a row that looked
   different inside one worker's log than in the global feed would contradict the tab's whole point. */
.k-worker-notifications {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.k-worker-notifications__loading { margin: 0; color: var(--k-text-muted); }

/* ── Worker Tasks tab (§10.4 tab 3) — W6 Task 7 ───────────────────────────────────────────
   A host, like its §10.3 sibling (.k-location-tasks): the grid, the §11.0 selector row, the status
   icons and the review panel are all the §10.2 menu's own components and carry their own rules
   (.k-tasks__period and .k-task-* above). All this block owns is the column the tab's parts stack in
   and its loading line — a task styled differently inside a worker than in the menu would contradict
   the tab's whole point. */
.k-worker-tasks {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.k-worker-tasks__loading { margin: 0; color: var(--k-text-muted); }

/* ── Worker Check-ins & check-outs tab (§10.4 tab 4) — W6 Task 8 ─────────────────────────────────
   §10.3 tab 5's block on the other axis (.k-location-checkins), copied for the reason its columns
   are: the two tabs read the same attendance record from the two sides it has, and a worker's
   working day must not look like a different kind of thing from a location's. Its OWN class names
   rather than a shared one — one selector tying the two screens together forever is the coupling the
   tab's own markers deliberately avoid. All this block owns is the column the tab's parts stack in,
   its two controlled lines, and the one thing that IS this tab's own: the working-day control. */
.k-worker-checkins {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.k-worker-checkins__loading,
.k-worker-checkins__empty { margin: 0; color: var(--k-text-muted); }
/* The em-dash of an open day reads as a value, not as a heading: same size as a moment, quieter. */
.k-worker-checkins__location,
.k-worker-checkins__moment { color: var(--k-text); }
/* DIZ-1 #3066 10-A1 (sonde v1–v5c-2, REV-D4 045315 / 063220, ARH-C 070115 „pB2"): the CHECK-OUT cell's span is ONE box.
   The td clips with `overflow: hidden; text-overflow: ellipsis; white-space: nowrap`. Inline, the span splits around its
   block audit line and the row action becomes a line fragment the ellipsis replaces with „…" — the button is not drawn,
   and Chromium's list hit test (elementsFromPoint, read by Playwright's click check) returns the span instead (T11a ×2).
   As one inline-block box the span is drawn whole and the action is the hit target again; `vertical-align: top` keeps
   the row height of the inline cell (0,00 px; baseline alignment adds 0,85 px). Open and closed cells both carry the
   action and a block audit line, so the rule keys on the attribute. Same pattern elsewhere: #3650 (Iza pilota). */
.k-worker-checkins__moment[data-kerber-worker-checkins-check-out] { display: inline-block; vertical-align: top; }
/* One control per row, sized and lit like §10.2's review control — a worker's grids should not sprout
   a different affordance for the same gesture. */
.k-worker-checkins__working-day {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 28px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    color: var(--k-accent-soft);
}
.k-worker-checkins__working-day:hover {
    background: rgba(var(--k-accent-rgb), 0.1);
    border-color: var(--k-border-strong);
}
.k-worker-checkins__working-day:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-worker-checkins__glyph { width: 16px; height: 16px; }

/* ── Worker Incidents tab (§10.4 tab 5) — W6 Task 9 ──────────────────────────────────────────────
   §10.3 tab 6's block on the other axis (.k-location-incidents), copied for the reason its columns
   are: the two tabs read the same §9 incident from the two sides it has, and an incident must not
   look like a different kind of thing for being read under a worker. Its OWN class names rather than
   a shared one — one selector tying the two screens together forever is the coupling the tab's own
   markers deliberately avoid. All this block owns is the column the tab's parts stack in, its two
   controlled lines, and the three cells that carry meaning of their own: the location this axis adds,
   the §9 state, and the row's link. */
.k-worker-incidents {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.k-worker-incidents__loading,
.k-worker-incidents__empty { margin: 0; color: var(--k-text-muted); }
/* The em-dash of an open incident reads as a value, not as a heading: same size as a moment, quieter. */
.k-worker-incidents__location,
.k-worker-incidents__moment,
.k-worker-incidents__category { color: var(--k-text); }
.k-worker-incidents__photos { color: var(--k-text-muted); }
/* The §9 state is told apart by a WORD first (the cell's text) and by colour only in support of it —
   never by colour alone. */
.k-worker-incidents__state--open { color: var(--k-warning); }
.k-worker-incidents__state--resolved { color: var(--k-success); }
/* The row's door into the incident: a plain link, lit like every other in-grid link in the app. */
.k-worker-incidents__link { color: var(--k-accent-soft); text-decoration: none; }
.k-worker-incidents__link:hover { text-decoration: underline; }
.k-worker-incidents__link:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* ── Portal guard refusal body (§3.3, O-3) — W6 Task 10 ──────────────────────────────────────────
   The P4 guard's controlled not-found line, rendered INSIDE the shell's main slot instead of a
   refused page. The muted one-liner the view-level not-found states already use, with the page
   padding a routed page would have brought — this body IS the page. */
.k-portal__not-found { margin: 0; padding: 24px; color: var(--k-text-muted); }
/* ── "My company" (§11.9) — W7 Task 1 ────────────────────────────────────────────────────────────
   The configuration menu's shell: the page frame every /company screen shares, the sub-navigation
   strip that sits on all of them, and the hub's own body of eight entries. Same page frame as every
   other menu (gutter + header), and nothing here invents a colour — the strip borrows the topbar's
   own link treatment because it IS a navigation, one level down. */
.k-company {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 16px var(--k-page-gutter);
}
.k-company__header { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.k-company__heading { margin: 0; font-size: 20px; }

/* Ruling R3's refusal state — a sentence, deliberately quiet: it is the whole page for anyone who is
   not the main client admin, and a loud error treatment would read as a fault rather than as a
   permission boundary. */
.k-company__refusal { margin: 0; color: var(--k-text-muted); }

/* The gate's failure state — the check could not answer, which IS a fault (unlike the quiet permission
   boundary above), so it reads in the danger colour, with a button that asks again. Same treatment as the
   working-day screen's error and retry, under the gate's own selectors. */
.k-company__access-failed { margin: 0; color: var(--k-danger); }
.k-company__retry {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    padding: 4px 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    background: transparent;
    color: var(--k-text);
    cursor: pointer;
}
.k-company__retry:hover { background: rgba(var(--k-accent-rgb), 0.1); }
.k-company__retry:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* The sub-navigation strip (design §3). A horizontal row that WRAPS rather than scrolls — eight
   entries at 200% zoom (ruling G15) have to stay reachable without a horizontal scrollbar.
   web-14 14a A2/A3 (mock .subnav M:241-244, M:298): a 44 px surface band with a strong hairline, a
   visible "Moja tvrtka" label, and the active entry UNDERLINED (2 px) rather than washed. The 44 px
   is a MIN height so a wrapped second row still fits. */
.k-company-nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px;
    min-height: 44px;
    background: var(--k-surface);
    border-bottom: 1px solid var(--k-border-strong);
}
/* A2: ABOVE the page heading and the page column's full width — CSS ONLY, so the DOM (heading outside
   CompanyGate, strip inside it) and the gate are untouched. .k-company is already a flex column and the
   gate renders no wrapper, so the strip is its direct child and order: -1 puts it first. The margin
   cancels .k-company's own padding exactly (16px top as written there, one --k-page-gutter each side)
   and the padding gives the gutter back to the entries, so it cannot overflow. The child combinator is
   deliberate: §11.7's QR page (web-25, out of the design) nests its strip inside .k-company-qr__screen,
   and there it keeps its place below the heading. */
.k-company > .k-company-nav {
    order: -1;
    margin: -16px calc(-1 * var(--k-page-gutter)) 0;
    padding: 0 var(--k-page-gutter);
}
/* A3 (mock .subnav .lbl M:244): the link's own 14 px on the right, none on the left (the strip's
   padding already gives the gutter), plus the mock's 8 px margin before the first entry. */
.k-company-nav__label {
    padding: 0 14px 0 0;
    margin-right: 8px;
    color: var(--k-text-label);
    text-transform: uppercase;
    font-weight: 700;
    letter-spacing: var(--k-label-tracking);
    font-size: 13px;
}
.k-company-nav__link {
    position: relative;
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 14px;
    color: var(--k-text-muted);
    text-decoration: none;
    text-transform: uppercase;
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    font-size: 13px;
    transition: color 0.14s ease;
}
.k-company-nav__link:hover { color: var(--k-accent-soft); }
.k-company-nav__link.active { color: var(--k-accent-soft); }
.k-company-nav__link.active::after {
    content: '';
    position: absolute;
    left: 10px;
    right: 10px;
    bottom: 0;
    height: 2px;
    background: var(--k-accent-soft);
}
.k-company-nav__link:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
/* web-14 14a A2 WITHOUT A JUMP (ARH-C ruling (a)): CompanyGate draws the strip only once the access
   check has answered, while the heading sits outside the gate and is painted at once — so the rule
   above, which orders the strip first, would push an already painted heading down by the band plus
   .k-company's 16 px gap. The page therefore RESERVES the band: an empty ::before, ordered first,
   with the strip's own min-height, hairline width (transparent — nothing is drawn) and margins, so it
   takes exactly the strip's place and the same gap. content-box so min-height + hairline add up the
   way the strip's do (its 44 px links fill the 44 px, the 1 px border comes on top), whatever reset a
   theme applies to pseudo-elements. The values are the strip's literals, not a shared variable: moving
   them into one would rewrite the strip's rules above (a hot file), and the pin
   A2_strip_space_is_reserved_before_the_gate_opens reads them FROM the strip's rules, so drift fails
   it. A wrapped second strip row (narrow window, 200 % zoom) is not reserved: before the strip exists
   no rule knows whether its entries will wrap.
   The reservation goes ONLY when the strip is a direct child. After the refusal it stays on purpose
   (ARH-C 222316): no strip ever comes, but an empty band beats the heading jumping up by ≈ 61 px.
   The one drop rule shares the reservation's specificity and wins by coming after it. A browser
   without :has() never drops the band: the heading sits 44 px lower for good, with no jump — a
   named degradation, deliberately without @supports (ARH-C 222316 point 6).
   The QR page (web-25, out of the design) keeps its layout: its strip is nested, never reserved. */
.k-company:not(.k-company-qr)::before {
    content: "";
    order: -1;
    flex: 0 0 auto;
    box-sizing: content-box;
    min-height: 44px;
    border-bottom: 1px solid transparent;
    margin: -16px calc(-1 * var(--k-page-gutter)) 0;
}
.k-company:has(> .k-company-nav)::before { display: none; }
/* web-14 14a A2's strip ON PAPER, on the Moja tvrtka pages where it is a DIRECT child of .k-company.
   §11.7's print block (below) zeroes .k-company's 16 px + gutter pad, and the strip's negative margin
   above was cut to cancel exactly that pad — so on paper it would hang off the sheet's edges. HIDDEN
   rather than re-margined, because that is what the print block already does with this screen's own
   heading (.k-company__header): a navigation strip is screen furniture, and its links do nothing on
   paper. Kept here, at the end of this screen's own section, so §11.7's print rules stay untouched;
   the QR page's strip sits inside .k-company-qr__screen and is already hidden with it. */
@media print {
    .k-company > .k-company-nav { display: none !important; }
    /* The strip's reserved band (above) goes with it — an empty band on paper is just a gap. */
    .k-company:not(.k-company-qr)::before { display: none !important; }
}

/* ── §12's admin log — W8 Task 3 ─────────────────────────────────────────────────────────────────
   The super-admin menu's chrome, written as a SIBLING of the .k-company-nav rules above rather than
   as a reuse of them: the two menus sit one level below the topbar in the same way, so they look
   alike, but §12 is a different menu with a different lifetime and one shared class would make every
   later change to either silently change both. Every colour is a --k-* token, never a raw hex. */

/* AdminGate's refusal — a sentence, deliberately quiet (the .k-company__refusal argument, verbatim):
   it is the WHOLE page for anyone who is not a super admin, and a loud error treatment would read as
   a fault rather than as a permission boundary. */
.k-admin__refusal { margin: 0; color: var(--k-text-muted); }

/* AdminGate's failure state — the check could not answer, which IS a fault (unlike the quiet permission
   boundary above), so it reads in the danger colour, with a button that asks again; the treatment of
   .k-company__access-failed / .k-company__retry under the gate's own selectors. The gate's output sits
   directly in <main class="k-page">, a plain block rather than a flex column, so the button needs no
   align-self and carries its own distance from the sentence (the 12 px of the .k-admin column). */
.k-admin__access-failed { margin: 0; color: var(--k-danger); }
.k-admin__retry {
    display: inline-flex;
    align-items: center;
    margin-top: 12px;
    padding: 4px 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    background: transparent;
    color: var(--k-text);
    cursor: pointer;
}
.k-admin__retry:hover { background: rgba(var(--k-accent-rgb), 0.1); }
.k-admin__retry:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* The sub-navigation strip. A horizontal row that WRAPS rather than scrolls — three entries at 200%
   zoom (ruling G15) have to stay reachable without a horizontal scrollbar. */
.k-admin-nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--k-border);
}
.k-admin-nav__link {
    padding: 6px 10px;
    border-radius: var(--k-radius-md);
    color: var(--k-text-muted);
    text-decoration: none;
    text-transform: uppercase;
    font-weight: 700;
    letter-spacing: var(--k-label-tracking);
    font-size: 13px;
    transition: color 0.14s ease, background 0.14s ease;
}
.k-admin-nav__link:hover { color: var(--k-accent-soft); }
.k-admin-nav__link.active {
    color: var(--k-accent-soft);
    background: rgba(var(--k-accent-rgb), 0.1);
}
.k-admin-nav__link:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* The one-tenant lens (?client=). A CHIP rather than a line of prose because it is a STATE the
   screen is in and it has to read as removable — the way out is part of the chip, not a control
   somewhere else on the page. */
.k-admin__chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 4px 10px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    background: var(--k-surface);
    color: var(--k-text-muted);
    font-size: 13px;
}
.k-admin__chip a { color: var(--k-accent-soft); text-decoration: none; }
.k-admin__chip a:hover { text-decoration: underline; }
.k-admin__chip a:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* ── §12's error list — W8 Task 5 ────────────────────────────────────────────────────────────────
   The page's own column: the heading, the strip, the chip and the grid stacked with one rhythm, and
   the same page gutter every other Kerber screen uses. */
.k-admin {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
}

.k-admin__title {
    margin: 0;
    font-size: 20px;
    font-weight: 700;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-text);
}

/* The line that stands in for the grid while the first query is in flight — quiet, like the gate's
   refusal: it is a state, not an event. */
.k-admin__loading { margin: 0; color: var(--k-text-muted); }

/* The drill-down link in the error-type cell. Underlined only on hover so a column of them does not
   read as a wall of rules, and focus-visible carries the shared ring (ruling G15). */
.k-admin__link {
    color: var(--k-accent-soft);
    text-decoration: none;
}
.k-admin__link:hover { text-decoration: underline; }
.k-admin__link:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* The copy-report control in the actions column: full-width inside its cell so a column of them
   lines up, and small enough not to grow the row. */
.k-admin__copy {
    width: 100%;
    font-size: 12px;
}

/* W8 Task 8 — the manual-copy dialog's payload, shown when the browser refused the clipboard. It is
   a text area rather than a <pre> so the operator can select-all with the keyboard and copy by hand,
   which is the whole reason this dialog exists; monospace and no wrapping because a re-flowed stack
   trace cannot be matched against a source file, and the horizontal scrollbar is the honest cost. */
.k-admin__copy-fallback {
    width: 100%;
    min-width: min(70vw, 700px);
    height: 50vh;
    font-family: var(--k-font-mono, ui-monospace, "Cascadia Mono", Consolas, monospace);
    font-size: 12px;
    line-height: 1.5;
    white-space: pre;
    overflow: auto;
    padding: 8px 10px;
    color: var(--k-text);
    background: var(--k-bg);
    border: 1px solid var(--k-border);
    border-radius: var(--k-radius-sm);
}

/* ── #200 — the super admin's grid of Kerber clients (mock web-28 k1 :656–674) ──────────────────────
   The name cell is two lines (mock :665): the state dot (the theme's .k-status), the name and — for an
   inactive client — the theme's compact „neaktivan" pill on the first; „OIB · adresa" small and muted under
   it (mock .ver :363). The red alarm pill is the theme's .k-pill--al as it is; nothing here restyles a pill
   or a dot, only the consumer's spacing (the pill rule leaves the space before it to its consumer). */
.k-admin-clients__client {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.k-admin-clients__head {
    display: flex;
    align-items: center;
    min-width: 0;
}
/* mock :665 `.yn` margin-right 10px. */
.k-admin-clients__state { margin-right: 10px; }
.k-admin-clients__name {
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--k-text);
}
/* mock :669 the pill's margin-left 8px. */
.k-admin-clients__inactive { margin-left: 8px; }
.k-admin-clients__sub {
    font-size: 11px;
    color: var(--k-text-muted);
}
/* mock :629 `.lang` — the workspace language's code as a small tag. */
.k-admin-clients__lang {
    display: inline-block;
    font-size: 11px;
    padding: 1px 6px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    color: var(--k-text-label);
}
/* mock :665 `.muted` 0 in the active-alarms column. */
.k-admin-clients__zero { color: var(--k-text-muted); }
/* #4130 — the row's „Radna mjesta" action, drawn as the mock's `.acts span` (web-28 :626–627): the soft
   accent at rest (W-28: an action column is coloured at rest), 12 px, 600, capitals with the label tracking,
   never wrapped; underlined on hover and keyboard focus like every other in-grid link. */
.k-admin-clients__action {
    color: var(--k-accent-soft);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    white-space: nowrap;
    text-decoration: none;
}
.k-admin-clients__action:hover,
.k-admin-clients__action:focus-visible { text-decoration: underline; }
/* mock :669 `tr.inactive` (:249): an inactive client's row is muted by COLOUR, never opacity (the
   locations' and task definitions' rule) — KerberGrid's RowCssClass puts the class on the row. The name
   carries a colour of its own (above), so it is muted by name as well. */
.k-grid__dx tr.k-admin-clients__row--inactive > td,
.k-grid__dx tr.k-admin-clients__row--inactive > td .k-admin-clients__name {
    color: var(--k-text-muted);
}

/* ── §12.1's one-group screen — W8 Task 7 ─────────────────────────────────────────
   The drill-down under a row of the error list: a summary card, the six breakdowns beside it, and
   the panel one occurrence opens over the grid. Every colour is a --k-* token, never a raw hex. */

/* "There is no such group" — a malformed key in the address, or a group this lens cannot see. Quiet
   like the gate's refusal and the loading line, for the same reason: it is a STATE the screen is in,
   not a fault it suffered. */
.k-admin__empty { margin: 0; color: var(--k-text-muted); }

/* The summary card. One block, because the six breakdowns are only readable AGAINST the total above
   them — "47, all of them on one handset" is the diagnosis, and splitting the two apart would put the
   comparison on the operator. */
.k-admin-group {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 14px 16px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    background: var(--k-surface);
}
.k-admin-group__header {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
/* The exception type is the headline. It breaks anywhere because a Java type name has no spaces to
   wrap at and a 200% zoom (ruling G15) must not push a horizontal scrollbar onto the page. */
.k-admin-group__type {
    margin: 0;
    font-size: 18px;
    overflow-wrap: anywhere;
}
/* The copy control sits at the far end of the header, away from the type it is about. */
.k-admin-group__header .k-admin__copy { width: auto; margin-left: auto; }

/* The facts, as label/value pairs on one wrapping row — a grid of fixed columns would leave the
   64-character key either clipped or dictating everything else's width. */
.k-admin-group__facts {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 18px;
    margin: 0;
}
.k-admin-group__facts dt {
    color: var(--k-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-size: 11px;
}
.k-admin-group__facts dd { margin: 0; font-variant-numeric: tabular-nums; }
/* The key is a hash: monospace so it can be read character by character, and breakable so it never
   widens the card. */
.k-admin-group__key {
    font-family: var(--k-font-mono, ui-monospace, "Cascadia Mono", Consolas, monospace);
    font-size: 12px;
    overflow-wrap: anywhere;
}
.k-admin-group__count { font-weight: 700; }

/* SIX BREAKDOWNS SIDE BY SIDE, wrapping into as many columns as fit: they exist to be COMPARED, and
   a stack of six lists would put the comparison a scroll apart. */
.k-admin-group__distributions {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 10px 16px;
}
.k-admin-group__distribution-title {
    margin: 0 0 4px;
    color: var(--k-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-size: 11px;
}
.k-admin-group__buckets { margin: 0; padding: 0; list-style: none; }
/* Label left, count right, so a column of buckets reads as a bar chart of numbers. */
.k-admin-group__bucket {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    font-size: 13px;
    overflow-wrap: anywhere;
}
.k-admin-group__bucket b { font-variant-numeric: tabular-nums; }

/* The occurrence panel: a card OVER the grid, not a page — the list it was opened from is still
   right underneath, and closing it must land the operator exactly where they were. Capped in height
   so a 4000-character stack trace cannot push the grid off the screen. */
.k-occurrence {
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-height: 60vh;
    overflow-y: auto;
    padding: 14px 16px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    background: var(--k-surface);
}
.k-occurrence__header {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
.k-occurrence__type { margin: 0; font-size: 16px; overflow-wrap: anywhere; }
.k-occurrence__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    margin-left: auto;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--k-radius-sm);
    background: transparent;
    color: var(--k-text-muted);
    cursor: pointer;
}
.k-occurrence__close:hover { border-color: var(--k-border-strong); color: var(--k-text); }
.k-occurrence__close:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-occurrence__close-glyph { width: 14px; height: 14px; }
.k-occurrence__facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 4px 16px;
    margin: 0;
}
.k-occurrence__facts dt {
    color: var(--k-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-size: 11px;
}
.k-occurrence__facts dd { margin: 0 0 6px; font-size: 13px; overflow-wrap: anywhere; }
.k-occurrence__section {
    margin: 4px 0 0;
    color: var(--k-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-size: 11px;
}
/* THE STACK TRACE DOES NOT WRAP, deliberately: a frame is one line, and a trace folding at the panel
   edge stops being scannable as a column of frames. It scrolls HORIZONTALLY inside its own box, so
   the page itself never grows a horizontal scrollbar. */
.k-occurrence__stack,
.k-occurrence__raw {
    margin: 0;
    max-height: 260px;
    overflow: auto;
    padding: 8px 10px;
    border: 1px solid var(--k-border);
    border-radius: var(--k-radius-sm);
    background: var(--k-bg);
    color: var(--k-text);
    font-family: var(--k-font-mono, ui-monospace, "Cascadia Mono", Consolas, monospace);
    font-size: 12px;
    line-height: 1.5;
    white-space: pre;
}
/* The raw breadcrumb column is a payload of unknown shape rather than a column of frames, so it DOES
   wrap — there is no line structure in it worth preserving at the cost of readability. */
.k-occurrence__raw { white-space: pre-wrap; overflow-wrap: anywhere; }

/* The trail. Three columns, in the order the phone wrote them. */
.k-occurrence__crumbs {
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
}
.k-occurrence__crumb td {
    padding: 3px 8px 3px 0;
    border-bottom: 1px solid var(--k-border);
    vertical-align: top;
}
.k-occurrence__crumb-utc {
    white-space: nowrap;
    color: var(--k-text-muted);
    font-variant-numeric: tabular-nums;
}
.k-occurrence__crumb-kind {
    white-space: nowrap;
    color: var(--k-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}
/* A label is a client's own string — it can be long, and it can be a single unbroken run. */
.k-occurrence__crumb-label { width: 100%; overflow-wrap: anywhere; }

/* ── §12.2's configuration audit — W8 Task 9 ─────────────────────────────────────
   The panel one audit row opens over the list: who/what/when, then the change itself as a three-column
   old → new table. Same card treatment as the occurrence panel above (it is the same kind of thing —
   one row of a log, in full, over the grid it came from), so the two are deliberately not two skins.
   Every colour is a --k-* token, never a raw hex. */
.k-audit {
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-height: 60vh;
    overflow-y: auto;
    padding: 14px 16px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-md);
    background: var(--k-surface);
}
.k-audit__header {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
/* WHAT changed, as the headline: the entity and the id of the one that was touched. It breaks
   anywhere because an entity name has no spaces to wrap at and a 200% zoom (ruling G15) must not push
   a horizontal scrollbar onto the page. */
.k-audit__what {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin: 0;
    font-size: 16px;
    overflow-wrap: anywhere;
}
/* The id is a number beside a name — muted and tabular, so it reads as an identifier rather than as
   part of the name. */
.k-audit__entity-id {
    color: var(--k-text-muted);
    font-size: 13px;
    font-variant-numeric: tabular-nums;
}
.k-audit__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    margin-left: auto;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--k-radius-sm);
    background: transparent;
    color: var(--k-text-muted);
    cursor: pointer;
}
.k-audit__close:hover { border-color: var(--k-border-strong); color: var(--k-text); }
.k-audit__close:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-audit__close-glyph { width: 14px; height: 14px; }
.k-audit__facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 4px 16px;
    margin: 0;
}
.k-audit__facts dt {
    color: var(--k-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-size: 11px;
}
.k-audit__facts dd { margin: 0 0 6px; font-size: 13px; overflow-wrap: anywhere; }
/* WHO, in two parts on two lines: the stored handle and the name resolved today. The handle is
   monospace because it is an identifier ("worker:12"), and it stays visible whatever the name says. */
.k-audit__actor { display: flex; flex-direction: column; }
.k-audit__handle {
    font-family: var(--k-font-mono, ui-monospace, "Cascadia Mono", Consolas, monospace);
    font-size: 12px;
    color: var(--k-text-muted);
}
/* #250: the one action with a NAME — the hand-over close. The stored action stays (it is the
   record); the ruling's word for it sits beside it, muted, the way the actor's name sits under the
   handle. The same pair appears in §12.3's Kind cell, so the two share one look. */
.k-audit__action-name,
.k-sync__handover { margin-left: 6px; color: var(--k-text-muted); font-size: 12px; }
.k-audit__section {
    margin: 4px 0 0;
    color: var(--k-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-size: 11px;
}
.k-audit__no-changes { margin: 0; color: var(--k-text-muted); font-size: 13px; }

/* THE CHANGE ITSELF. Three columns, and the two value columns share the space evenly: they exist to
   be COMPARED, so one of them growing at the other's expense would defeat the whole table. */
.k-audit__diff {
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
    table-layout: fixed;
}
.k-audit__diff th {
    padding: 3px 8px 3px 0;
    border-bottom: 1px solid var(--k-border-strong);
    color: var(--k-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    font-size: 11px;
    font-weight: 600;
    text-align: left;
}
.k-audit__field-head { width: 24%; }
.k-audit__change td {
    padding: 4px 8px 4px 0;
    border-bottom: 1px solid var(--k-border);
    vertical-align: top;
}
/* The property name is an identifier, like the handle above. */
.k-audit__field {
    font-family: var(--k-font-mono, ui-monospace, "Cascadia Mono", Consolas, monospace);
    overflow-wrap: anywhere;
}
/* A value is a tenant's own string — it can be long and it can be a single unbroken run. */
.k-audit__old,
.k-audit__new { overflow-wrap: anywhere; }
/* The new side is the one an operator is checking, so it carries the emphasis; the old side is muted
   context beside it. Colour is reinforcement — the COLUMN HEADINGS are what say which is which. */
.k-audit__old { color: var(--k-text-muted); }
.k-audit__new { color: var(--k-text); }
.k-audit__value { display: block; }
/* A long or multi-line value keeps its shape (scen 75) and scrolls inside its own box, so a
   serialized object cannot push the panel — or the page — sideways. */
.k-audit__value--block {
    margin: 0;
    max-height: 160px;
    overflow: auto;
    padding: 6px 8px;
    border: 1px solid var(--k-border);
    border-radius: var(--k-radius-sm);
    background: var(--k-bg);
    font-family: var(--k-font-mono, ui-monospace, "Cascadia Mono", Consolas, monospace);
    line-height: 1.5;
    white-space: pre-wrap;
}

/* ── §12.3's sync anomalies — W8 Task 10 ─────────────────────────────────────────
   KerberGrid's RowCssClass hook puts .k-row--anomaly on EVERY data row of this grid, and that is not
   a per-row verdict the way §10.1's .k-row--error is: every row here IS an anomaly, because that is
   the set the source builds. So the mark is RESTRAINED — a warning-coloured edge on the row rather
   than a wash over it. A full-row tint would paint the entire screen and stop distinguishing
   anything, which is the failure mode of a highlight that is always on.
   ONE EDGE, DRAWN AS AN INSET SHADOW rather than a border, because a border on a <td> changes the
   cell's box and nudges every column of a marked row out of line with the header above it.
   Every colour is a --k-* token (--k-warning is defined at :root), never a raw hex. */
.k-grid__dx tr.k-row--anomaly > td:first-child {
    box-shadow: inset 3px 0 0 0 var(--k-warning);
}

/* THE OFFSET IS THE NUMBER THE SCREEN EXISTS FOR, so it is the one cell that carries the warning
   colour itself — and tabular figures, because a column of signed durations is read by comparing
   them down the column. */
.k-sync__offset {
    color: var(--k-warning);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* ── §11.1's workers grid — W7 Task 3 ────────────────────────────────────────────────────────────
   The grid itself is KerberGrid's (§11.0's behaviours are configured, never re-implemented); the two
   rules below are only what its CELLS need. The status pair borrows the Locations menu's own boolean
   treatment rather than inventing a second one — muted for the "nothing to see here" state, the
   theme's success colour for the live one — and scen 49's real signal is the WORD in the cell, so
   the colour is reinforcement rather than the message. */
.k-workers__cell { color: var(--k-text); }
.k-workers__state--on { color: var(--k-success); font-weight: 600; }
.k-workers__state--off { color: var(--k-text-muted); }

/* W7 Task 4 — §11.1's worker form. The toolbar above the grid holds the one page-level command
   (scen 29); the row command lives in the grid's own command column (scen 30). */
.k-company__toolbar { display: flex; justify-content: flex-end; margin-bottom: 8px; }

.k-company__primary {
    padding: 6px 14px;
    border: 1px solid var(--k-accent);
    border-radius: 4px;
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    font: inherit;
    cursor: pointer;
}

/* web-21c V1 (Codex P2 on #3257): an icon in front of the label, as in "+ Novi klijent" (mock web-21 M:514,
   whose .btn spaces icon and text 8px apart and centres them; „+ Novi radnik" too since #4301). Only the svg is
   touched, so a button that carries text alone (Devices) draws exactly as before. */
.k-company__primary > svg {
    margin-right: 8px;
    vertical-align: middle;
}

/* The dialog's body. web-20 20b C2 (mock web-20 k2, M:468 .cols2): two columns, "Osoba i pristup"
   left and "Radna mjesta" right, 22px apart. The tracks are auto-fit with a floor rather than a fixed
   1fr 1fr, so a narrow viewport or 200% zoom (ruling G15) folds them back into ONE column instead of
   squeezing every label against its box. The popup's own width is the DX shell's, not set here. */
.k-worker-editor { min-width: min(420px, 80vw); }

.k-worker-editor__fields {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
    gap: 0 22px;
    align-items: start;
}

.k-worker-editor__col { min-width: 0; }

/* M:470 .sec h5 — the column heading; --k-accent-soft is the mock's --primary-soft. */
.k-worker-editor__heading {
    margin: 0 0 10px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--k-border-strong);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-accent-soft);
}

.k-worker-editor__field { display: flex; flex-direction: column; gap: 4px; }

/* M:195 .fld { margin-bottom: 14px } — one block per mock row: a lone field, a pair, or the PIN pair
   with its hint. Inside a pair the row's margin is the pair's, not each field's. */
.k-worker-editor__col > .k-worker-editor__field,
.k-worker-editor__block,
.k-worker-editor__col > .k-worker-editor__pair { margin-bottom: 14px; }

/* M:219 .fld .two — the mock's pairs (V1): Ime | Prezime, Novi PIN | Potvrda, OIB | Telefon,
   E-mail | Jezik. min-width: 0 keeps a DX editor from pushing its track wider than half. */
.k-worker-editor__pair { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

.k-worker-editor__pair > .k-worker-editor__field { min-width: 0; }

/* The state field's switch and the hint beside it (M:553, hint margin-left 10px). */
.k-worker-editor__row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* M:197 .fld label em — the required-field mark (C5). G3's `.k-worker-editor__label em` now paints the same
   (--k-danger, normal, 3px); this local class stays only because WorkerEditor.razor still puts it on the
   <em> — dropping it from the markup is a separate step (REV-D 214204 U1). */
.k-worker-editor__required { margin-left: 3px; font-style: normal; color: var(--k-danger); }

/* M:258 .fld .hint (C7, C9, C12). */
.k-worker-editor__hint { margin: 4px 0 0; font-size: 12px; color: var(--k-text-muted); }

.k-worker-editor__row > .k-worker-editor__hint { margin-top: 0; }

/* A refusal sits UNDER the box it belongs to (the W4 R4 discipline: field-hinted, save-gated). */
.k-worker-editor__field-error { margin: 0; font-size: 13px; color: var(--k-danger); }

.k-worker-editor__error { margin: 8px 0 0; color: var(--k-danger); }

.k-worker-editor__loading { margin: 0; color: var(--k-text-muted); }

.k-worker-editor__actions { display: flex; gap: 8px; justify-content: flex-end; }

.k-worker-editor__save {
    padding: 6px 14px;
    border: 1px solid var(--k-accent);
    border-radius: 4px;
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    font: inherit;
    cursor: pointer;
}

.k-worker-editor__save[disabled] { opacity: 0.6; cursor: default; }

/* web-20 20c P5 (M:566 .btn.sec): the documents button in the right column IS this dialog's secondary
   button — no shared secondary-button primitive exists (measured 3.10.), so it shares Odustani's rule
   rather than inventing a second look for the same kind of button. */
.k-worker-editor__cancel,
.k-worker-editor__documents {
    padding: 6px 14px;
    border: 1px solid var(--k-border);
    border-radius: 4px;
    background: var(--k-surface);
    color: inherit;
    font: inherit;
    cursor: pointer;
}

/* M:566 — the mock's .btn is an inline button; inside the column's flex field it would otherwise
   stretch to the column's width. */
.k-worker-editor__documents { align-self: flex-start; }

/* M:565 C17 (P4) — the note beside the "Dokumenti radnika" heading, the mock's inline small. */
.k-worker-editor__heading-note {
    color: var(--k-text-muted);
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
}

/* web-20 20c C14 — the ordered list of working positions (mock web-20 .roles, M:472-478). The list is
   an <ol>, so the browser's own list indent and numbers go first; the mock draws a plain box. */
.k-worker-roles {
    margin: 0;
    padding: 0;
    list-style: none;
    /* M:472 .roles */
    border: 1px solid var(--k-border-strong);
    border-radius: 8px;
    background: var(--k-bg);
}

/* M:473 .roles .r — every row, the "+ dodaj" row included (the mock's .r.add is an .r too). */
.k-worker-roles__row,
.k-worker-roles__add {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-bottom: 1px solid var(--k-border);
    font-size: 14px;
}

/* M:474 .roles .r:last-child */
.k-worker-roles__row:last-child,
.k-worker-roles__add:last-child { border-bottom: 0; }

/* The handle and the ✕ are <button>s (a name and a keyboard target, U2/R14); the browser's and DX's
   button look must not come through, so they are reset before the mock's own declarations. */
.k-worker-roles__handle,
.k-worker-roles__remove {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
}

/* M:475 .roles .r .h */
.k-worker-roles__handle {
    color: var(--k-border-strong);
    letter-spacing: -2px;
    cursor: grab;
}

/* M:607 (P2, W-54 (a)): ONE working position — nothing to reorder, the handle is dimmed (and disabled
   in the markup). Counter-example M:655 (Zonski administrator, one position, handle not dimmed) is
   named in the PR body. */
.k-worker-roles__handle--single {
    opacity: .3;
    cursor: default;
}

/* M:476 .roles .r .main — --k-accent / --k-accent-soft are the mock's --primary / --primary-soft. */
.k-worker-roles__main {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .5px;
    text-transform: uppercase;
    padding: 1px 6px;
    border-radius: 4px;
    border: 1px solid var(--k-accent);
    color: var(--k-accent-soft);
}

/* M:477 .roles .r .x */
.k-worker-roles__remove {
    margin-left: auto;
    color: var(--k-text-muted);
    cursor: pointer;
}

/* M:478 .roles .r.add */
.k-worker-roles__add {
    color: var(--k-text-muted);
    border-top: 1px dashed var(--k-border-strong);
}

/* P3 (M:559, M:655): "+ dodaj radno mjesto" is a TEXT row, so the DX combo inside it loses its box. */
.k-worker-roles__add .k-worker-roles__picker {
    flex: 1 1 auto;
    border: 0;
    background: none;
    box-shadow: none;
}

/* P3, the box itself (TEST-WEB 224408): the frame and the fill are the INNER input's, from this theme's own
   input:not([type="checkbox"]):not([type="radio"]) — (0,2,1), which beats DX's transparent input (0,2,0)
   — so the row's input (InputCssClass) is reset at (0,3,1). The text reads as the mock's row, --muted at
   full strength (M:478), and keeps the theme's keyboard ring (input:focus-visible). The ⌄ is gone through
   ShowDropDownButton=false. */
.k-worker-roles__add .k-worker-roles__picker input.k-worker-roles__picker-input {
    border: 0;
    background: none;
    padding: 0;
    min-height: 0;
    font-size: inherit;
    color: var(--k-text-muted);
}
.k-worker-roles__add .k-worker-roles__picker input.k-worker-roles__picker-input::placeholder {
    color: var(--k-text-muted);
    opacity: 1;
}
/* With the frame gone, the keyboard ring is the only sign of focus (WCAG 2.4.7) — and DX's
   .dxbl-text-edit>.dxbl-text-edit-input { outline: 0 } (0,2,0) beats the theme's input:focus-visible
   (0,1,1), so the ring is given back here. */
.k-worker-roles__add .k-worker-roles__picker input.k-worker-roles__picker-input:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* Text for a screen reader only (U2's live region, T3): in the accessibility tree, not on screen. */
.k-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* ── §11.2's clients grid and form — W7 Task 5 ───────────────────────────────────────────────────
   Five plain text columns and a five-field dialog, so there is nothing here the workers screen has
   not already had to decide: the row command and the two dialog buttons reuse their neighbours'
   shapes rather than inventing a second look for the same gesture one menu entry away. The rules are
   duplicated rather than shared under a common class name because the two screens' BEM blocks are
   their own — a shared .k-company__cell would make either screen's restyling reach into the other. */
.k-clients__cell { color: var(--k-text); }

/* web-21 C6: a client with no portal users shows the app's no-value glyph, muted (mock M:520-523
   span.muted) — present enough to read as "none", quiet enough not to compete with a real count. */
.k-clients__none { color: var(--k-text-muted); }

/* The dialog's body. web-21 (21b, W-55, ARH-C N9): EDIT is two columns — the five fields left, the
   read-only „Korisnici portala" card right — in the 760 px dialog ClientEditor.razor sets; CREATE is
   the fields alone at the popup's default width. Below 800 px of viewport everything is ONE column
   (the rule after this block), which is also what 1440 px at 200 % zoom becomes — the G15 concern the
   old single-column-everywhere rule answered. */
.k-client-editor { min-width: min(420px, 80vw); }

.k-client-editor__cols {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 0 22px;
    align-items: start;
}

/* D5: the mock's rows — Naziv, Adresa, OIB + Telefon side by side, E-mail — drawn by the GRID only.
   The DOM keeps the spec's order (name, address, OIB, e-mail, phone): scen 62's pin and the tab order
   both follow the DOM, and the visual order differs from it only on this one row (ARH-C N8). */
.k-client-editor__fields {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas: "name name" "address address" "oib phone" "email email";
    gap: 10px;
}

.k-client-editor__field { display: flex; flex-direction: column; gap: 4px; }

.k-client-editor__field[data-kerber-client-field="name"] { grid-area: name; }
.k-client-editor__field[data-kerber-client-field="address"] { grid-area: address; }
.k-client-editor__field[data-kerber-client-field="oib"] { grid-area: oib; }
.k-client-editor__field[data-kerber-client-field="phone"] { grid-area: phone; }
.k-client-editor__field[data-kerber-client-field="email"] { grid-area: email; }

.k-client-editor__label-row { display: flex; align-items: baseline; gap: 3px; }

.k-client-editor__label { font-size: 13px; color: var(--k-text-muted); }

/* D3: the required mark (mock `.fld label em`) — upright, in the danger colour. */
.k-client-editor__required { font-style: normal; color: var(--k-danger); }

/* D3/D6: the explanatory line under a box (mock `.fld .hint`). */
.k-client-editor__hint { margin: 0; font-size: 12px; color: var(--k-text-muted); }

/* D7/D8: the read-only portal users card (mock `.sec` + `.locl`). */
.k-client-editor__portal { display: flex; flex-direction: column; gap: 6px; }

.k-client-editor__portal-title {
    margin: 0;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .5px;
    color: var(--k-accent);
}

.k-client-editor__portal-subtitle { margin: 0 0 4px; font-size: 12px; color: var(--k-text-muted); }

.k-client-editor__portal-list {
    margin: 0;
    padding: 0;
    list-style: none;
    border: 1px solid var(--k-border-strong);
    border-radius: 8px;
    background: var(--k-bg);
}

.k-client-editor__portal-user {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    border-bottom: 1px solid var(--k-border);
    font-size: 13px;
}

.k-client-editor__portal-user:last-child { border-bottom: 0; }

.k-client-editor__portal-name { color: var(--k-text); }

.k-client-editor__portal-line { margin-left: auto; font-size: 12px; color: var(--k-text-muted); }

/* A refusal sits UNDER the box it belongs to (the W4 R4 discipline: field-hinted, save-gated). */
.k-client-editor__field-error { margin: 0; font-size: 13px; color: var(--k-danger); }

.k-client-editor__error { margin: 8px 0 0; color: var(--k-danger); }

.k-client-editor__loading { margin: 0; color: var(--k-text-muted); }

.k-client-editor__actions { display: flex; gap: 8px; justify-content: flex-end; }

.k-client-editor__save {
    padding: 6px 14px;
    border: 1px solid var(--k-accent);
    border-radius: 4px;
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    font: inherit;
    cursor: pointer;
}

.k-client-editor__save[disabled] { opacity: 0.6; cursor: default; }

.k-client-editor__cancel {
    padding: 6px 14px;
    border: 1px solid var(--k-border);
    border-radius: 4px;
    background: var(--k-surface);
    color: inherit;
    font: inherit;
    cursor: pointer;
}

/* USKI ZASLON — web-21 N9 (ARH-C), the #2180 pattern (.k-device-pairing__steps): below 800 px (the
   edit dialog is 760 px) the card drops under the fields and the fields go back to one column in DOM
   order, so on a narrow screen the visual order IS the tab order. Pinned by WebStyleAuditTests. */
@media (max-width: 800px) {
    .k-client-editor__cols,
    .k-client-editor__fields { grid-template-columns: minmax(0, 1fr); }
    .k-client-editor__fields { grid-template-areas: none; }
    .k-client-editor__fields > .k-client-editor__field { grid-area: auto; }
}

/* ── §11.3's locations grid, tab shell and General form — W7 Task 6 ──────────────────────────────
   Three BEM blocks, kept apart from each other and from W5's operational .k-locations for the
   reason the clients screen states above: a shared class would make one screen's restyling reach
   into another's. Every colour is a --k-* token (never a raw hex), the way kerber-theme.css has
   worked since W1. */

/* The Client/Company segment (web-14 B2). THE SAME SHAPE AND TOKENS as .k-mapgrid__mode — an operator
   who knows one switch knows the other — but its own block, for the reason stated above.
   W-44 (mock web-14 k1 :300): the segment sits in the toolbar row's lead (.k-grid__lead inside
   .k-grid__bar, which already centre it in the row and space it from the title), so it carries no
   bottom margin of its own — one would push it off the row's centre line. */
.k-locations-config__scopes {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.k-locations-config__scope {
    font: inherit;
    /* K3c rez B: web-14-moja-tvrtka-lokacije.html:43 .seg span */
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-text);
    background: var(--k-surface);
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    padding: 4px 10px;
    cursor: pointer;
}
/* The chosen half reads as PRESSED — announced through aria-pressed as well, so the state is not
   colour alone. */
.k-locations-config__scope--on {
    color: var(--k-btn-text-on-accent);
    background: var(--k-accent);
    border-color: var(--k-accent);
}

.k-locations-config__scope:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

.k-locations-config__cell { color: var(--k-text); }

/* C2 (mock .yn M:246): the active cell's dot — grey by default, green for an active location. */
.k-locations-config__dot {
    display: inline-block;
    width: 9px;
    height: 9px;
    margin-right: 6px;
    border-radius: 50%;
    background: var(--k-text-muted);
    vertical-align: middle;
}
.k-locations-config__dot--on { background: var(--k-success); box-shadow: 0 0 6px var(--k-success); }

/* C3 (mock .qr M:247-248): the QR sticker plus a tick (connected, green) or a cross (not, red). A POI's
   cell carries the bare class and nothing in it (Q7), so it has no colour of its own. */
.k-locations-config__qr { display: inline-flex; align-items: center; gap: 6px; vertical-align: middle; }
.k-locations-config__qr svg { width: 14px; height: 14px; }
.k-locations-config__qr svg.k-locations-config__qr-mark { width: 13px; height: 13px; }
.k-locations-config__qr--ok { color: var(--k-success); }
.k-locations-config__qr--no { color: var(--k-danger); }

/* C9 (mock tr.inactive M:249): an inactive location's row is muted — KerberGrid's RowCssClass puts the
   class on the row. The cells' own spans carry an explicit colour (above), so they are muted by name;
   the dot keeps its grey and the QR mark its meaning. */
.k-grid__dx tr.k-locations-config__row--inactive > td,
.k-grid__dx tr.k-locations-config__row--inactive > td .k-locations-config__cell {
    color: var(--k-text-muted);
}

/* The six-tab strip of one location. Deliberately the same shape as W5's .k-location-view__tabs —
   an operator moving between the operational view and the configuration screen should recognise the
   control — but its own block, because the two disagree about one thing this one has and that one
   does not: a DISABLED tab. */
.k-location-config__tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin: 12px 0 0;
    border-bottom: 1px solid var(--k-border);
}

.k-location-config__tab {
    padding: 6px 12px;
    /* K3c rez B: web-14-moja-tvrtka-lokacije.html:95 i :153 .tabs span */
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    border-bottom: 2px solid transparent;
    color: var(--k-text-muted);
    text-decoration: none;
}

.k-location-config__tab:hover { color: var(--k-text); }

.k-location-config__tab--active {
    color: var(--k-text);
    border-bottom-color: var(--k-accent);
}

/* A disabled tab is a <span>, so it has no link affordance to remove — only the muted, non-clickable
   look that says the same thing to a sighted user that aria-disabled says to a screen reader. */
.k-location-config__tab--disabled { opacity: 0.5; cursor: default; }

.k-location-config__tab:focus-visible {
    outline: 2px solid var(--k-accent);
    outline-offset: -2px;
}

/* web-14 14c-1 D6 (mock web-14 M:97 `.tabs a i`, M:340): the number beside a tab — the tab's own rows.
   An <i> INSIDE the tab's link or span, so the tab keeps its caption first; upright and muted, never
   the tab's active colour or weight. */
.k-location-config__count { font-style: normal; color: var(--k-text-muted); margin-left: 6px; font-weight: 400; }

.k-location-config__note { margin: 8px 0 0; font-size: 13px; color: var(--k-text-muted); }

.k-location-config__body { margin-top: 12px; }

.k-location-config__pending { margin: 0; color: var(--k-text-muted); }

/* web-14 14c-1 D3 (mock `.qr` M:247–248, k2 r.337): the header's QR link fact — the QR icon, the tick or the
   cross, and the words; success when linked, danger (Q1) when not. */
.k-location-fact-qr { display: inline-flex; align-items: center; gap: 6px; }
.k-location-fact-qr svg { width: 14px; height: 14px; }
/* The second icon — the tick or the cross — is 13 px (mock M:337 / M:310), set here, not inline (CSP). */
.k-location-fact-qr svg + svg { width: 13px; height: 13px; }
.k-location-fact-qr--ok { color: var(--k-success); }
.k-location-fact-qr--no { color: var(--k-danger); }

/* web-14 E1 (M:251): dvije kartice — Podaci lijevo, Karta desno; ispod 900 px jedan stupac (G15, 200 % zoom) */
.k-location-general-form__fields { display: flex; flex-direction: column; gap: 10px; }

.k-location-general-form__field { display: flex; flex-direction: column; gap: 4px; }

/* The one pair of boxes that belongs on one line: latitude and longitude are one value in two
   halves, and reading them stacked invites entering one and forgetting the other. */
.k-location-general-form__pair { display: flex; flex-wrap: wrap; gap: 8px; }

/* web-14 E9 (M:349 `style="opacity:.6"`): an EXISTING location's coordinates are read, not typed (W-46,
   Q-14c-8 „a") — the boxes are dimmed as the mock dims them. A number, not a colour: no token exists.
   M:349 opacity:.6 — isti oblik kao web-15 `.k-control-point-editor__coordinate`. */
.k-location-general-form__field--readonly .k-location-general-form__pair { opacity: .6; }

.k-location-general-form__label { font-size: 13px; color: var(--k-text-muted); }

/* B14 / W-06 (mock web-14 .fld label em M:197): the required field's star — Naziv and Klijent only.
   Same shape as `.k-control-point-editor__required`. */
.k-location-general-form__required { font-style: normal; color: var(--k-danger); margin-left: 3px; }

.k-location-general-form__hint { margin: 0; font-size: 13px; color: var(--k-text-muted); }

/* W-44 (mock web-14 `.tags span` + `.tags .add`): „+ dodaj" uz Radna mjesta i Zone — the mock's tag pill,
   dashed, transparent and muted. The theme has no quiet pill-button of this shape, hence this one rule. It
   sits under its TagBox at its own width (align-self), and :hover is listed beside the resting state so the
   global `button:hover` (0,1,1) does not fill it with the accent. */
.k-location-general-form__tag-add,
.k-location-general-form__tag-add:hover {
    align-self: flex-start;
    height: 26px;
    padding: 0 10px;
    border: 1px dashed var(--k-accent);
    border-radius: 13px;
    background: transparent;
    color: var(--k-text-muted);
    font-size: 12px;
    font-weight: 400;
    letter-spacing: normal;
}

/* #3554 A: „Traži adresu" under the address box — the type switch's button (__kind-option) at its own width
   rather than stretched across the field's column. Placement only: no colour of its own. */
.k-location-general-form__geocode { align-self: flex-start; }

/* The number of shifts beside a position's name inside its tag (mock web-14-moja-tvrtka-lokacije.html:263
   `.tags span i`, k2 :347 „Porta <i>2 smjene</i>"): upright and muted. GeneralTab puts a real space in the DOM
   before the number (so it is read „Porta 1 smjena"); that space plus this 3px make the mock pill's 6px gap. */
.k-location-general-form__tag-shifts { font-style: normal; color: var(--k-text-muted); margin-left: 3px; }

/* The positions' tags carry that number through DevExpress's TagDisplayTemplate, and DevExpress 25.2.9 (Fluent
   core.min.css) paints the tag's pill only on `.dxbl-tag:not(.dxbl-tag-tmpl)`. This puts back exactly what that
   rule gives every other tag — DevExpress's own variables — so the positions' tags look like the zones'. */
.k-location-general-form__field[data-kerber-location-field="roles"] .dxbl-tag-box.dxbl-text-edit > .dxbl-tag.dxbl-tag-tmpl {
    border-radius: var(--dxbl-tag-box-tag-border-radius);
    background-color: var(--dxbl-tag-box-tag-bg);
    color: var(--dxbl-tag-box-tag-color);
}

/* A refusal sits UNDER the box it belongs to (the W4 R4 discipline: field-hinted, save-gated). */
.k-location-general-form__field-error { margin: 0; font-size: 13px; color: var(--k-danger); }
/* #4411 (mock upozorenja): the working-position line under „Radna mjesta" is a warning the operator may override
   („Spremi svejedno"), not an error — body text with the warning triangle in the warning colour. */
.k-location-general-form__field-error--warning { color: var(--k-text); }
.k-location-general-form__field-error--warning::before { content: "\26A0\FE0E\00A0"; color: var(--k-warning); }

.k-location-general-form__error { margin: 8px 0 0; color: var(--k-danger); }

.k-location-general-form__loading { margin: 0; color: var(--k-text-muted); }

.k-location-general-form__actions { display: flex; gap: 8px; margin-top: 12px; }

.k-location-general-form__save {
    padding: 6px 14px;
    border: 1px solid var(--k-accent);
    border-radius: 4px;
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    font: inherit;
    cursor: pointer;
}

.k-location-general-form__save[disabled] { opacity: 0.6; cursor: default; }

.k-location-general-form__map { margin-top: 16px; }

.k-location-general-form__map-caption { margin: 0 0 8px; font-size: 15px; }

/* Raspored, nije iz mocka: the stage is what the caption is positioned against (the mock's `.map`),
   and (REV I-1) the container whose width decides where the caption goes around the base switch. */
.k-location-general-form__map-stage { position: relative; container-type: inline-size; }

/* web-14 E13 (M:274 `.map .ttl`): --k-text-label stands for the mock's --label. Above the provider's
   tiles, never catching the pointer (the map stays draggable/pannable under it) — pointer-events is
   not from the mock. NO z-index, deliberately: .k-map__canvas is its own stacking context (z-index 0)
   and this caption comes AFTER the map in the markup, so tree order already paints it over the tiles;
   a z-index here would be a new owner in the theme's stacking set, which MapSwitchStackingTests Z3
   enumerates and forbids moving.
   THE GENERAL MAP HAS THE BASE SWITCH (REV I-1): KerberMap draws .k-map__views on every available map,
   top right, opaque, z-index 1 — so it paints OVER this caption wherever the two meet, and the caption
   must not reach under it.
   Raspored, nije iz mocka (the mock has no switch): `right` keeps the caption's column clear of the
   switch, and the caption wraps inside it. No token holds the switch's width, so it is derived here
   from the switch's own rules, in their order — 1px .k-map border + 12px .k-map__views right + 2×1px
   its border + 2×6px its padding + 2×4px .k-map__views-group gap + 3×2×10px .k-map__view padding +
   11em of label text (the widest set, en ROADS / SATELLITE / TERRAIN: 10.992em measured over
   SairaSemiCondensed-SemiBold.ttf's advance widths; the switch's 12px is this caption's 12px, so the
   em is shared) + 21 letters × .5px .k-map__view letter-spacing + 12px clear space (this caption's own
   left) = 249.5px at 12px. */
.k-location-general-form__map-over { position: absolute; left: 12px; top: 10px; right: calc(1px + 12px + 2 * 1px + 2 * 6px + 2 * 4px + 3 * 2 * 10px + 11em + 21 * .5px + 12px); pointer-events: none; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: var(--k-label-tracking); color: var(--k-text-label); }

/* Raspored, nije iz mocka (REV I-1): a stage of 520px or less would leave the caption beside the switch
   a column of ~258px or less (520 − 12 − 249.5), and at the narrowest two-column layout (~901px) that
   column is gone entirely. There the caption moves UNDER the switch and takes the full width instead:
   its top is the switch's bottom — 1px .k-map border + 12px .k-map__views top + 2×1px its border +
   2×6px its padding + 2×4px .k-map__view padding + 1.6em line — plus 8px. The line is NOT Saira's
   line-height normal: .k-map__view's `font: inherit` takes line-height 1.5 from the Bootstrap reboot of
   DevExpress BlazingDark bs5 (REV re-review n-1), and 1.6em is a safe upper bound over that 1.5. */
@container (max-width: 520px) {
    .k-location-general-form__map-over { top: calc(1px + 12px + 2 * 1px + 2 * 6px + 2 * 4px + 1.6em + 8px); right: 12px; }
}

/* web-14 E1/E4 (M:251-257): the two cards. Every rendered root carries --cards (the loading and
   unavailable states render a lone <p>, not the root), so the element rules above are the cards'
   base and the rules below override them where the cards differ. */
.k-location-general-form--cards {
    display: grid;
    grid-template-columns: 1.1fr 1fr;
    /* web-14 E14 (M:353-369): Karta and the QR card share the right-hand column. The data card spans
       both rows (below), and the SECOND row is the flexible one — so the data card's height lands
       there and the first row is exactly Karta's: the QR card sits right under it. */
    grid-template-rows: auto 1fr;
    gap: 14px;
    align-items: start;
}

.k-location-general-form__card {
    background: var(--k-surface);
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius);
    padding: 14px 18px 16px;
}

.k-location-general-form__card-title {
    margin: 0 0 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--k-border-strong);
    font-size: 14px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-accent);
}

.k-location-general-form__fields.k-location-general-form__card {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px 10px;
    grid-row: span 2;
}

/* Inside the data card's two-column grid every field and the title span the row; only the --half
   pair (address, phone — E4) shares one. */
.k-location-general-form__fields.k-location-general-form__card > .k-location-general-form__card-title { grid-column: 1 / -1; margin-bottom: 0; }

.k-location-general-form__field { grid-column: 1 / -1; }

.k-location-general-form__field--half { grid-column: auto; }

/* __map's own 16 px top margin would push the right-hand column down inside the grid. */
.k-location-general-form__map.k-location-general-form__card { margin-top: 0; }

.k-location-general-form--cards > .k-location-general-form__error,
.k-location-general-form--cards > .k-location-general-form__actions { grid-column: 1 / -1; }

/* web-14 E14 (M:366-368, mock `.qrbox` M:276-278) — the location's QR card, in the right-hand column
   under Karta (M:353-369; the grid's two rows are set on --cards above). Its own rules rather than
   .k-location-general__qr-box's: two views, two rules (O-10) — that one is a 180 px white panel with
   a 156 px code and the name under it, aligned to the top beside its actions; this one is the mock's
   96 px code with its own white frame, centred beside two lines of text. */
.k-location-qr { grid-column: 2; }
.k-location-qr__box { display: flex; gap: 14px; align-items: center; }
/* THE QR SITS ON WHITE, in the dark theme's middle — the .k-qr-sheet rule's reason: a code drawn in
   the theme's colours is not the code the printer and the phone camera will see. The white frame is
   the code's quiet zone (part of a scannable code, not decoration), and the white is the theme's own
   --k-white-rgb, as on .k-login__qrbox. Never smoothed: a resampled module edge is what a phone
   camera fails on. */
.k-location-qr__image {
    width: 96px;
    height: 96px;
    image-rendering: pixelated;
    border: 6px solid rgb(var(--k-white-rgb));
    border-radius: 4px;
    background: rgb(var(--k-white-rgb));
}
.k-location-qr__text { font-size: 13px; color: var(--k-text-muted); }
.k-location-qr__text b { color: var(--k-text); display: block; }

@media (max-width: 900px) {
    .k-location-general-form--cards { grid-template-columns: 1fr; grid-template-rows: none; }
    .k-location-general-form__field--half { grid-column: 1 / -1; }
    /* One column: every card back in document order — data, Karta, QR. */
    .k-location-general-form__fields.k-location-general-form__card { grid-row: auto; }
    .k-location-qr { grid-column: auto; }
}

/* web-14 E6 (M:346, OP-9): the type switch — separate buttons with aria-pressed, the shape and tokens
   of 14a's scope switch, as its own block (scen 80's pin forbids .k-mapgrid__mode here). */
.k-location-general-form__kind { display: flex; gap: 8px; flex-wrap: wrap; }

.k-location-general-form__kind-option {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font: inherit;
    /* K3c rez B: web-14-moja-tvrtka-lokacije.html:226 i :260 .kind span */
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    color: var(--k-text);
    background: var(--k-surface);
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    padding: 4px 10px;
    cursor: pointer;
}

.k-location-general-form__kind-option svg { width: 14px; height: 14px; }

.k-location-general-form__kind-option--on {
    color: var(--k-btn-text-on-accent);
    background: var(--k-accent);
    border-color: var(--k-accent);
}

/* The pin's hole: the mock's raw fill, as the page token — and the accent on the pressed button. */
.k-location-general-form__kind-hole { fill: var(--k-bg); }

.k-location-general-form__kind-option--on .k-location-general-form__kind-hole { fill: var(--k-accent); }

.k-location-general-form__kind-option:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* web-14 E10 (M:350): „Stanje" above the switch, a column like every other field. The global input box
   rule (input:not([type="checkbox"])…) excludes the switch's input (#149), and the global input:hover /
   input:focus rules still match it — focus sets outline: none (pre-existing). The switch's colour, size
   and focus ring are the house's, set at the end of this section (14b snapshot fix). */
.k-location-general-form__field--state { gap: 6px; }

/* web-14 E15 (M:284 .savebar, M:371): Odustani · Spremi below both cards, on the right. The grid's own
   gap already separates the row from the cards, hence no top margin. */
.k-location-general-form--cards > .k-location-general-form__actions { justify-content: flex-end; gap: 10px; margin-top: 0; }

/* web-14 F3 (M:283 `.fixd`, M:421): the pending-correction note, pushed left of Odustani/Spremi. */
.k-location-general-form__pending { margin-right: auto; font-size: 12px; color: var(--k-warning); }

/* W-45 (docs/design/web-decisions.md:119, „ispod naziva žuto"; for the location W-46 :120): the
   hand-correction line under the coordinates field — the mock's yellow note (web-14 M:283 `.fixd`). */
.k-location-general-form__corrected { margin: 0; font-size: 12px; color: var(--k-warning); }

/* M:36 .btn.sec — the quiet button, in __save's proportions. */
.k-location-general-form__cancel {
    padding: 6px 14px;
    border: 1px solid var(--k-border-strong);
    border-radius: 4px;
    background: transparent;
    color: var(--k-text);
    font: inherit;
    cursor: pointer;
}

.k-location-general-form__cancel[disabled] { opacity: 0.6; cursor: default; }

.k-location-general-form__save:focus-visible,
.k-location-general-form__cancel:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* .k-switch — THE SHARED DEVEXPRESS-SWITCH PRIMITIVE (ARH-C 20261002-163659), theme-wide: any
   DxCheckBox with CheckType.Switch that carries CssClass="k-switch" (DxDataEditor<T>.CssClass, 25.2)
   takes the mock's SIZE — 38×20 with a 16 px thumb 2 px in (web-14 M:266 .tog i). Consumers: web-14
   14b Stanje (REV-D 141210 t.2) and web-15 15a F7 Stanje. It sits here, at the end of the GeneralTab
   section, only so the hot sheet is not reordered.
   SIZE ONLY (K-3 #3029 × #3053, ARH-C 034431/183951): the colour (--k-accent track, hover), the DARK
   thumb (ARH-C 190105) and the house focus ring come from the theme-wide `.dxbl-checkbox` rules near
   the top of this sheet — ONE place for every DevExpress checkbox, radio and switch, so this block
   names none of them.
   This rule uses the theme's own switch variables and its classes (.dxbl-checkbox, .dxbl-checkbox-switch) —
   INTERNAL DX VARIABLES AND CLASSES, NOT A CONTRACT (re-measure on any DevExpress upgrade). K3-F F2: measured
   in devexpress.blazor.themes.fluent/25.2.9 core.min.css — BlazingDark's `--dxbl-checkbox-switch-{width,height,
   element-size,element-margin}` are read by no Fluent rule. Fluent sizes the track with
   `--dxbl-checkbox-check-element-{width,height}` and the thumb with
   `--dxbl-checkbox-check-element-switch-trigger-{width,height}`, chosen per size mode on
   `.dxbl-checkbox.dxbl-checkbox-switch` (0,2,0) and `….dxbl-sm/.dxbl-lg` (0,3,0); the thumb's inset is
   `--dxbl-checkbox-check-element-switch-margin` (translateX; vertically Fluent centres the thumb). Three
   classes on the switch's own root (0,3,0), later in the cascade, outrank all three size modes, so the
   size holds whatever SizeMode a consumer sets — as BlazingDark's single switch-width did. Fluent draws a
   0.0625rem track border inside the 38×20 (border-box) that BlazingDark did not; on the ON track it takes
   the accent (`.dxbl-checkbox` above). */
.dxbl-checkbox.dxbl-checkbox-switch.k-switch {
    --dxbl-checkbox-check-element-width: 38px;
    --dxbl-checkbox-check-element-height: 20px;
    --dxbl-checkbox-check-element-switch-trigger-width: 16px;
    --dxbl-checkbox-check-element-switch-trigger-height: 16px;
    --dxbl-checkbox-check-element-switch-margin: 2px;
}

/* ── §11.3.2's control points tab and its dialog — W7 Task 7 ─────────────────────────────────────
   TWO BEM BLOCKS AND ALMOST NO LAYOUT, deliberately: the tab's whole surface is W2's KerberMapGrid,
   which brings its own map/table grid (.k-mapgrid), and a second opinion about how the two halves
   share the space here would fight it. What is left is the tab's own two lines and the dialog. */
.k-location-points__cell { color: var(--k-text); }

/* web-15 15b (B1, mock web-15 M:333): the chip row sits in its own line above the MapGrid (Q4) — the
   gap the mock keeps between the chips and the table. */
.k-location-points > .k-chips { margin-bottom: 8px; }

.k-location-points__loading { margin: 0; color: var(--k-text-muted); }

.k-location-points__error { margin: 8px 0 0; color: var(--k-danger); }

/* web-15 15a E2 (mock web-15 .yn M:246): the active cell's dot — grey by default, green for an active
   point. Own classes rather than §11.3's .k-locations-config__dot: #2969 (web-14 14a) is not on main
   at the time of this branch (DIZ-7 Q3, named). */
.k-location-points__dot {
    display: inline-block;
    width: 9px;
    height: 9px;
    margin-right: 6px;
    border-radius: 50%;
    background: var(--k-text-muted);
    vertical-align: middle;
}
/* The glow at the mock's alpha (.yn.on i M:246: rgba(53,203,125,.6)), mixed from the token so the
   colour has one source. */
.k-location-points__dot--on {
    background: var(--k-success);
    box-shadow: 0 0 6px color-mix(in srgb, var(--k-success) 60%, transparent);
}

/* web-15 15a E3 (mock web-15 .qr M:247-248): the QR sticker plus a tick (connected, green) or a cross
   (not connected, red). */
.k-location-points__qr { display: inline-flex; align-items: center; gap: 6px; vertical-align: middle; }
.k-location-points__qr svg { width: 14px; height: 14px; }
.k-location-points__qr svg.k-location-points__qr-mark { width: 13px; height: 13px; }
.k-location-points__qr--ok { color: var(--k-success); }
.k-location-points__qr--no { color: var(--k-danger); }

/* web-15 15a E9 (mock web-15 tr.inactive M:249): an inactive point's row is muted — the MapGrid's
   RowCssClass puts the class on the row. The cells' own spans carry an explicit colour (above), so
   they are muted by name; the dot keeps its grey and the QR mark its meaning. */
.k-grid__dx tr.k-location-points__row--inactive > td,
.k-grid__dx tr.k-location-points__row--inactive > td .k-location-points__cell {
    color: var(--k-text-muted);
}

.k-control-point-editor { min-width: min(420px, 80vw); }

.k-control-point-editor__fields { display: flex; flex-direction: column; gap: 10px; }

.k-control-point-editor__field { display: flex; flex-direction: column; gap: 4px; }

/* web-15 15a krug 1 (mock web-15 .fld label M:196): the field labels read as the mock's — 12 px, 600,
   upper case, the theme's label tracking and label colour (--k-text-label = mock --label #B6B9D1). */
.k-control-point-editor__label {
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-text-label);
}

/* The stored place, which is read rather than edited — see the dialog's own note on why the numbers
   are invariant. */
.k-control-point-editor__coordinates { margin: 12px 0 0; font-size: 13px; }

.k-control-point-editor__hint { margin: 4px 0 0; font-size: 13px; color: var(--k-text-muted); }

/* A refusal sits UNDER the box it belongs to (the W4 R4 discipline: field-hinted, save-gated). */
.k-control-point-editor__field-error { margin: 0; font-size: 13px; color: var(--k-danger); }

.k-control-point-editor__error { margin: 8px 0 0; color: var(--k-danger); }

.k-control-point-editor__actions { display: flex; gap: 8px; justify-content: flex-end; }

.k-control-point-editor__save {
    padding: 6px 14px;
    border: 1px solid var(--k-accent);
    border-radius: 4px;
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    font: inherit;
    cursor: pointer;
}

.k-control-point-editor__save[disabled] { opacity: 0.6; cursor: default; }

.k-control-point-editor__cancel {
    padding: 6px 14px;
    border: 1px solid var(--k-border);
    border-radius: 4px;
    background: var(--k-surface);
    color: inherit;
    font: inherit;
    cursor: pointer;
}

/* web-15 15a F2 (mock web-15 .fld label em M:255): the required field's star. */
.k-control-point-editor__required { font-style: normal; color: var(--k-danger); margin-left: 3px; }

/* web-15 15a F4 (mock web-15 .fld .two M:257): inside its field the coordinate is two read-only boxes
   side by side. Scoped to the field so the older rule above keeps its own meaning untouched. */
.k-control-point-editor__field .k-control-point-editor__coordinates {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin: 0;
}

/* web-15 15a krug 1 F8 (mock web-15 .warnbox M:311, ikona M:436): the hand-correction note as the
   mock's warning box — border and wash mixed from --k-warning at the mock's .5/.08 alpha, the
   triangle 18 px in --k-warning, the text in the label colour. */
.k-control-point-editor__warnbox {
    display: flex;
    gap: 10px;
    padding: 10px 12px;
    border-radius: 8px;
    border: 1px solid color-mix(in srgb, var(--k-warning) 50%, transparent);
    background: color-mix(in srgb, var(--k-warning) 8%, transparent);
    color: var(--k-text-label);
    font-size: 13px;
}
.k-control-point-editor__warnbox-icon { width: 18px; height: 18px; color: var(--k-warning); flex: none; }
.k-control-point-editor__warnbox-text { margin: 0; }

/* web-15 15a krug 2 (mock web-15 M:435 `.in` opacity .6): the two read-only coordinate boxes are
   dimmed — the boxes only (DxTextBox CssClass), not the label above them nor the hint below. */
.k-control-point-editor__coordinates .k-control-point-editor__coordinate { opacity: .6; }

/* ── §11.3.5 documents (W7 Task 8): the two surfaces and the add form they share ───────────────── */

.k-location-documents { display: flex; flex-direction: column; gap: 12px; }

/* #4305 (W-52): the label and the selector side by side in the lead of the grid's bar (one row with search and
   „Izvoz ▾"); the selector takes its own width, as on the Shifts tab. */
.k-location-documents__scope { display: flex; flex-direction: row; align-items: center; gap: 8px; }

/* #4305: the label stays on one line beside the selector (white-space: nowrap; the same on Tasks and Shifts). */
.k-location-documents__label { font-size: 13px; color: var(--k-text-muted); white-space: nowrap; }

.k-location-documents__loading,
.k-worker-documents__loading { margin: 8px 0; color: var(--k-text-muted); }

/* An honest empty state, and it is a statement about the unshaped set — see the tabs' own notes. */
.k-location-documents__empty,
.k-worker-documents__empty { margin: 8px 0; color: var(--k-text-muted); }

.k-location-documents__error { margin: 8px 0; color: var(--k-danger); }

.k-worker-documents { display: flex; flex-direction: column; gap: 12px; min-width: min(680px, 88vw); }

/* #4429: the table in the documents dialog has its own height, never --k-grid-fit-h (registerGridFit skips every grid
   in .dxbl-popup / [role="dialog"], kerber-shell.js). Dialog = table + 390.5 px (measured over #4426, run 39509334111):
   at 28 px top and bottom the table may be H − 446.5; H − 460 (13.5 px spare) gives 540 / 440 px at 1000 / 900. */
.k-worker-documents .k-grid { height: calc(100dvh - 460px); min-height: 240px; }

/* #4429 K5: a worker with NO documents gets the empty-state line above the table, and the body grew by it (V1b 24.10.:
   body content 849 against 804 with two documents, 45 px over the 13.5 px spare — „Dodaj dokument" 15.5 px under the
   body's visible bottom). The line gets a fixed 22 px, so the block it adds is exactly 8 + 22 + 8 margin + 12 gap = 50 px,
   and the table gives those 50 px back: the frame is as tall as with documents. */
.k-worker-documents__empty { line-height: 22px; }

.k-worker-documents:has(> .k-worker-documents__empty) .k-grid { height: calc(100dvh - 510px); }

.k-worker-documents__actions { display: flex; gap: 8px; justify-content: flex-end; }

.k-worker-documents__close {
    padding: 6px 14px;
    border: 1px solid var(--k-border);
    border-radius: 4px;
    background: var(--k-surface);
    color: inherit;
    font: inherit;
    cursor: pointer;
}

/* The add form (both surfaces). The target lines sit above the fields because they are the SCOPE of
   what is about to be written, not one more thing to fill in (scen 151). */
.k-document-add {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px;
    border: 1px solid var(--k-border);
    border-radius: 4px;
    background: var(--k-surface);
}

.k-document-add__targets { display: flex; flex-wrap: wrap; gap: 4px 20px; }

.k-document-add__target { display: flex; gap: 6px; margin: 0; font-size: 13px; }

.k-document-add__target-label { color: var(--k-text-muted); }

.k-document-add__target-value { font-weight: 600; }

.k-document-add__field { display: flex; flex-direction: column; gap: 4px; max-width: 420px; }

.k-document-add__label { font-size: 13px; color: var(--k-text-muted); }

.k-document-add__file { font: inherit; }

.k-document-add__limit { margin: 0; font-size: 12px; color: var(--k-text-muted); }

.k-document-add__message { margin: 0; font-size: 13px; }

.k-document-add__message--error { color: var(--k-danger); }

.k-document-add__actions { display: flex; gap: 8px; }

.k-document-add__save {
    padding: 6px 14px;
    border: 1px solid var(--k-accent);
    border-radius: 4px;
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    font: inherit;
    cursor: pointer;
}

.k-document-add__save[disabled] { opacity: 0.6; cursor: default; }

/* ── §11.3.4 shifts (W7 Task 10): the tab's list, its confirmations and the shift form ─────────── */

.k-location-shifts { display: flex; flex-direction: column; gap: 12px; }

/* #4305: the row's left part — label, selector and „Prikaži i prošle" — is ONE flex row in the bar's lead
   (the left side, so no margin-left: auto as on Tasks). The label does not wrap. */
.k-location-shifts__role { display: flex; align-items: center; gap: 8px; }

/* #4305: „Prikaži i prošle" (the DxCheckBox's wrapper) keeps its caption on one line and does not shrink in
   that flex row — squeezed, it broke into three lines. */
.k-location-shifts__show-past { white-space: nowrap; flex: none; }

.k-location-shifts__label { font-size: 13px; color: var(--k-text-muted); white-space: nowrap; }

.k-location-shifts__loading,
.k-location-shifts__empty { margin: 8px 0; color: var(--k-text-muted); }

.k-location-shifts__error { margin: 8px 0; color: var(--k-danger); }

.k-location-shifts__new {
    padding: 6px 14px;
    border: 1px solid var(--k-accent);
    border-radius: 4px;
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    font: inherit;
    cursor: pointer;
}

.k-location-shifts__calendar { display: flex; flex-direction: column; gap: 8px; }

.k-location-shifts__calendar-title { margin: 0; font-size: 15px; }

.k-shift-editor__confirm {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 8px 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: 4px;
    background: var(--k-surface);
}

.k-shift-editor__confirm-text { margin: 0; }

/* B13 / W-04 (web-decisions :78): the inline delete confirmation's RED TITLE, on a line of its own above the
   question (the confirm is a wrapping flex row). */
.k-shift-editor__confirm-title { margin: 0; flex-basis: 100%; color: var(--k-danger); font-weight: 700; }

.k-shift-editor__confirm-yes,
.k-shift-editor__confirm-no,
.k-shift-editor__save,
.k-shift-editor__delete,
.k-shift-editor__cancel {
    padding: 6px 14px;
    border: 1px solid var(--k-border-strong);
    border-radius: 4px;
    background: var(--k-surface);
    color: inherit;
    font: inherit;
    cursor: pointer;
}

.k-shift-editor__save {
    border-color: var(--k-accent);
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
}

.k-shift-editor__save[disabled],
.k-shift-editor__delete[disabled] { opacity: 0.6; cursor: default; }

/* B13 / W-04 (web-decisions :78; owner 1.10. #18; mock web-17 k6 :610 `.btn.dan.outl`): the two DELETE buttons —
   the footer's „Obriši smjenu" and the confirmation's „Obriši" — are a red OUTLINE with red text, never filled.
   LOCAL rules, colour only: K3c N4 forbids k-btn / k-btn--danger-outline on these markers (A classes, #3436), so
   k-btn--danger-outline's colours are repeated here; the shape stays the grouped rule's above, which is not split
   (K3c P-pop). Like k-btn--danger-outline: the base also covers a disabled button under the mouse, and the
   hover/active wash stays a WASH (≤ .15), enabled only — (0,3,0) over the global `button:hover` (0,1,1), which
   would otherwise fill it with the accent. */
.k-shift-editor__confirm-yes,
.k-shift-editor__confirm-yes:disabled:hover,
.k-shift-editor__delete,
.k-shift-editor__delete:disabled:hover {
    background: transparent;
    border-color: var(--k-danger);
    color: var(--k-danger);
}
.k-shift-editor__confirm-yes:hover:not(:disabled),
.k-shift-editor__confirm-yes:active:not(:disabled),
.k-shift-editor__delete:hover:not(:disabled),
.k-shift-editor__delete:active:not(:disabled) {
    background: rgba(var(--k-danger-rgb), 0.1);
    border-color: var(--k-danger);
    color: var(--k-danger);
}

/* web-17 D2c k4a — „Otkaži smjenu" (ShiftCancelDialog). Colours, border, shadow, header and buttons are the K2c
   dialog shell's (confirm, danger) and k-btn--danger-outline's (#3097); only what is the dialog's own lives
   here. K3a′ N2 (ARH-C 073345): its sentences are 14px — the mock's dialog body `.dlg .fb`
   web-17:380 (dialog web-17:540–547). The gap between the summary, the choice and its effect is the 12px the
   theme's other dialogs use (the theme has no spacing token). */
.k-shift-cancel-dialog__text { margin: 0; font-size: 14px; }
.k-shift-cancel-dialog .k-shift-cancel-dialog__content { display: flex; flex-direction: column; gap: 12px; }
.k-shift-cancel-dialog .k-shift-cancel-dialog__scope { border: 0; margin: 0; padding: 0; }

/* web-22 22c — „Obriši uređaj" (DeviceDeleteDialog). Shell as ShiftCancelDialog's (K2c confirm, danger); its two
   sentences are the mock's 14px — without this rule they were 12.25px (e2e R6, PR-CI 38035593360; REV-D2 074830,
   ARH-C 075241). Only the size is the dialog's own: the gap between the sentences stays the shell's
   `.k-dialog__body p` margin. */
.k-device-delete-dialog__text { font-size: 14px; }

/* web-17 PR-C k2 — the shift calendar (mock web-17 M:344, M:392-393, M:467). A cancelled occurrence is
   a HOLE (W-41) and carries no style at all. Through W2's additive CalendarTask.CssClass seam
   (ShiftCalendarInput): the alarm-1-exempt shift is the DASHED block, and a task is muted CONTEXT with
   its name on the right. No stacking rule: DevExpress lays overlapping appointments out SIDE BY SIDE in
   columns (measured golden tests/Kerber.Server.Tests/W2/Golden/calendar-demo-default.html:873-879,
   data-columns-count="2"), so the task never sits under the shift it falls in — and
   MapSwitchStackingTests.Z3 enumerates every z-index owner in this theme. The classes are repeated for
   the specificity reason the shift backdrop's rule documents: DevExpress's own appointment classes are
   more specific than one of ours. */
/* PILOT 24.10. — the SHIFT BLOCK (mock web-17 `.shb` M:389; the same values as the legend's
   `.k-shift-legend__swatch--shift` below): every occurrence carries `k-shift-occurrence`
   (ShiftCalendarInput.ShiftCssClass), and this rule is the block's ONLY fill — KerberCalendar's appointment
   template replaces DevExpress's `.dxbl-apt-bg`, the one element Fluent 25.2.9 paints, so without it the
   block is transparent and the shift's duration cannot be seen. It sits BEFORE the exempt rule on purpose:
   the same specificity (0,3,0), so the later exempt rule's dashed border wins and the fill stays. */
.k-calendar .k-shift-occurrence.k-shift-occurrence {
    background: rgba(var(--k-white-rgb), 0.1);
    border: 1px solid rgba(var(--k-white-rgb), 0.28);
    border-radius: 4px;
}
.k-calendar .k-shift-occurrence--exempt.k-shift-occurrence--exempt {
    border: 1px dashed rgba(var(--k-white-rgb), 0.28);
    border-radius: 4px;
}
.k-calendar .k-shift-context-task.k-shift-context-task {
    opacity: 0.55;
    text-align: right;
}
/* The caption row's legend (mock M:321-323, M:467): a small swatch before each word. */
.k-shift-legend__item { display: inline-flex; align-items: center; gap: 5px; }
.k-shift-legend__swatch { display: inline-block; width: 14px; height: 12px; border-radius: 3px; }
.k-shift-legend__swatch--shift { background: rgba(var(--k-white-rgb), 0.1); border: 1px solid rgba(var(--k-white-rgb), 0.28); }
.k-shift-legend__swatch--exempt { background: rgba(var(--k-white-rgb), 0.1); border: 1px dashed rgba(var(--k-white-rgb), 0.28); }
.k-shift-legend__swatch--task { background: rgba(var(--k-accent-rgb), 0.28); border: 1px solid var(--k-accent); opacity: 0.55; }

/* web-17 D2c k3 — the shift callout's CONTENT (mock k3 M:500-505): the name, four rows with the label muted on
   the left and the value on the right, and the two actions on the right. The card's frame, tail and placement
   are KerberCalendarCallout's (W-20) and are not repeated here; no stacking rule (MapSwitchStackingTests.Z3).
   Tokens only. */
.k-shift-card { display: flex; flex-direction: column; gap: 6px; min-width: 260px; color: var(--k-text); }
.k-shift-card__row { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; font-size: 13px; }
.k-shift-card__label { color: var(--k-text-muted); }
.k-shift-card__value { text-align: right; }
.k-shift-card__actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 6px; }

.k-shift-editor { display: flex; flex-direction: column; gap: 12px; min-width: 320px; }

.k-shift-editor__scope { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; margin: 0; }

.k-shift-editor__scope-label { color: var(--k-text-muted); }

.k-shift-editor__scope-value { margin: 0; }

.k-shift-editor__fields { display: flex; gap: 12px; flex-wrap: wrap; }

.k-shift-editor__field { display: flex; flex-direction: column; gap: 4px; }

.k-shift-editor__field--check { flex-direction: row; align-items: center; }

.k-shift-editor__label { font-size: 13px; color: var(--k-text-muted); }

/* B14 / W-06 (mock web-17 .fld label em M:255): the required field's star — name, start and end only.
   Same shape as `.k-control-point-editor__required`. */
.k-shift-editor__required { font-style: normal; color: var(--k-danger); margin-left: 3px; }

.k-shift-editor__choice { max-width: 220px; }

.k-shift-editor__number { max-width: 140px; }

.k-shift-editor__error { margin: 0; color: var(--k-danger); }

.k-shift-editor__field-error { margin: 0; font-size: 13px; color: var(--k-danger); }

/* B13 — mock web-17 k6 :610 (`.ff.split`): Delete left, the Cancel / Save group pushed right (margin-left: auto,
   so without Delete the group still stays right); the row spans the popup footer (the k-manual-dialog__footer way). */
.k-shift-editor__actions { display: flex; gap: 8px; width: 100%; }

.k-shift-editor__actions-end { display: flex; gap: 8px; margin-left: auto; }

/* web-17 A2-T4 (W-51, mock k1 M:363, :433-439) — the shift list as a KerberGrid. A FINISHED definition's
   row is muted by COLOUR, never opacity (REV-D U2c): the quiet name link inherits it (W-24). The line under
   the name is the mock's .ver (11 px, muted, on its own line); "(+1 dan)" and the dash of "no exemption"
   are muted text; the exemption tick is the mock's .chk.on box. Tokens only. */
.k-location-shifts__row--finished td { color: var(--k-text-muted); }

.k-shifts__sub { display: block; font-size: 11px; color: var(--k-text-muted); }

.k-shifts__next-day { color: var(--k-text-muted); }

.k-shifts__none { color: var(--k-text-muted); }

.k-shifts__check {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border: 1px solid var(--k-accent);
    border-radius: 4px;
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    font-size: 13px;
}

/* ── §11.3.3 tasks (W7 Task 12): the tab's scope row, its view switch and its two surfaces ─────── */

.k-location-tasks-config { display: flex; flex-direction: column; gap: 12px; }

/* #4305 (W-48) — ROW 1: the status chips on the left, the working position (label + selector, __role) on the
   right; margin-left: auto keeps the position right when there are no chips. „Novi zadatak" and List / Calendar
   are row 2's (a KerberGridBar). */
.k-location-tasks-config__scope { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }

.k-location-tasks-config__role { display: flex; align-items: center; gap: 8px; margin-left: auto; }

/* #4305: the label stays on one line beside the selector. */
.k-location-tasks-config__label { font-size: 13px; color: var(--k-text-muted); white-space: nowrap; }

.k-location-tasks-config__loading,
.k-location-tasks-config__empty { margin: 8px 0; color: var(--k-text-muted); }

.k-location-tasks-config__error { margin: 8px 0; color: var(--k-danger); }

/* New task is an ANCHOR (navigation into the wizard) styled as the primary action of the scope row —
   the same treatment §11.3.4's New shift button gets, so the two tabs read alike. */
.k-location-tasks-config__new {
    padding: 6px 14px;
    border: 1px solid var(--k-accent);
    border-radius: 4px;
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    font: inherit;
    text-decoration: none;
}

/* P77 (#3689, 1 (a)) — on a DEACTIVATED location New task is a <span aria-disabled="true"> with no
   href: muted and not clickable, the treatment .k-btn[aria-disabled="true"] gets. The note beside it
   says why in visible text (the same words as the span's tooltip). */
.k-location-tasks-config__new[aria-disabled="true"] {
    opacity: .4;
    cursor: not-allowed;
}

.k-location-tasks__inactive-note { font-size: 13px; color: var(--k-text-muted); }

.k-location-tasks-config__views { align-self: flex-start; }

/* #3756 — the status chips Svi / Aktivni / Neaktivni in the scope row (.k-chips already wraps).
   #4305: first in the row, so the rule that set them off from the selector before them is gone. */
.k-location-tasks-config__status {
    display: flex;
    align-items: center;
    align-self: center;
}

/* P106 — "something is defined, nothing is active" (mock kadar 4, `td.praz`): muted like the empty state,
   its title in the text colour at 15 px on its own line. */
.k-location-tasks-config__no-active { margin: 8px 0; color: var(--k-text-muted); }

.k-location-tasks-config__no-active b { display: block; font-size: 15px; color: var(--k-text); }

/* One cell of the DEFINITIONS grid (#209) — the plain text treatment §11.3's locations grid uses for
   its own cells. P106: an INACTIVE definition's row is muted under „Svi" (below), and because this rule
   gives the cell its own colour, the muting names the cell as well as the td. */
.k-location-tasks-config__cell { color: var(--k-text); }

/* P106 — the inactive row under „Svi" (mock kadar 3, the control points' tr.inactive shape): muted by
   COLOUR, never opacity (REV-D U2c); the quiet name link inherits it. */
.k-grid__dx tr.k-location-tasks-config__row--inactive > td,
.k-grid__dx tr.k-location-tasks-config__row--inactive > td .k-location-tasks-config__cell {
    color: var(--k-text-muted);
}

/* P106 — the „neaktivan" pill after the name (the theme's .k-pill--compact); the space before it is the
   consumer's, so it is set here. */
.k-location-tasks-config__inactive { margin-left: 8px; }

/* The row's own link into the wizard — the name (W-48 took the „Uređivanje" column off). It inherits
   the cell's colour rather than the browser's link blue: inside a grid cell a coloured word would read
   as a status, which is the one thing the status column is for. The underline on hover is what says it
   is a link. */
.k-location-tasks-config__open { color: inherit; text-decoration: none; }

.k-location-tasks-config__open:hover,
.k-location-tasks-config__open:focus-visible { text-decoration: underline; }

.k-location-tasks-config__calendar { display: flex; flex-direction: column; gap: 8px; }

.k-location-tasks-config__calendar-title { margin: 0; font-size: 15px; }

/* W-50 (#1766) — the task callout's CONTENT (mock web-16 k3): the name, two rows with the label muted on the
   left and the value on the right, and the actions on the right. A copy of the shift card's rules (web-17 D2c k3)
   under the task's own block: .k-shift-card is the SHIFT callout's, and each screen's BEM block is its own. The
   card's frame, tail and placement are KerberCalendarCallout's (W-20) and are not repeated here; no stacking rule
   (MapSwitchStackingTests.Z3). Tokens only. */
.k-task-card { display: flex; flex-direction: column; gap: 6px; min-width: 260px; color: var(--k-text); }
.k-task-card__row { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; font-size: 13px; }
.k-task-card__label { color: var(--k-text-muted); }
.k-task-card__value { text-align: right; }
.k-task-card__actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 6px; }

/* W-50 (#1766) — „Obriši ponavljanje" (TaskOccurrenceDeleteDialog). Colours, border, shadow, header and buttons
   are the K2c dialog shell's (confirm, danger; W-04) and k-btn--danger-outline's; only what is the dialog's own
   lives here, copied from ShiftCancelDialog's rules under the task's own block: 14px sentences, the 12px gap
   between the summary, the choice and its effect, a bare fieldset. The outcome's sentence (refused / failed) is
   the danger colour the tabs' other alerts use (.k-location-tasks-config__error). */
.k-task-delete-dialog__text { margin: 0; font-size: 14px; }
.k-task-delete-dialog .k-task-delete-dialog__content { display: flex; flex-direction: column; gap: 12px; }
.k-task-delete-dialog .k-task-delete-dialog__scope { border: 0; margin: 0; padding: 0; }
.k-task-delete-dialog__message { margin: 0; font-size: 14px; color: var(--k-danger); }

/* ── §11.5's templates screen — W7 Task 13 ───────────────────────────────────────────────────────
   One column and two links, so this block only has to answer one question the neighbouring screens
   have not: what a NAVIGATION affordance looks like where its neighbours are buttons. "New template"
   is an anchor (the wizard is a page, not a dialog) and takes the primary treatment §11.1's toolbar
   command already has, so the two menu entries read alike; the row links inherit the cell's colour
   rather than the browser's link blue, because a coloured word inside a grid cell reads as a status.
   The rules are duplicated rather than shared under a common class name for the reason §11.2's block
   states: each screen's BEM block is its own, and a shared .k-company__cell would make one screen's
   restyling reach into the others. */
.k-company-templates__new {
    padding: 6px 14px;
    border: 1px solid var(--k-accent);
    border-radius: 4px;
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    font: inherit;
    text-decoration: none;
}

.k-company-templates__loading { margin: 8px 0; color: var(--k-text-muted); }

.k-company-templates__open,
.k-company-templates__action { color: inherit; text-decoration: none; }

.k-company-templates__open:hover,
.k-company-templates__open:focus-visible,
.k-company-templates__action:hover,
.k-company-templates__action:focus-visible { text-decoration: underline; }

/* ── §11.6's settings screen — W7 Task 15, laid out as two columns of cards by web-24 24a ──────────
   Six blocks on one page (company data, logo, alarms on the left; zones, incident categories and the
   G9 saved-table-layouts reset as the small last card on the right — mock web-24-postavke.html
   M:550–551). The page-level block .k-settings-page owns the columns and their 14 px rhythm (which
   replaced the old 24 px margin between stacked sections); .k-settings-card is the one card look all
   six share. Both live ONLY in this §11.6 block — ruling R3: no card rule ever goes on
   .k-company-alarms*, whose root §11.8's alarms page (AlarmsPage.razor) carries too.
   The two named lists share one BEM block (.k-settings-list) because they share one component; the
   rules are otherwise duplicated per screen rather than shared under a common name, for the reason
   §11.2's block states — each screen's BEM block is its own. */
.k-settings-page__columns { display: grid; grid-template-columns: 1.15fr 1fr; gap: 14px; align-items: start; }

.k-settings-page__column { display: flex; flex-direction: column; gap: 14px; min-width: 0; }

.k-settings-card { background: var(--k-surface); border: 1px solid var(--k-border-strong); border-radius: 10px; padding: 14px 18px 16px; }

/* The mock draws the desktop only (H2); below 900 px the columns stack — and so do a card's two-up
   field rows (.k-settings-card__row, its own block below) — the threshold §11.1's cards use
   (.k-location-general-form--cards). An override has its base rule's specificity, so it must come
   AFTER that rule (SettingsPageRenderTests.B_settings_narrow_overrides_come_after_their_base_rules). */
@media (max-width: 900px) { .k-settings-page__columns { grid-template-columns: 1fr; } }

/* The one card heading, subtitle and footer (mock .card h2 / .card h2 small / .card .foot, M:552–554),
   and the page header's note (M:585). On the §11.6 block only — never on .k-company-alarms* (R3). */
.k-settings-card__heading { margin: 0 0 12px; padding-bottom: 8px; border-bottom: 1px solid var(--k-border-strong); display: flex; justify-content: space-between; align-items: center; gap: 12px; font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: .5px; color: var(--k-accent); }

.k-settings-card__sub { color: var(--k-text-muted); font-size: 12px; font-weight: 400; text-transform: none; letter-spacing: 0; }

.k-settings-card__foot { display: flex; justify-content: flex-end; gap: 10px; margin-top: 8px; }

.k-settings-page__note { color: var(--k-text-muted); font-size: 13px; }

/* A card's fields, its two-up rows, the required mark, a note under a field and the failed-read line
   (mock .fld / .fld .two / .fld label em / .fld .hint, M:255–258, M:197). The mark's look is local
   until the shell's forms (G3) bring a shared class. The card's width now bounds the fields, so the
   old 520 px cap on .k-company-data__fields is gone. The row's tracks are minmax(0, 1fr) (the idiom
   of .k-device-pairing below) so an editor's min-content can never push the right field past the
   card. A __group holds a row and the note under it, so the fields' 12 px gap is not between them
   and the note sits the mock's 4 px under the row (M:258, M:592). */
.k-settings-card__fields { display: flex; flex-direction: column; gap: 12px; }

.k-settings-card__group { display: flex; flex-direction: column; }

.k-settings-card__row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 10px; }

/* Below 900 px the two-up rows stack — AFTER the base rule above, which has the same specificity. */
@media (max-width: 900px) { .k-settings-card__row { grid-template-columns: 1fr; } }

.k-settings-card__required { margin-left: 3px; color: var(--k-danger); font-style: normal; }

.k-settings-card__note { margin: 4px 0 0; color: var(--k-text-muted); font-size: 12px; }

.k-settings-card__error { color: var(--k-danger); }

/* A card's own field, its narrow number box (mock .num .in — 90 px, right-aligned, M:569), a field's
   refusal and the card's message line — first used by the alarms card (web-24 24a, E5). On the §11.6
   block only: the alarms card's old .k-company-alarms__* classes stay unstyled (R3). */
.k-settings-card__field { display: flex; flex-direction: column; gap: 4px; }

.k-settings-card__number { width: 90px; }

.k-settings-card__number-input { text-align: right; }

/* web-24 24g: a number box with its unit beside it, in one line (mock .num, M:569 — inline-flex, centred,
   8 px apart). The mock gives the unit no style; its rule exists so the class has one (the style audit). */
.k-settings-card__num { display: inline-flex; align-items: center; gap: 8px; }

.k-settings-card__unit { flex: none; }

.k-settings-card__field-error { margin: 0; font-size: 13px; color: var(--k-danger); }

.k-settings-card__message { margin: 8px 0 0; }

.k-settings-card__message--error { color: var(--k-danger); }

/* The logo card (mock .logo / .logo .pv / .logo .pv b, M:555–558, M:596): a 140×90 frame showing the
   logo the way the top bar does, beside the company name, and „Odaberi sliku…" — the <label> of the
   file input, drawn as a secondary button (its look is in the secondary list below). The input is
   VISUALLY hidden, not display:none: it stays in the tab order, its label opens the dialog, and its
   keyboard focus is drawn on the label right after it. */
.k-settings-card__logo { display: flex; gap: 16px; align-items: center; }

.k-settings-card__frame { width: 140px; height: 90px; padding: 0 8px; border: 1px solid var(--k-border-strong); border-radius: 8px; background: var(--k-bg); display: flex; align-items: center; justify-content: center; gap: 8px; overflow: hidden; text-align: center; }

/* The name stops at two lines with an ellipsis (REV-D2 N2): a long one used to wrap past the 90 px
   frame, which cut its first and last words off with no mark. One long word breaks anywhere (with no
   hyphen) instead of being cut sideways. The name, a flex child of the frame, can shrink below its
   content because overflow: hidden gives a flex item an automatic minimum of 0 (Flexbox §4.5). The
   whole name is the element's title. A one-line name is not clamped. */
.k-settings-card__frame-name { color: var(--k-accent); font-size: 13px; text-transform: uppercase; letter-spacing: .5px; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; overflow-wrap: anywhere; }

.k-settings-card__file { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

.k-settings-card__choose { display: inline-flex; align-items: center; cursor: pointer; }

.k-settings-card__file:focus-visible + .k-settings-card__choose { outline: var(--k-focus-ring); outline-offset: var(--k-focus-ring-offset); }

.k-company-data__field { display: flex; flex-direction: column; gap: 4px; }

.k-company-data__label,
.k-settings-list__label { color: var(--k-text-muted); font-size: 13px; }

/* B14b / W-06 (vlasnik 5.9.): zvjezdica obaveznog polja uz oznaku novog unosa zone / kategorije.
   Same shape as `.k-shift-editor__required`. */
.k-settings-list__required { font-style: normal; color: var(--k-danger); margin-left: 3px; }

.k-company-data__field-error,
.k-company-data__message--error,
.k-company-logo__message--error,
.k-settings-list__message--error,
.k-settings-list__error,
.k-layout-reset__message--error { color: var(--k-danger); }

.k-company-data__message,
.k-company-logo__message,
.k-settings-list__message,
.k-layout-reset__message { margin: 8px 0 0; }

.k-company-data__field-error { margin: 0; font-size: 13px; }

.k-company-data__save,
.k-company-logo__save,
.k-settings-card__save,
.k-settings-list__add,
.k-layout-reset__start,
.k-layout-reset__yes {
    padding: 6px 14px;
    border: 1px solid var(--k-accent);
    border-radius: 4px;
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    font: inherit;
}

/* K3c rez B: web-24-postavke.html:563 .lst .r .a - izdvojeno iz pravila iznad; isti oblik, font: inherit
   prvi, pa samo tipografija. */
.k-settings-list__confirm-yes {
    padding: 6px 14px;
    border: 1px solid var(--k-danger);
    border-radius: 4px;
    background: transparent;
    color: var(--k-danger);
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}

/* B20 / W-04 (web-decisions :78; knjiga r.2662 P122 2b — the same rule for an inline action): the inline
   confirmations' ACTION buttons — the list row's delete (above, its own rule) and the layout reset's „yes"
   (here) — are a red OUTLINE with red text, never filled, and sit LAST in the DOM. LOCAL rules, colour only:
   K3c N4 forbids k-btn / k-btn--danger-outline on these markers (B selector / A class, #3436), so
   k-btn--danger-outline's colours are repeated here; the shape stays the grouped rule's above, which is not
   split (K3c P-pop) — the layout reset's colour wins because it comes LATER at the same (0,1,0). Like
   k-btn--danger-outline: the base also covers a disabled button under the mouse, and the hover/active wash
   stays a WASH (≤ .15), enabled only — (0,3,0) over the global `button:hover` (0,1,1). */
.k-settings-list__confirm-yes:disabled:hover,
.k-layout-reset__yes,
.k-layout-reset__yes:disabled:hover {
    background: transparent;
    border-color: var(--k-danger);
    color: var(--k-danger);
}
.k-settings-list__confirm-yes:hover:not(:disabled),
.k-settings-list__confirm-yes:active:not(:disabled),
.k-layout-reset__yes:hover:not(:disabled),
.k-layout-reset__yes:active:not(:disabled) {
    background: rgba(var(--k-danger-rgb), 0.1);
    border-color: var(--k-danger);
    color: var(--k-danger);
}

.k-settings-card__cancel,
.k-settings-card__choose,
.k-layout-reset__no {
    padding: 6px 12px;
    border: 1px solid var(--k-border);
    border-radius: 4px;
    background: transparent;
    color: inherit;
    font: inherit;
}

/* K3c rez B: web-24-postavke.html:563 .lst .r .a - izdvojeno iz pravila iznad; isti oblik, font: inherit
   prvi, pa samo tipografija. */
.k-settings-list__save,
.k-settings-list__delete,
.k-settings-list__confirm-no {
    padding: 6px 12px;
    border: 1px solid var(--k-border);
    border-radius: 4px;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}

.k-company-logo__preview {
    display: block;
    max-width: 64px;
    max-height: 40px;
}

.k-company-logo__empty,
.k-settings-list__empty,
.k-settings-list__loading,
.k-company-data__loading,
.k-layout-reset__lead,
.k-settings-list__note { color: var(--k-text-muted); }

.k-company-logo__field { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

.k-settings-list__note { margin: 4px 0 0; font-size: 13px; }

.k-settings-list__rows { margin: 0 0 12px; padding: 0; list-style: none; }

/* K3a′ N2: own 14px (mock `.lst .r` web-24:560), not the 15px body (D3). */
.k-settings-list__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 4px 0;
    font-size: 14px;
}

.k-settings-list__row .k-settings-list__message { margin: 0; flex-basis: 100%; }

.k-settings-list__confirm { display: inline-flex; align-items: center; gap: 8px; }

.k-settings-list__new { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

.k-settings-list__new .k-settings-list__message { margin: 0; flex-basis: 100%; }

.k-layout-reset__confirm { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

.k-layout-reset__lead { margin: 0 0 8px; max-width: 640px; }

/* ── §11.8's alarm configuration — W7 Task 16 ────────────────────────────────────────────────────
   One row per catalogue entry, each with three settings, each setting carrying WHAT APPLIES and WHERE
   IT COMES FROM. The whole problem this block solves is that last part: a value and its source badge
   have to read as one statement, or an operator scanning the list cannot tell an override from an
   inheritance at a glance — which is exactly what scen 240 is about. Since web-19 (W-53) the
   alarms are one table — see the table block below.
   The shared editor's own BEM block (.k-alarm-config) is used by §11.3.6 too, for the reason that
   component exists: one screen furniture, two hosts. */
/* web-26 — the level row (mock web-26 k1 :630 .period): the list, the filter chip and the legend. */
.k-company-alarms__toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; margin-top: 16px; }

.k-company-alarms__scope { display: flex; flex-wrap: nowrap; align-items: center; gap: 10px; }

/* web-26 W-60 — the list's entry: the name left, its customized count right (mock web-26 k3 :706). */
.k-company-alarms__option { display: flex; justify-content: space-between; gap: 12px; width: 100%; }

.k-company-alarms__option-name { color: var(--k-text); }

.k-company-alarms__option-count { font-size: 12px; color: var(--k-text-muted); }

.k-company-alarms__option-count--some { color: var(--k-accent-soft); }

/* W2b (REV-D3 114723): text on DevExpress's selection fill (= --k-accent) takes the on-accent token, as .k-seg__item--on; 7.96:1. */
.k-company-alarms__option--selected .k-company-alarms__option-name, .k-company-alarms__option--selected .k-company-alarms__option-count { color: var(--k-btn-text-on-accent); }

.k-company-alarms__label { color: var(--k-text-muted); font-size: 13px; }

.k-company-alarms__scope .k-company-alarms__label { font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .5px; white-space: nowrap; }

.k-company-alarms__scope .k-company-alarms__list { width: 330px; flex: 0 0 330px; }
/* web-26 — the page's subtitle beside the heading (mock web-26 k1 :629 .muted 13 px). */
.k-company-alarms__subtitle { color: var(--k-text-muted); font-size: 13px; }

/* web-26 — the legend (mock web-26 k1 :630 .legend2; mock web-19 CSS r. 460–461). */
.k-company-alarms__legend { display: flex; align-items: center; gap: 16px; margin-left: auto; font-size: 12px; color: var(--k-text-muted); }

.k-company-alarms__legend-item { display: inline-flex; align-items: center; }

/* The toolbar's search box (mock web-26 k1 :630 `.search`, right of the legend): `.k-grid .k-grid__search` does not
   reach it (the row is not inside a .k-grid), so it gets the grids' width and floor here, as the map-grid's head
   does. Its focus ring is named next to the grid's own, in the Task 9 block. */
.k-company-alarms__toolbar .k-grid__search { width: 280px; min-width: 220px; }

.k-company-alarms__swatch { display: inline-block; width: 12px; height: 12px; border-radius: 3px; margin-right: 5px; }

/* mock: rgba(--primary-rgb, .5) and #3a4062; the second is a raw hex, so the nearest token stands in
   (--k-border-strong #363C68) — named deviation 2 (as web-19b). */
.k-company-alarms__swatch--here { background: rgba(var(--k-accent-rgb), 0.5); }

.k-company-alarms__swatch--inherited { background: var(--k-border-strong); }

/* web-26 D134 — the question before another item replaces the unsaved rows of the item on screen. Final round
   m-1 (ARH-C 053145, the cure of web-19b Z1 M-3): a row of its own in the toolbar (flex-basis 100%): the list
   never moves and the question never squeezes in beside it; the chip and the legend go to the row below (the
   legend keeps its right edge). P122 (2b), owner 11.10.: „Odbaci promjene" carries W-04's colour modifier
   k-btn--danger-outline (no k-btn base, so the pair keeps one size); the shape stays this rule's — the modifier wins
   on colour only because it comes LATER at the same (0,1,0). */
.k-company-alarms__confirm { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; flex-basis: 100%; }

.k-company-alarms__confirm-text { color: var(--k-text); font-size: 13px; }

.k-company-alarms__confirm-yes,
.k-company-alarms__confirm-no {
    display: inline-flex;
    align-items: center;
    padding: 4px 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    background: transparent;
    color: var(--k-text);
    font: inherit;
    cursor: pointer;
}

.k-company-alarms__confirm-yes:focus-visible,
.k-company-alarms__confirm-no:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

.k-company-alarms__error,
.k-alarm-config__error { margin: 0; color: var(--k-danger); }

.k-alarm-config { margin-top: 16px; }

/* web-19 — THE MOCK'S TABLE (web-19 table.g, D1–D16; web-26 k1 the same). One row per alarm,
   the column headers are the captions, and a row has two states: READ (the values) and EDIT (the
   controls). Both halves of a cell are rendered; the row's state class shows one of them. Rows set
   at this level carry the accent bar and a light wash (D14), inherited rows are dimmed, the row being
   edited carries the stronger wash. */
.k-alarm-config__table { width: 100%; min-width: 935px; border-collapse: collapse; font-size: 13px; table-layout: fixed; }

/* The table's scroller (the editor's one wrapper around the <table>, §11.8 and §11.3.6 alike): below the table's
   min-width the table slides sideways inside it instead of squeezing its columns into each other or widening the
   page. min-width 935 px is the narrowest table in which every column holds its widest content — measured in a
   browser over the real markup (levels 2 and 4, read and edit rows): the tolerance column's number box needs
   101.3 px and gets 10.84 %, 101.3 / 0.1084 = 934.5 px; the others need less (action 94 / 0.1228 = 765.5,
   enabled 68.5 / 0.0939 = 729.5, source 90 / 0.1517 = 593.3, e-mail 117.8 / 0.2616 = 450.3, name 89.1 / 0.2616 =
   340.6). */
.k-alarm-config__scroll { overflow-x: auto; }

/* Stable column widths (the editor's <colgroup>): with the fixed layout above the header keeps them whatever the
   rows are, a search with no hit included. PROPORTIONAL to the mock (web-26 k1 :634, web-19 :486 `th
   style="width:…"`): the mock's px over the table's 1384 px at a 1440 px window, so 1440 draws exactly the mock —
   130 / 1384 = 9.39 %, 150 / 1384 = 10.84 %, 210 / 1384 = 15.17 %, 170 / 1384 = 12.28 % (47.69 % together); the
   name and the addresses, which the mock leaves open, share the other 52.31 %. */
.k-alarm-config__col--enabled { width: 9.39%; }

.k-alarm-config__col--tolerance { width: 10.84%; }

.k-alarm-config__col--source { width: 15.17%; }

.k-alarm-config__col--action { width: 12.28%; }

/* NARROW WINDOWS (below 991 px the table's scroller is narrower than the table's 935 px): the four columns of fixed
   content take their own content minimum instead of their share — tolerance 102, action 94, source 90, enabled 69 px,
   measured in a browser over the real markup (levels 2 and 4, read and edit rows) — and the name and the addresses
   share the rest, so the table fits its scroller down to 591 px (355 + 2 × 117.8, the widest address) and does not
   slide at all at 900 px. Why it must not slide there: a browser moving the focus with Tab scrolls a focused control
   into view only when NONE of it is visible — measured: a „Vrati na naslijeđeno" 13 px inside the scroller's edge
   stayed clipped by 82 px, and the same button wholly outside was scrolled fully in. */
@media (max-width: 990px) {
    .k-alarm-config__table { min-width: 591px; }

    .k-alarm-config__col--enabled { width: 69px; }

    .k-alarm-config__col--tolerance { width: 102px; }

    .k-alarm-config__col--source { width: 90px; }

    .k-alarm-config__col--action { width: 94px; }
}

.k-alarm-config__th {
    padding: 8px 10px;
    border-bottom: 1px solid var(--k-border-strong);
    color: var(--k-text-label);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    text-align: left;
    text-transform: uppercase;
    /* A header WRAPS within its column (the widths are fixed now): one that stayed on one line ran into its
       neighbour's caption at narrow widths. */
    overflow-wrap: break-word;
}

.k-alarm-config__cell {
    padding: 8px 10px;
    border-bottom: 1px solid var(--k-border);
    font-weight: 400;              /* the name cell is a row header (<th scope="row">), drawn as a cell */
    text-align: left;
    vertical-align: middle;
}

.k-alarm-config__row { color: var(--k-text); }

.k-alarm-config__row--inherited .k-alarm-config__cell { color: var(--k-text-muted); }

.k-alarm-config__row--inherited .k-alarm-config__cell:first-child { color: var(--k-text-label); }

.k-alarm-config__row--here .k-alarm-config__cell { background: rgba(var(--k-accent-rgb), 0.05); }

.k-alarm-config__row--here .k-alarm-config__cell:first-child { box-shadow: inset 3px 0 0 var(--k-accent); }

.k-alarm-config__row--edit .k-alarm-config__cell { background: rgba(var(--k-accent-rgb), 0.10); }

.k-alarm-config__row:not(.k-alarm-config__row--edit) .k-alarm-config__edit,
.k-alarm-config__row--edit .k-alarm-config__read { display: none; }

.k-alarm-config__read,
.k-alarm-config__edit,
.k-alarm-config__toggle { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; }

.k-alarm-config__open {
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.k-alarm-config__open:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

.k-alarm-config__num { display: inline-block; width: 22px; color: var(--k-text-muted); }

.k-alarm-config__unit,
.k-alarm-config__inherited { color: var(--k-text-muted); }   /* what applies, beside an empty control */

/* #4714 — the separator hint: its own line under the address box (the edit half wraps), muted like
   .k-incident-mail__note. */
.k-alarm-config__hint { display: block; flex-basis: 100%; margin-top: 4px; font-size: 12px; color: var(--k-text-muted); }

/* The control labels stay for assistive technology; the column header is the visible caption. */
.k-alarm-config__label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

.k-alarm-config__effective { display: inline-flex; align-items: baseline; gap: 6px; }

.k-alarm-config__effective--inactive { color: var(--k-text-muted); font-size: 13px; }

/* The row's one source (mock .lvl): a quiet outlined label, the accent one when set here. */
.k-alarm-config__source {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    color: var(--k-text-muted);
    font-size: 11px;
    /* May wrap: the column's width is a share of the table now, and the words are the only thing that would
       hold it wider. */
}

.k-alarm-config__row--here .k-alarm-config__source,
.k-alarm-config__row--edit .k-alarm-config__source {
    border-color: var(--k-accent);
    background: rgba(var(--k-accent-rgb), 0.10);
    color: var(--k-accent-soft);
}

/* D13 „Vrati na naslijeđeno" (mock .rst): a text action, not a boxed button. */
.k-alarm-config__clear {
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--k-accent-soft);
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: var(--k-label-tracking);
    text-transform: uppercase;
    text-align: left;              /* may wrap, as the source label beside it: left-aligned like the column */
    cursor: pointer;
}

.k-alarm-config__clear[disabled] { opacity: 0.5; cursor: default; }

.k-alarm-config__clear:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* D16 — the footer: the count of rows drawn and the level's sentence. */
.k-alarm-config__footer {
    margin: 0;
    padding: 8px 10px;
    color: var(--k-text-muted);
    font-size: 12px;
}

.k-alarm-config__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

.k-alarm-config__actions .k-alarm-config__message { margin: 0; flex-basis: 100%; }

.k-alarm-config__message--error { color: var(--k-danger); }

/* web-19 O2 — THE ONE SAVE BAR of an alarm screen (§11.8 and §11.3.6): the count and the change list
   on the left, "Odustani" and "Spremi" on the right (mock web-19 k1 .savebar, the W-45 pattern). Save
   is the primary gesture, Cancel the quiet one. The bar is ALWAYS drawn and keeps its place in the
   layout, as the mock draws it: with nothing unsaved both buttons are disabled and the summary is
   empty (its live region stays in the DOM, so the first change is announced). */
.k-alarm-savebar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 14px;
}

/* Novi-tekst B2: the count and, beside it, the change description in brackets sit on the left; the
   first button takes the free space, so the two texts stay together. */
.k-alarm-savebar__summary { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 6px; }

.k-alarm-savebar__count,
.k-alarm-savebar__changes { color: var(--k-text-muted); font-size: 13px; }

.k-alarm-savebar__cancel { margin-left: auto; }

.k-alarm-savebar__save,
.k-alarm-savebar__cancel {
    display: inline-flex;
    align-items: center;
    padding: 6px 14px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    cursor: pointer;
}

.k-alarm-savebar__save { background: var(--k-accent); color: var(--k-btn-text-on-accent); }

.k-alarm-savebar__cancel { background: transparent; color: var(--k-text); }

.k-alarm-savebar__save[disabled],
.k-alarm-savebar__cancel[disabled] { opacity: 0.5; cursor: default; }

.k-alarm-savebar__save:focus-visible,
.k-alarm-savebar__cancel:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* The REPORT of stored tolerances above the ceiling (owner's ruling 11, 20.9.2026) — one line above
   the list, drawn only while such a value exists.

   IT BORROWS --k-warning, NOT --k-danger, and the distinction is the point: nothing is broken and
   nothing was refused. A value that predates the rule is being REPORTED, exactly as the ruling says
   ("ne mijenjaju se same nego se prijavljuju"). --k-danger is the REFUSAL's colour
   (.k-alarm-config__message--error, a different line on a different occasion), and the two must not
   look alike or the operator learns nothing from the colour.

   THE COUNT IS A CHIP because the sentence carries no number — Croatian has three plural forms and
   .resx knows none — so the number must read as a number rather than as part of the copy. */
.k-alarm-config__ceiling {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin: 0 0 12px;
    padding: 8px 12px;
    border: 1px solid var(--k-warning);
    border-radius: var(--k-radius-sm);
    color: var(--k-warning);
}

.k-alarm-config__ceiling-chip {
    flex: none;
    min-width: 20px;
    padding: 1px 7px;
    border-radius: var(--k-radius-sm);
    background: var(--k-warning);
    color: var(--k-bg);
    font-weight: 600;
    text-align: center;
}

/* ── §11.3.6's location alarm tab — W7 Task 17 ───────────────────────────────────────────────────
   TWO of the editor above mounted on one page, plus §9's incident addresses. Since web-19b only ONE
   level is on screen: the toolbar above the sections chooses it (the level chips, K1b) and the other
   level's section carries `hidden`, so what tells the levels apart is the chosen chip and each row's
   source badge rather than a heading.
   Only one section is on screen, so it draws no rule above itself any more (web-19b C4).
   The editors themselves bring their own block (.k-alarm-config), which is the point of sharing
   them: nothing about how an alarm row looks is decided twice. */
.k-location-alarms { display: flex; flex-direction: column; gap: 8px; }

.k-location-alarms__note,
.k-location-alarms__empty { margin: 0; color: var(--k-text-muted); font-size: 13px; }

.k-location-alarms__error { margin: 0; color: var(--k-danger); }

/* web-19b C1 (mock web-19 k1 :483): the row above the table that chooses the ONE level on screen -
   the level chips (.k-chips, K1b) for up to four working positions, the list
   (.k-location-alarms__scope) for more than four, and the „Samo prilagođeni" filter chip (C3, .k-chip)
   after them. Layout only; the chips and the list bring their own look. */
.k-location-alarms__toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

.k-location-alarms__level { padding-top: 8px; }

/* web-19b: the level not chosen is `hidden`. Stated here rather than left to the user-agent [hidden] rule
   (the .k-conn-strip[hidden] lesson): a `display` given to the section later would otherwise silently put
   both levels back on screen, and no render test can see CSS. */
.k-location-alarms__level[hidden] { display: none; }

/* No margin of its own: the toolbar's gap spaces it, so the list stands on the filter chip's line. */
.k-location-alarms__scope {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.k-location-alarms__label { color: var(--k-text-muted); font-size: 13px; }

/* web-19b C4 — the legend at the end of the level row (mock web-19 k1 :483, .legend2 CSS r. 460–461):
   „postavljeno ovdje" and „naslijeđeno", each after its swatch. The swatches are hidden from assistive
   technology — the words carry the meaning, not the colour. The level row itself (.k-location-alarms__toolbar,
   T2) and the list's entries (.k-location-alarms__option*, T4) keep their rules above. */
.k-location-alarms__legend {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-left: auto;
    font-size: 12px;
    color: var(--k-text-muted);
}

.k-location-alarms__legend-item { display: inline-flex; align-items: center; }

.k-location-alarms__swatch {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 3px;
    margin-right: 5px;
}

/* mock: rgba(--primary-rgb, .5) and #3a4062; the second is a raw hex, so the nearest token stands in
   (--k-border-strong #363C68) — web-19b C4's deviation from the mock: a token instead of its raw hex. */
.k-location-alarms__swatch--here { background: rgba(var(--k-accent-rgb), 0.5); }

.k-location-alarms__swatch--inherited { background: var(--k-border-strong); }

/* D153 — the question before another working position replaces level 4's unsaved rows.
   Z1 M-3: a row of its own in the toolbar (flex-basis 100%), so nothing moves sideways under the pointer when it appears. */
.k-location-alarms__confirm { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; flex-basis: 100%; }

.k-location-alarms__confirm-text { color: var(--k-text); font-size: 13px; }

.k-location-alarms__confirm-yes,
.k-location-alarms__confirm-no {
    display: inline-flex;
    align-items: center;
    padding: 4px 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    background: transparent;
    color: var(--k-text);
    font: inherit;
    cursor: pointer;
}

.k-location-alarms__confirm-yes:focus-visible,
.k-location-alarms__confirm-no:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}

/* B20 / W-04 (web-decisions :78; knjiga r.2662 P122 2b): „Odbaci promjene" is a red OUTLINE with red text, never
   filled, LAST in the DOM. LOCAL rule, colour only (A class, K3c N4: no k-btn*); the shape stays the grouped rule's
   above, not split (K3c P-pop) — the colour wins because it comes LATER at the same (0,1,0). The hover/active wash
   stays a WASH (≤ .15) — (0,3,0) over the global `button:hover` (0,1,1). The button is never disabled. */
.k-location-alarms__confirm-yes {
    background: transparent;
    border-color: var(--k-danger);
    color: var(--k-danger);
}
.k-location-alarms__confirm-yes:hover:not(:disabled),
.k-location-alarms__confirm-yes:active:not(:disabled) {
    background: rgba(var(--k-danger-rgb), 0.1);
    border-color: var(--k-danger);
    color: var(--k-danger);
}

/* B5 — the number beside a location tab's title (mock web-19 :97 `.tabs span i`). */
.k-location-config__tab-count { margin-left: 6px; font-style: normal; font-weight: 400; color: var(--k-text-muted); }

/* web-19b C2 (mock web-26 k3 :706): one entry of the level list — the name on the left, its
   customized count to the right in the muted tone; a count above zero reads stronger, „—"
   (zero) and an unknown count stay muted. */
.k-location-alarms__option {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
}

.k-location-alarms__option-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.k-location-alarms__option-count {
    flex: none;
    color: var(--k-text-muted);
    font-size: 12px;
    font-variant-numeric: tabular-nums;
}

.k-location-alarms__option-count--some { color: var(--k-text-label); }

/* The incident addresses. One row per destination — the shared list, or one per category — and the
   CONFIRMATION strip is deliberately loud beside its own row rather than in a dialog: ruling P3's
   switch deletes addresses somebody is relying on, and the row it will act on is the one the
   operator has to see while answering. */
.k-incident-mail { padding-top: 16px; border-top: 2px solid var(--k-border); }

.k-incident-mail__heading { margin: 0 0 8px; font-size: 16px; }

/* web-19c: the subtitle rides inside the heading (mock r. 509: 12px muted); the note closes the drawn
   card, below whatever rows it shows (mock r. 559). The mock's --muted is --k-text-muted here. */
.k-incident-mail__subtitle { font-size: 12px; color: var(--k-text-muted); font-weight: 400; margin-left: 6px; }

.k-incident-mail__note { font-size: 12px; color: var(--k-text-muted); margin-top: 8px; }

/* #4714 — the separator hint: its own line under the shared box (the row wraps), or once above the
   per-category list; the note's tokens. */
.k-incident-mail__hint { display: block; flex-basis: 100%; margin-top: 4px; font-size: 12px; color: var(--k-text-muted); }

.k-incident-mail__loading,
.k-incident-mail__empty { margin: 0; color: var(--k-text-muted); font-size: 13px; }

.k-incident-mail__error { margin: 0; color: var(--k-danger); }

.k-incident-mail__mode { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

.k-incident-mail__label { min-width: 160px; color: var(--k-text-muted); font-size: 13px; }

/* web-19c — the mode is the joined segment (K1c). PLACEMENT ONLY (U1): it keeps its own width in the
   wrapping row; the items' layout stays .k-seg's. */
.k-incident-mail__seg { flex: none; }

.k-incident-mail__stored { color: var(--k-text-muted); font-size: 13px; flex-basis: 100%; }

.k-incident-mail__rows { margin: 0; padding: 0; list-style: none; }

.k-incident-mail__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 12px 0;
    border-top: 1px solid var(--k-border);
}

.k-incident-mail__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

.k-incident-mail__confirm {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    flex-basis: 100%;
    color: var(--k-danger);
}

/* B20 / W-04 (web-decisions :78; knjiga r.2662 P122 2b): ruling P3's „yes" — the switch that deletes the other
   shape's addresses — is a red OUTLINE with red text, never filled, LAST in the DOM. Until B20 it had no rule and
   wore the global `button` accent fill. LOCAL rule, colour only (no k-btn*, like the other inline confirmations);
   the base also covers a disabled button under the mouse, and the hover/active wash stays a WASH (≤ .15), enabled
   only — (0,3,0) over the global `button:hover` (0,1,1). */
.k-incident-mail__confirm-yes,
.k-incident-mail__confirm-yes:disabled:hover {
    background: transparent;
    border-color: var(--k-danger);
    color: var(--k-danger);
}
.k-incident-mail__confirm-yes:hover:not(:disabled),
.k-incident-mail__confirm-yes:active:not(:disabled) {
    background: rgba(var(--k-danger-rgb), 0.1);
    border-color: var(--k-danger);
    color: var(--k-danger);
}

.k-incident-mail__actions .k-incident-mail__message { margin: 0; flex-basis: 100%; }

.k-incident-mail__message--error { color: var(--k-danger); }

/* ── §11.7's QR generation and print sheets — W7 Task 18 ─────────────────────────────────────────
   Two problems in one block: the SCREEN half (a count, a reprint list, a preview) and THE REPO'S
   FIRST PRINT STYLESHEET.

   THE PREVIEW IS THE SHEET. There is exactly one set of sticker markup, styled for two media, which
   is what makes scen 219 — "the screen version and the print version decode to the same code" — true
   by construction instead of by two renderings somebody has to keep in step. Everything below
   .k-qr-sheets is therefore already laid out in MILLIMETRES on screen: what an operator sees is the
   paper, on a white ground, in the dark theme's middle.

   WHY THE STICKER IS ~40 mm AND NOT THE ~60 mm SCEN 218 ASKS FOR. Six rows of 60 mm is 360 mm, and
   an A4 page is 297 mm tall — the 3 × 6 layout scen 205-207 requires and a 60 mm SQUARE sticker
   cannot both exist on A4. The layout wins: it is structural, and three scenarios turn on it.
   That fixes the cell at 63 mm × 46 mm, and the sticker's own CONTENT — the 40 mm symbol plus its
   two lines of text — at roughly 40 mm × 46 mm, whose diagonal is about 61 mm. THAT is the reading
   of "approximately 6 cm" that survives; the CELL's diagonal is 78 mm and means nothing physical,
   since the gutter around a sticker is not part of it. The symbol is 29 modules across (QR version 3
   at level H), so a 40 mm image is a 1.38 mm module: comfortably above the ~0.5 mm a phone camera
   needs at arm's length, and below the ~2 mm scen 218 hoped for. Only a human print preview can
   settle the rest. */
.k-company-qr__panel { margin-top: 24px; }

.k-company-qr__heading { margin: 0 0 4px; font-size: 16px; }

.k-company-qr__lead,
.k-company-qr__note { margin: 0 0 8px; max-width: 640px; color: var(--k-text-muted); font-size: 13px; }

.k-company-qr__error { margin: 0; color: var(--k-danger); }

.k-company-qr__controls { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

.k-company-qr__controls .k-company-qr__error { flex-basis: 100%; }

.k-company-qr__label { min-width: 120px; color: var(--k-text-muted); font-size: 13px; }

.k-company-qr__rows { margin: 0 0 12px; padding: 0; list-style: none; max-height: 320px; overflow: auto; }

.k-company-qr__row { display: flex; align-items: center; gap: 8px; padding: 4px 0; }

.k-company-qr__row-label { display: inline-flex; align-items: baseline; gap: 8px; }

.k-company-qr__row-kind { color: var(--k-text-muted); font-size: 12px; min-width: 110px; }

/* THE SHEET AND ITS STICKERS. Black on white in BOTH media: this is paper being previewed, and a
   QR drawn in the theme's colours would be a preview of something the printer will never produce. */
.k-qr-sheets { margin-top: 16px; }

.k-qr-sheet {
    display: grid;
    grid-template-columns: repeat(3, 63mm);
    grid-template-rows: repeat(6, 46mm);
    justify-content: center;
    box-sizing: border-box;
    width: 190mm;
    background: #fff;
    color: #000;
    margin: 0 0 16px;
    padding: 2mm 0;
}

.k-qr-sticker {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1mm;
    box-sizing: border-box;
    padding: 1mm;
    overflow: hidden;
    text-align: center;
    /* A sticker is cut out as one piece; a symbol split across a page boundary is waste paper. */
    break-inside: avoid;
    page-break-inside: avoid;
}

/* PIXELATED, deliberately. The PNG is 10 device pixels per module and the print scales it up; a
   smoothing filter would blur the module edges, which is the one thing a QR decoder cannot afford. */
.k-qr-sticker__image {
    display: block;
    width: 40mm;
    height: 40mm;
    image-rendering: pixelated;
}

.k-qr-sticker__caption {
    max-width: 100%;
    font-size: 7pt;
    line-height: 1.1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The 32 characters in readable form, BESIDE the symbol and never inside it — the QR's own content
   stays bare (scen 210). Monospace so a hand-typed fallback can be checked character by character. */
.k-qr-sticker__code {
    font-family: var(--k-font-mono, ui-monospace, "Cascadia Mono", Consolas, monospace);
    font-size: 5.5pt;
    letter-spacing: 0.02em;
}

@media print {
    /* A4 portrait with a narrow, symmetric margin: 190 mm of content across 210 mm of paper, and
       6 × 46 mm = 276 mm down 297 mm. */
    @page { size: A4 portrait; margin: 10mm; }

    /* WHITE, LOUDLY. The theme is dark-only, and every browser drops background colours from print
       output by default — which would print white text on nothing. */
    html, body {
        background: #fff !important;
        color: #000 !important;
    }

    /* THE APPLICATION SHELL AND THE SCREEN FURNITURE GO AWAY. Named by what to REMOVE rather than by
       what to keep: a rule that whitelisted the sheets would start printing the topbar the day
       somebody renamed a shell class, and printing chrome is a failure nobody notices until it is on
       paper. */
    .k-topbar,
    .k-omnibox,
    .k-company__header,
    .k-company-qr__screen { display: none !important; }

    /* THE SHELL'S OWN GUTTERS GO WITH IT. .k-page centres a max-width column and .k-company adds a
       16 px + page-gutter pad and a flex gap — all of it correct on screen and all of it a silent
       offset on paper, where @page has already reserved the only margin there is. Without this the
       190 mm sheet starts one gutter in and the third column runs off the right edge. */
    .k-page {
        max-width: none;
        min-height: 0;
        margin: 0;
    }

    .k-company {
        padding: 0;
        gap: 0;
    }

    .k-qr-sheets { margin: 0; }

    /* ONE SHEET PER PAGE (scen 206): the pagination already decided which codes are on which sheet,
       and this is what makes the browser agree. `break-after` is the modern spelling and
       `page-break-after` the one older engines still read; the LAST sheet takes neither, or every
       print ends with a blank page. */
    .k-qr-sheet {
        margin: 0;
        padding: 0;
        break-after: page;
        page-break-after: always;
    }

    .k-qr-sheet:last-child {
        break-after: auto;
        page-break-after: auto;
    }
}

/* ══ INS-1 (§8.2, W-66): THE PUBLIC INSTALL PAGE ═══════════════════════════════════════════════
   The one page a stranger sees, on a phone, usually on mobile data. Mock:
   docs/design/mocks/web-29-instalacija.html (frame 1) — dark theme and Saira like the app itself,
   so the worker recognises „this is Kerber" before reading a word.

   PHONE FIRST AND NO GRID: the whole page is one column that simply grows, because the mock's
   frame IS a phone. The desktop case (mock caption: „isti sadržaj centriran") is the same column
   with a max width — there is no second layout to keep in step. */
.k-install {
    display: flex;
    flex-direction: column;
    gap: 9px;                   /* web-29 A5, M:90 */
    max-width: 30rem;
    margin: 0 auto;
    padding: 14px 18px 2rem;    /* web-29 A5, M:90 */
    color: var(--k-text);
}

/* web-29 A1/A2, M:91-93: vlasnikov logo 34 px uz riječ, verzal. */
.k-install__brand {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 20px;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--k-accent);
}

.k-install__logo { display: block; }

/* web-29 A3, M:94; verzal već iz globalnog h1, ali bez njegova `--k-label-tracking` (:151) —
   mockov `.ht` razmak slova ne nosi. */
.k-install__title { margin: 0; font-size: 28px; font-weight: 700; line-height: 1.05; letter-spacing: normal; color: var(--k-text); }
.k-install__lead { margin: 0; color: var(--k-text-label); font-size: 14px; line-height: 1.3; }   /* web-29 A4, M:95 */

/* THE BUTTON IS A LINK, and it is the biggest thing on the page: it is the only action, and a
   worker in a yard taps it with a glove on. min-height keeps it above the 44 px touch target the
   rest of the app uses. */
.k-install__download {
    display: flex;              /* web-29 B2, M:96: ikona + verzal u jednom retku */
    align-items: center;
    justify-content: center;
    gap: 10px;
    min-height: 60px;           /* web-29 B2, M:96 */
    padding: .875rem 1rem;
    border-radius: 12px;        /* web-29 B2, M:96 */
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    font-weight: 700;           /* web-29 B2, M:96 */
    font-size: 19px;            /* web-29 B2, M:96 */
    text-transform: uppercase;  /* web-29 B2, M:96 */
    letter-spacing: .04em;      /* web-29 B2, M:96 */
    text-align: center;
    text-decoration: none;
}

.k-install__download-icon { width: 26px; height: 26px; flex: none; }   /* web-29 B2, M:97 */

.k-install__download:hover { background: var(--k-accent-hover); }
.k-install__download:focus-visible { outline: var(--k-focus-ring); outline-offset: 2px; }

/* The measured row under the button: version, build date, size, minimum Android. It WRAPS instead
   of shrinking — four numbers on a 320 px screen are two lines, not four unreadable columns. */
.k-install__meta {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;    /* web-29 B5, M:98 */
    gap: .25rem 14px;           /* web-29 B5, M:98 */
    margin: 0;
    color: var(--k-text-label); /* web-29 B5, M:98 */
    font-size: 13px;            /* web-29 B5, M:98 */
}

.k-install__meta b { color: var(--k-text); }   /* web-29 B5, M:99 */

.k-install__hint,
.k-install__unavailable {
    margin: 0;
    color: var(--k-text-muted);
    font-size: .8125rem;
}

.k-install__hint { font-size: 12px; color: var(--k-text-label); }   /* web-29 B6, M:122 + M:142 */
.k-install__hint b { color: var(--k-accent-soft); }                /* web-29 B6, M:123 (--secondary) */

/* „Not published" is a state of the folder, not an error: it reads as a notice, not as a crash. */
.k-install__unavailable {
    padding: .75rem;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius, .5rem);
    color: var(--k-warning);
    font-size: .875rem;
}

/* THE FOUR STEPS CARRY THEIR OWN NUMBERS (list-style: none + counter) because the numbers are part
   of the instruction the mock prints in a circle, and a browser's default marker cannot be styled
   into one. The list stays an <ol>, so a screen reader still hears four ordered steps. */
.k-install__steps {
    display: flex;
    flex-direction: column;
    gap: 9px;                   /* web-29 C8: koraci su u mocku izravna djeca `.page { gap: 9px }` (M:90) */
    margin: .5rem 0 0;
    padding: 0;
    list-style: none;
    counter-reset: k-install-step;
}

.k-install__step {
    display: grid;
    grid-template-columns: 30px 1fr;           /* web-29 C8, M:100 */
    gap: .125rem 12px;                         /* web-29 C8, M:100 */
    padding: 7px 0;                            /* web-29 C8, M:100 */
    border-top: 1px solid var(--k-border);     /* web-29 C8, M:100 */
    counter-increment: k-install-step;
}

.k-install__step::before {
    content: counter(k-install-step);
    grid-row: 1 / span 2;
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 30px;                               /* web-29 C7, M:101 */
    height: 30px;
    border: 2px solid var(--k-accent);         /* web-29 C7, M:101: obrub, ne ispuna */
    border-radius: 50%;
    background: var(--k-surface);
    color: var(--k-accent);
    font-weight: 700;
    font-size: 15px;                           /* web-29 C7, M:101 */
}

.k-install__step > b { align-self: end; font-size: 16px; }                          /* web-29 C9, M:102 */
.k-install__step > span { color: var(--k-text-label); font-size: 12.5px; line-height: 1.3; } /* web-29 C9, M:104 */
.k-install__step > span b { color: var(--k-text); }                                 /* web-29 C9, M:103 */

/* QR KODOVI IMAJU SVOJU MJERU, i to je izmjereno (k0 krug 3 + e2e 35353037007): QrPng crta
   10 px po modulu, pa slika bez pravila pri prozoru od 380 px ide od 14 do 384 px — izvan
   stupca. Sirina ide u postotku s gornjom granicom, a `pixelated` cuva module ostrima kad se
   slika smanji (interpolacija bi im pojela rubove i otezala skeniranje). */
.k-install__qr img {
    display: block;
    width: 100%;
    max-width: 14rem;
    height: auto;
    image-rendering: pixelated;
}

/* web-29 M:151 „Na desktopu: isti sadržaj centriran + QR kod stranice" — izmjereno (DIZ-5 snimka
   1440): blok-slika je stajala LIJEVO u stupcu (x 528–724 u 528–912). Spremnik ostaje pune širine
   stupca (pa `width: 100%` slike i dalje znači stupac, kapa 14rem gore netaknuta), a slika i
   natpis se centriraju kao stavke stupca; `text-align` centrira natpis koji se prelomi. */
.k-install__qr {
    display: flex;
    flex-direction: column;
    align-items: center;
    max-width: 100%;
    text-align: center;
}

/* Dijalog uparivanja: kod uparivanja je VECI (skenira ga Kerberov skener), kod instalacije
   manji (skenira ga kamera telefona) — odluka vlasnika 11.9., mock web-22 okvir „2b". */
/* Klasa stoji na SAMOJ slici (DevicePairingOffer.razor:101), pa potomak `img` nikad nije
   pogadjao — izmjereno: QR uparivanja je ostajao 410 px (e2e 35355961146). */
.k-device-pairing__qr {
    display: block;
    width: 100%;
    max-width: 16rem;
    height: auto;
    image-rendering: pixelated;
}

.k-device-pairing__install-qr {
    display: block;
    width: 100%;
    max-width: 10rem;
    height: auto;
    image-rendering: pixelated;
}

/* #2180 — DVA KORAKA JEDAN UZ DRUGI, po okviru „2b" (web-22-uredjaji.html): korak 1 (instalacija)
   i korak 2 (uparivanje) su braca u jednoj mrezi, 1fr : 1.4fr kao u podlozi, jer je QR uparivanja
   veci. Sirinu prozora daje DxPopup Width u DevicePairingPanel.razor, ne ovo pravilo. */
.k-device-pairing__steps {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
    gap: 18px;
    align-items: stretch;
}

.k-device-pairing__step {
    padding: 16px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius);
    background: var(--k-bg);
}

/* #2180 — naslovi kartica dijaloga („1 · Instalirajte Kerber", „2 · Uparite telefon s tvrtkom",
   QR, PIN) su male verzal oznake kao mock web-22 r.504 (`.pair .box h6`), ARH-C 080054. Mockov
   `--label` (#B6B9D1) je nas `--k-text-label`. */
.k-device-pairing__method-title,
.k-device-pairing__step-title {
    margin: 0 0 10px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .5px;
    color: var(--k-text-label);
}

/* Unutar koraka 2 QR i PIN stoje jedan uz drugi, kao u podlozi (scen 185: oba odjednom). Stupac QR-a
   raste do kape koju vec nosi `.k-device-pairing__qr`, PIN dobiva ostatak — ali nikad manje od
   sirine svojih sest znamenki (min-content), jer PIN koji se prelomi ili prelije nije PIN. */
.k-device-pairing__methods {
    display: grid;
    grid-template-columns: minmax(0, 16rem) minmax(min-content, 1fr);
    gap: 16px;
    align-items: center;
}

/* Adresa instalacijske stranice RIJECIMA, za diktiranje (podloga: „kerber.example.hr/app", istaknuto),
   sada UNUTAR recenice koraka 1. #3666 (P58 v2, vlasnik 9.10.; (a) 9.10.): lomi se SAMO poslije „/"
   i poslije „." u hostu (i u IP adresi; tocka u putu nije lom) — tamo DevicePairingOffer.razor:72
   stavlja <wbr> — i nikad usred rijeci, pa ovdje nema ni `anywhere` ni `break-all`. Sirina prozora (760 px) i uski raspored ispod 800 px ostaju kakvi jesu. */
.k-device-pairing__install-url {
    margin: 0;
    color: var(--k-accent-soft);
    font-weight: 600;
    overflow-wrap: normal;
}

/* PIN u dvije skupine po tri („482 913"): razmak slova 8 px kao u podlozi, i NIKAD prelomljen na
   razmaku izmedu skupina — PIN u dva retka nije PIN (a stupac mu min-content uzima iz ovoga). */
.k-device-pairing__pin {
    margin: 10px 0 4px;
    color: var(--k-text);
    font-size: 34px;
    font-weight: 700;
    letter-spacing: 8px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* #2419 — crta roka nosi „Novi kod" (mock web-22 okvir „2b", :600: rok lijevo, „Novi kod" desno).
   Prelama se na uskom prozoru, pa gumb nikad ne izlazi iz dijaloga. web-22a: velicina i boja
   teksta iz podloge (.exp, :508). */
.k-device-pairing__expiry-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 16px;
    margin-top: 14px;
    color: var(--k-text-label);
    font-size: 13px;
}

.k-device-pairing__new-code {
    /* P172 (#3871): „Novi PIN za uparivanje" je predug za redak roka i prelama se; desno kao mock :600. */
    margin-left: auto;
    padding: 4px 12px;
    border: 1px solid var(--k-accent);
    border-radius: var(--k-radius-md);
    background: transparent;
    color: var(--k-accent-soft);
    font: inherit;
    /* K3c rez B: web-22-uredjaji.html:453 .rst */
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    cursor: pointer;
}

.k-device-pairing__new-code:disabled {
    opacity: .5;
    cursor: default;
}

/* #3878 (ARHITEKT 154014): globalni `button:hover` (0,1,1) pobjeđivao je ovu klasu (0,1,0), pa se gumb pod hoverom
   punio s --k-accent-hover. Mock web-22-uredjaji.html:453 .rst nema ni ispunu ni hover: hover ostaje kao mirovanje. */
.k-device-pairing__new-code:hover {
    background: transparent;
    border-color: var(--k-accent);
}

/* Novi kod nije stigao — stari i dalje vrijedi, pa je ovo upozorenje uz crtu roka, a ne greška
   koraka 2. */
.k-device-pairing__renew-error {
    margin: 4px 0 0;
    color: var(--k-danger);
}

/* #2419 — „Uređaj uparen: <naziv>" (W-56, W-66g): dobra vijest, stoji 3 s pa se prozor zatvori. */
.k-device-pairing__paired {
    margin: 0 0 12px;
    padding: 8px 12px;
    border: 1px solid var(--k-success);
    border-radius: var(--k-radius-md);
    color: var(--k-success);
    font-weight: 600;
}

/* web-22a — KORAK 1 PO OKVIRU „2b" (:596): QR lijevo, recenica desno, razmak 14 px. Stupac QR-a
   raste do kape koju vec nosi `.k-device-pairing__install-qr` (10rem — kapa prati korijenski font,
   ThemeTests; podloga crta 120 px), tekst dobiva ostatak i prelama se. */
/* #3666 (ARH-C 062835, REV-D 062727): adresa se NIKAD ne lomi usred rijeci (P58 v2), pa stupac teksta
   ne smije biti uzi od svog najsireg komada — min-content, ne 0. Mjera (k2b, dugi host): komad
   „abcdefgh12345678." (106,9 px) u stupcu od 103,7 px, scrollWidth 107 > clientWidth 104. Mjesto daje
   stupac QR-a: slika je `width: 100%; max-width: 10rem`, pa se skuplja sa stupcem (E2E tvrdi >= 120 px). */
.k-device-pairing__install-body {
    display: grid;
    grid-template-columns: minmax(0, 10rem) minmax(min-content, 1fr);
    gap: 14px;
    align-items: center;
}

.k-device-pairing__install-text {
    color: var(--k-text-label);
    font-size: 13px;
    line-height: 1.45;
}

.k-device-pairing__install-how { margin: 0; }

/* „Ako je Kerber vec instaliran, preskocite." — prigusen, u novom retku (podloga :596). */
.k-device-pairing__install-skip {
    margin: 2px 0 0;
    color: var(--k-text-muted);
}

/* web-22a — korak 2 (:597): jedna recenica desno od QR-a, iznad PIN-a. */
.k-device-pairing__pair-how {
    margin: 0;
    color: var(--k-text-label);
    font-size: 13px;
}

/* web-22a — vrijeme roka je istaknuto (podloga `.exp b`, :509: --warn). */
.k-device-pairing__expiry-at {
    color: var(--k-warning);
    font-weight: 700;
}

/* web-22a D14 — info okvir pod crtom roka (podloga k2b :601): ikona lijevo, prigusen tekst. */
.k-device-pairing__info {
    display: flex;
    gap: 10px;
    margin-top: 14px;
    padding: 10px 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-lg);
    background: var(--k-bg);
    color: var(--k-text-muted);
    font-size: 13px;
}

.k-device-pairing__info-icon {
    flex: none;
    width: 18px;
    height: 18px;
    color: var(--k-accent-soft);
}

.k-device-pairing__info-text { margin: 0; }

/* USKI ZASLON — ODLUKA #2180, okvir „2b" ga ne crta: ispod 800 px (sirina prozora je 760 px) koraci
   se slazu okomito, korak 1 iznad koraka 2, a unutar koraka 2 PIN ispod QR-a. Redoslijed ostaje
   1 → 2 jer ga daje redoslijed u DOM-u, ne mreza. */
@media (max-width: 800px) {
    .k-device-pairing__steps,
    .k-device-pairing__methods,
    .k-device-pairing__install-body { grid-template-columns: minmax(0, 1fr); }
}

.k-install__footprint {
    margin-top: .5rem;
    padding-top: 8px;           /* web-29 D4, M:106 */
    border-top: 1px solid var(--k-border);
    color: var(--k-text-label); /* web-29 D4, M:106 */
    font-size: 11px;            /* web-29 D4, M:106 */
    line-height: 1.4;           /* web-29 D4, M:106 */
}

.k-install__footprint p { margin: 0 0 .375rem; }

/* The fingerprint is 64 hex characters: it must WRAP rather than push the page sideways, and it is
   read character by character when somebody verifies it, so it stays monospaced. */
.k-install__footprint code {
    font-family: var(--k-font-mono, ui-monospace, monospace);
    overflow-wrap: anywhere;
    font-size: 10.5px;          /* web-29 D4, M:107 */
    color: var(--k-text);       /* web-29 D4, M:107 */
}

/* ── K2c (DIZ-5): the shared DevExpress dialog shell .k-dialog ─────────────────────────────────────────
   A DxPopup wears it through its public API: CssClass="k-dialog k-dialog--form" (or --confirm, + --danger),
   HeaderCssClass="k-dialog__head", BodyCssClass="k-dialog__body", FooterCssClass="k-dialog__foot"; the footer
   template holds .k-dialog__aside (left line) and .k-dialog__actions (secondary first, primary LAST).
   W-04 (docs/design/web-decisions.md:77) holds: buttons bottom right with the primary rightmost, frame
   --k-border-strong, 60 % backdrop (--k-scrim), CAPS cyan form title, red danger title. Deliberate deviation
   (ARH-C 043748 Q1): radius var(--k-radius) = 10px and form title 17px/700, as drawn by the owner-approved mock
   web-10 ("ODOBRENO 25.9."), not W-04's 8px and 15/600.
   The frame goes through DevExpress's own --dxbl-popup-* variables (declared on .dxbl-modal, read on the dialog or
   below it), so no DevExpress rule competes on our element. The backdrop reader .dxbl-modal > .dxbl-modal-back is
   NOT under the dialog (T0, DevExpress 25.2.9), so its variables sit on the .dxbl-modal whose root holds a shell
   dialog. Q3 (ARH-C 043748): DevExpress writes the body/footer padding shorthand and the header/footer lines at
   (0,5,0) (blazing-dark 25.2.9 rules #5485/#5512/#5514); the rules that change them REPEAT our area class to
   (0,6,0), never !important — precedent .k-calendar--weekbar (:1507 at ea638f85e, repeated class against DevExpress).
   --danger comes AFTER --form and --confirm: all three are (0,2,0) on one element and declare the header colour.
   The shell gives buttons no shape (G1-B): that is .k-btn's (K2b). Pins: KerberDijalogCssTests.
   K3-F N12d (#3291, ARH-C 093829): Fluent 25.2.9 (core.min.css md5 81c5423f) paints each area itself from its OWN
   --dxbl-popup-* variable, declared on the .dxbl-modal ancestor, where BlazingDark let the areas inherit the frame:
   the body's background (`…>.dxbl-modal-body { background-color: var(--dxbl-popup-body-bg) }`, 0,5,0) and the footer's
   text (`…>.dxbl-modal-footer { color: var(--dxbl-popup-footer-color) }`), so both are set here from the frame's own
   values. Fluent's frame and lines are `border: var(--dxbl-popup-border-width) var(--dxbl-popup-border-style) …` with
   width 0 and style none — the --k-border-strong edge and the header/footer lines (mock web-10:164 `.dlg`, :187 `.fh`,
   :191 `.ff`: 1px solid) were invisible — so width and style come back (BlazingDark's 1px solid). Fluent rounds the
   header and footer from their own radius (0.5rem) inside our 10px frame; BlazingDark derived it from the frame
   (`calc(var(--dxbl-popup-border-radius) - var(--dxbl-popup-border-width))`), and so does this rule. Fluent pads the
   title 2px top and bottom (`.dxbl-modal-title { padding: var(--dxbl-popup-header-content-padding-y) … }`); the mock
   has none (:188 `.fh h4 { margin: 0 }`). Full reader list with verdicts: K3-F N12d list (PR body). Pinned by
   FluentDxblVarsReadTests.N12d_* .
   ARH-C 094712 (N12e, in the same commit): the header keeps BlazingDark's line-height 1.25 (header height ≈49px as
   before; Fluent 1.75rem gave ≈60px), the body takes the mock's 1.45 (web-10:10 `body`, the sheet's own body
   line-height); the close button's hover colour N12e set here (white at 70 %) is WITHDRAWN by N12f below (self-report
   DIZ-1, TEST-WEB v12b: BlazingDark hovered in the title's colour on a transparent fill); its focus ring is the house
   ring (G2): --k-accent, 2px (the width inside --k-focus-ring, as the danger-outline block below).
   K3-F N12f (ARH-C 112757, TEST-WEB v12b against BlazingDark main 1cfa64077): (A) the TITLE carries the header row, as
   under BlazingDark, where `span.dxbl-modal-title` measured 3.5px top and bottom padding plus a 1px transparent border
   (form row 59.23px, confirm 54.98px). Fluent pads the title only through --dxbl-popup-header-content-padding-y (its one
   reader, the title rule `.dxbl-modal-title { padding: var(-y) var(-x) }`; Fluent draws no title border), so the hook is
   BlazingDark's padding plus the border's 1px, calc(3.5px + 1px): a transparent border leaves no mark, the box is the
   same (form 59.25px, confirm 55.00px; the 28.25px close button no longer sets the row). (B) The close button hovers in
   the TITLE's colour on a transparent fill, as under BlazingDark (`--dxbl-popup-header-btn-hover-color: unset`, so the
   glyph inherited the header colour — red on a danger confirm): the hook reads --dxbl-popup-header-color, which --form,
   --confirm and --danger each set on this same element, so var() resolves to that dialog's title colour; the fill stays
   Fluent's transparent (not set here). (D) The footer text size: the two footer rules below. Pinned by
   FluentDxblVarsReadTests.N12d_* and N12f_* . */
.k-dialog.k-dialog--form,
.k-dialog.k-dialog--confirm {
    --dxbl-popup-bg: var(--k-surface);
    --dxbl-popup-color: var(--k-text);
    --dxbl-popup-border-color: var(--k-border-strong);
    --dxbl-popup-border-width: 1px;
    --dxbl-popup-border-style: solid;
    --dxbl-popup-border-radius: var(--k-radius);
    --dxbl-popup-header-border-radius: calc(var(--dxbl-popup-border-radius) - var(--dxbl-popup-border-width));
    --dxbl-popup-footer-border-radius: calc(var(--dxbl-popup-border-radius) - var(--dxbl-popup-border-width));
    --dxbl-popup-shadow: var(--k-shadow-dialog);
    --dxbl-popup-header-bg: var(--k-surface);     /* covers DevExpress's 10 % black header ::before */
    --dxbl-popup-header-content-padding-y: calc(3.5px + 1px);   /* N12f (A): BlazingDark title padding 3.5 + transparent border 1 */
    --dxbl-popup-header-line-height: 1.25;
    --dxbl-popup-body-bg: var(--k-surface);
    --dxbl-popup-body-line-height: 1.45;
    --dxbl-popup-footer-bg: var(--k-surface);     /* covers DevExpress's 7 % black footer ::before */
    --dxbl-popup-footer-color: var(--k-text);
    --dxbl-popup-header-btn-color: var(--k-text-muted);
    --dxbl-popup-header-btn-hover-color: var(--dxbl-popup-header-color);   /* N12f (B): the title's colour (N12e's white withdrawn) */
    --dxbl-popup-header-btn-outline-color: var(--k-accent);
    --dxbl-popup-header-btn-outline-width: 2px;
}

/* Issue 3440 (owner's decision 7.10.2026., 187 C "1"): EVERY DxPopup dialog is rounded 10px and titled 17px/700,
   as the owner-approved dialog mock (25.9.) draws it — not only the dialogs that wear the .k-dialog shell.
   Exceptions, by name: .k-dialog (the shell above sets its own values; --confirm is 16/700 by mock web-10),
   .k-media-viewer-popup (full screen), .k-omnibox-popup (search, not a dialog), and DevExpress's own popups under
   .dxbl-modal that are not dialogs: editor drop-downs, the grid column chooser, the pivot field list and the
   toolbar's modal menu (drop-down modal, dialog, bottom sheet).
   The variable is on the dialog element itself, so it wins by INHERITANCE (the nearer element) over the value
   DevExpress declares on .dxbl-modal / .dxbl-modal.dxbl-sm / .dxbl-modal.dxbl-lg — not by selector weight; a rule on
   the bare .dxbl-modal would also reach the drop-downs.
   RISK: --dxbl-popup-* are DevExpress internals (measured in the pinned 25.2.9, not public API). On every DevExpress
   upgrade repeat the class census over blazing-dark.bs5.min.css and the before/after measurement in a browser:
     tr '\175' '\n' < blazing-dark.bs5.min.css | grep -o -E '\.dxbl-popup\.dxbl-[a-z0-9-]+' | sort | uniq -c | sort -rn
   (\175 is the closing brace, written in octal so that this comment holds no lone brace.)
   Pins: KerberDijalogSviCssTests; computed style: CompanySmokeTests (worker editor). */
.dxbl-modal > .dxbl-modal-root > .dxbl-popup:not(.k-dialog):not(.k-media-viewer-popup):not(.k-omnibox-popup):not(.dxbl-edit-dropdown):not(.dxbl-grid-column-chooser-dialog):not(.dxbl-pivot-table-field-list):not(.dxbl-toolbar-dropdown-modal):not(.dxbl-toolbar-dialog):not(.dxbl-toolbar-bottom-sheet) {
    --dxbl-popup-border-radius: var(--k-radius);
    --dxbl-popup-header-font-size: 17px;
    --dxbl-popup-header-font-weight: 700;
}

/* K3-F N12a (#3291, ARH-C 080330): BlazingDark's --dxbl-popup-back-opacity is GONE, not renamed. Fluent 25.2.9
   (core.min.css md5 81c5423f) paints the backdrop as `.dxbl-modal>.dxbl-modal-back { background-color:
   var(--dxbl-popup-back-bg) }` with no opacity at all, so the scrim is drawn at full strength — the result
   BlazingDark's `opacity: 1` gave. Pinned by FluentDxblVarsReadTests.N12_namjerno_uklonjena_* . */
.dxbl-modal:has(> .dxbl-modal-root > .k-dialog.k-dialog--form),
.dxbl-modal:has(> .dxbl-modal-root > .k-dialog.k-dialog--confirm) {
    --dxbl-popup-back-bg: var(--k-scrim);         /* the scrim already carries W-04's 60 % */
}

/* --form (mock web-10:186-192): header 14/20, body 16 20 6, footer 12 20 16.
   K3-F N12a (#3291, ARH-C 080330): the vertical paddings and the body text size go through the names Fluent
   25.2.9 reads (core.min.css md5 81c5423f; every --dxbl-* name is DevExpress-INTERNAL, "may change between
   versions", docs.devexpress.com/Blazor/405705 — re-measure on an upgrade). BlazingDark read one -y per area
   (`padding: var(--dxbl-popup-header-padding-y) var(--dxbl-popup-header-padding-x)`); Fluent reads top and
   bottom apart (`padding: var(--dxbl-popup-header-padding-top) var(--dxbl-popup-header-padding-x)
   var(--dxbl-popup-header-padding-bottom)`, the same for -body- and -footer-), so each -y value is written
   twice, unchanged, and the two asymmetric bottoms below still win as properties (Q3). BlazingDark read
   --dxbl-popup-font-size on .dxbl-modal-content; Fluent reads --dxbl-popup-body-font-size on the body alone
   (it declares --dxbl-popup-footer-font-size but no rule reads it; the footer's size is a property on .k-dialog__foot,
   K3-F N12f below). Fluent declares all of these on the .dxbl-modal ANCESTOR (.dxbl-modal, and .dxbl-modal.dxbl-sm|lg
   for the body's), so ours, on the dialog below it, wins by inheritance at any specificity.
   Pinned by FluentDxblVarsReadTests.N12a_* (Fluent name, our value, this selector). */
.k-dialog.k-dialog--form {
    --dxbl-popup-header-padding-top: 14px;
    --dxbl-popup-header-padding-bottom: 14px;
    --dxbl-popup-header-padding-x: 20px;
    --dxbl-popup-header-font-size: 17px;
    --dxbl-popup-header-font-weight: 700;
    --dxbl-popup-header-color: var(--k-accent);
    --dxbl-popup-body-padding-top: 16px;
    --dxbl-popup-body-padding-bottom: 16px;
    --dxbl-popup-body-padding-x: 20px;
    --dxbl-popup-body-font-size: 14px;
    --dxbl-popup-body-color: var(--k-text-label);   /* K2 §2.6; K3-F N12c, note below */
    --dxbl-popup-footer-padding-top: 12px;
    --dxbl-popup-footer-padding-bottom: 12px;
    --dxbl-popup-footer-padding-x: 20px;
}

.k-dialog--form .k-dialog__head {
    text-transform: uppercase;
    letter-spacing: .5px;
}

/* Body text in the label colour (K2 §2.6, mocks web-20…26 and web-28 :380 `.dlg .fb`; NOT web-10, whose `.fb` has
   no colour — its summary values set their own, see .k-manual-dialog__value). K3-F N12c (#3291, ARH-C 085855): it is
   the variable --dxbl-popup-body-color on .k-dialog.k-dialog--form above, no longer a property here. BlazingDark's body
   rule set no colour, so `.k-dialog.k-dialog--form .k-dialog__body { color: var(--k-text-label) }` (0,3,0) won by
   inheritance; Fluent 25.2.9 (core.min.css md5 81c5423f) paints the body itself —
   `.dxbl-modal>.dxbl-modal-root>.dxbl-popup>.dxbl-modal-content>.dxbl-modal-body { color: var(--dxbl-popup-body-color) }`
   (0,5,0), on the SAME element (BodyCssClass) — so that rule was dead and is removed. Fluent declares the variable on
   the .dxbl-modal ancestor; ours on the dialog wins by inheritance. Pinned by FluentDxblVarsReadTests.N12c_* and
   KerberDijalogCssTests pin 13. */

.k-dialog.k-dialog--form .k-dialog__body.k-dialog__body.k-dialog__body.k-dialog__body { padding-bottom: 6px; }

/* K3-F N12f (ARH-C 112757 D): the footer text keeps BlazingDark's size — form 14px (the --dxbl-popup-font-size: 14px the
   form set for the whole content until N12a), confirm 12.25px (BlazingDark's default 0.875rem at our 14px rem; the confirm
   never set it). Fluent 25.2.9 sizes neither the footer nor .dxbl-modal-content (it declares --dxbl-popup-footer-font-size
   on .dxbl-modal and reads it nowhere), so the footer inherited body's 15px. The size is a property on OUR footer element
   (FooterCssClass) — no DevExpress rule sets it, so the repeated class serves padding-bottom only (Q3). */
.k-dialog.k-dialog--form .k-dialog__foot.k-dialog__foot.k-dialog__foot.k-dialog__foot { padding-bottom: 16px; font-size: 14px; }

/* --confirm (mock web-10:164-167): ONE box `padding: 18px 20px` — title 16px/700 in the text colour, 8px to the
   paragraph, paragraph 14px to the buttons, 18px below — split over DevExpress's three areas: header 18 20 8,
   body 0 20, footer 0 20 18. No caps, no lines. The two bottoms and the two lines repeat the area class (Q3).
   K3-F N12a: Fluent's -top/-bottom names, as --form above. */
.k-dialog.k-dialog--confirm {
    --dxbl-popup-header-padding-top: 18px;
    --dxbl-popup-header-padding-bottom: 18px;
    --dxbl-popup-header-padding-x: 20px;
    --dxbl-popup-body-padding-top: 0;
    --dxbl-popup-body-padding-bottom: 0;
    --dxbl-popup-body-padding-x: 20px;
    --dxbl-popup-footer-padding-top: 0;
    --dxbl-popup-footer-padding-bottom: 0;
    --dxbl-popup-footer-padding-x: 20px;
    --dxbl-popup-body-color: var(--k-text);       /* K3-F N12d: Fluent paints the body from it (form: --k-text-label) */
    --dxbl-popup-header-font-size: 16px;
    --dxbl-popup-header-font-weight: 700;
    --dxbl-popup-header-color: var(--k-text);
}

.k-dialog.k-dialog--confirm .k-dialog__head.k-dialog__head.k-dialog__head.k-dialog__head {
    border-bottom: 0;
    padding-bottom: 8px;
}

.k-dialog.k-dialog--confirm .k-dialog__foot.k-dialog__foot.k-dialog__foot.k-dialog__foot {
    border-top: 0;
    padding-bottom: 18px;
    font-size: 12.25px;   /* K3-F N12f (D): BlazingDark's default 0.875rem at the 14px rem (form footer note above) */
}

/* The confirm paragraph (mock web-10:164-167): label colour, 14px below; (0,3,1) over Bootstrap's reboot p (0,0,1). */
.k-dialog.k-dialog--confirm .k-dialog__body p {
    color: var(--k-text-label);
    margin: 0 0 14px;
}

/* --danger (W-04, web-00:180) with --form or --confirm: red title. The red outline button is #3097's. LAST of the three. */
.k-dialog.k-dialog--danger { --dxbl-popup-header-color: var(--k-danger); }

/* Footer row: the action group packed right and pushed right (margin-left: auto, so a lone group stays right —
   deliberate deviation from the mock's space-between, W-04); the left line muted and pushed left. ONE row (mock
   web-10:171-172): DevExpress's footer wraps (flex-wrap: wrap), so the group never shrinks or wraps and the left line
   grows from a zero basis and wraps its own text. */
.k-dialog .k-dialog__actions {
    display: flex;
    gap: 10px;
    justify-content: flex-end;
    margin-left: auto;
    flex: none;
    white-space: nowrap;
}

.k-dialog .k-dialog__aside {
    font-size: 12px;
    color: var(--k-text-muted);
    margin-right: auto;
    flex: 1 1 0;
    min-width: 0;
}

/* #4540 Z3a — „Karta za tvrtku …" (ClientMapDialog; mock 4540 v2 .k45opts / .k45opt / .k45kw / .k45note / .k45err)
   on the theme's tokens, inside the shared .k-dialog--form shell. The options are a native fieldset of radios; a
   disabled fieldset (nothing read yet, or a save in flight) dims them, as the mock's .k45locked does. */
.k-client-map-dialog__options {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin: 4px 0 14px;
    padding: 0;
    border: 0;
    min-width: 0;
}

.k-client-map-dialog__option {
    padding: 10px 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-lg);
}

.k-client-map-dialog__option:has(input:checked) {
    border-color: var(--k-accent);
    background: rgba(var(--k-accent-rgb), .08);
}

.k-client-map-dialog__options:disabled .k-client-map-dialog__option { opacity: .5; }

.k-client-map-dialog__label {
    display: flex;
    gap: 12px;
    align-items: center;
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    color: var(--k-text);
}

/* N2 krug 2 — the radio drawn as the mock's .k45rad (18px ring in --muted, the chosen one in the accent with an 8px
   dot): a native DISABLED radio is painted by Chromium in its own grey whatever accent-color says, the checked one
   barely different from the unchecked, so during „Spremanje…" the chosen option no longer showed. Drawn here, the
   locked fieldset only dims it (the .5 above), as the mock's .k45locked does. Focus keeps the theme's
   input:focus-visible ring. */
.k-client-map-dialog__label input[type="radio"] {
    appearance: none;
    flex: none;
    display: inline-grid;
    place-content: center;
    width: 18px;
    height: 18px;
    margin: 0;
    border: 2px solid var(--k-text-muted);
    border-radius: 50%;
    background: transparent;
}

.k-client-map-dialog__label input[type="radio"]:checked { border-color: var(--k-accent); }

.k-client-map-dialog__label input[type="radio"]:checked::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--k-accent);
}

.k-client-map-dialog__warn {
    display: flex;
    gap: 8px;
    align-items: flex-start;
    margin: 6px 0 0 30px;
    font-size: 13px;
    color: var(--k-text-label);
}

/* The rows' decorative icons (mock .k45kw svg / .k45err svg): the warning triangle and the error circle, drawn
   inline as ControlPointEditor's warnbox icon is; aria-hidden, the row's text says it all. */
.k-client-map-dialog__icon {
    width: 18px;
    height: 18px;
    flex: none;
    color: var(--k-danger);
}

.k-client-map-dialog__warn .k-client-map-dialog__icon {
    width: 16px;
    height: 16px;
    margin-top: 2px;
    color: var(--k-warning);
}

/* „Spremi" while saving (mock v2 .btn .k45spin): DevExpress's DxWaitIndicator before the text, laid out as the
   DevExpress docs' indicator-container (a flex row) with the mock's 8px between indicator and text. */
.k-client-map-dialog__save-content {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

/* N2 (mock v2 .k45spin, the arc in --on-primary): Fluent 25.2.9 strokes the spin indicator through
   --dxds-color-content-primary-default-rest, an accent shade in dark mode that would draw cyan on the cyan „Spremi",
   so on this indicator it is the button's own text colour. */
.k-client-map-dialog__spinner {
    flex: none;
    --dxds-color-content-primary-default-rest: var(--k-btn-text-on-accent);
}

/* #4540 A2 (mock v2 .k45spin 14px; REV-B 032215 measured 15.3px): DevExpress 25.2.9 draws the spin as a 16×32
   viewBox whose circle is cx 8, cy 8, r 7, stroke 2, inside a box of --dxbl-wait-indicator-size-m = 1.25rem —
   17.5px on our 14px root, so the circle came out 14 × 17.5/16 = 15.3px across its centre line, 17.5px outside.
   The mock's 14px is the OUTER edge (its `* { box-sizing: border-box; }`): a 14px box is 14/16 = 0.875px per unit,
   the circle 14px outside, 12.25px across its centre line, its stroke 1.75px (the mock's 2px; 0.25px accepted,
   coordinator's ruling for A2). Plain sizes on our own class (0,2,0 over DevExpress's .dxbl-wait-indicator), no
   DevExpress size parameter. */
.k-client-map-dialog__save-content .k-client-map-dialog__spinner {
    width: 14px;
    min-width: 14px;
    height: 14px;
}

/* N2 krug 2: `.k-btn svg` (16px × 16px) would squeeze DevExpress's 16×32 viewBox, so the circle shrank to 7px and sat
   4.75px above the pivot the spin rotates around. The image keeps its own geometry — the box's width, twice as tall,
   the top half shown (the spin's overflow: hidden) — so the circle's centre (8, 8), at 7px × 7px, is the box's
   centre, the pivot of the spin's transform-origin: center. Width and height are stated with the box above
   (14px → 14px × 28px). */
.k-client-map-dialog__save-content .k-client-map-dialog__spinner > svg {
    width: 14px;
    height: 28px;
}

.k-client-map-dialog__note {
    margin: 0 0 12px;
    font-size: 13px;
    color: var(--k-text-muted);
}

.k-client-map-dialog__error {
    display: flex;
    gap: 10px;
    margin: 0 0 12px;
    padding: 10px 12px;
    border: 1px solid var(--k-danger);
    border-radius: var(--k-radius-lg);
    background: rgba(var(--k-danger-rgb), .08);
    color: var(--k-text);
    font-size: 13px;
}

/* #1343 W-36 T6/T7 — the manual attendance dialogs (mock web-10 kadrovi 2, 3, 3b, 5). The shapes follow the mock's
   own classes (.kv summary, .quick buttons, .warn / .info / .err bands) on the theme's tokens. */
.k-manual-dialog { display: flex; flex-direction: column; gap: 12px; min-width: 320px; }

.k-manual-dialog-popup { max-width: 95vw; }

.k-manual-dialog__summary { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; margin: 0; }

.k-manual-dialog__caption { color: var(--k-text-muted); }

/* Mock web-10:194 `.kv dd { color: var(--text) }`: set here, because the K2c form body draws in --k-text-label. */
.k-manual-dialog__value { margin: 0; color: var(--k-text); }

.k-manual-dialog__muted { color: var(--k-text-muted); }

.k-manual-dialog__pill {
    padding: 0 6px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    font-size: 12px;
}

.k-manual-dialog__field { display: flex; flex-direction: column; gap: 4px; }

.k-manual-dialog__field[data-kerber-manual-invalid] .k-manual-dialog__input { outline: 1px solid var(--k-danger); }

.k-manual-dialog__label { font-size: 13px; color: var(--k-text-muted); }

.k-manual-dialog__row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

.k-manual-dialog__input { max-width: 220px; }

.k-manual-dialog__quick {
    height: 28px;
    padding: 0 10px;
    border: 1px solid var(--k-border-strong);
    border-radius: 14px;
    background: var(--k-surface);
    color: inherit;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
}

.k-manual-dialog__quick[disabled] { opacity: 0.6; cursor: default; }

.k-manual-dialog__warn,
.k-manual-dialog__info,
.k-manual-dialog__error {
    padding: 10px 12px;
    border: 1px solid var(--k-border-strong);
    border-radius: var(--k-radius-sm);
    font-size: 13px;
}

.k-manual-dialog__warn { border-color: var(--k-warning); }

.k-manual-dialog__info { color: var(--k-text-muted); }

.k-manual-dialog__error { border-color: var(--k-danger); }

.k-manual-dialog__footer { display: flex; gap: 12px; align-items: center; justify-content: space-between; width: 100%; }

.k-manual-dialog__who { color: var(--k-text-muted); font-size: 13px; }

.k-manual-dialog__actions { display: flex; gap: 8px; }

.k-manual-dialog__cancel,
.k-manual-dialog__submit {
    padding: 6px 14px;
    border: 1px solid var(--k-border-strong);
    border-radius: 4px;
    background: var(--k-surface);
    color: inherit;
    font: inherit;
    cursor: pointer;
}

.k-manual-dialog__submit {
    border-color: var(--k-accent);
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
}

.k-manual-dialog__cancel[disabled],
.k-manual-dialog__submit[disabled] { opacity: 0.6; cursor: default; }

/* ── #1343 W-36 T5 (P4-b) — the check-in tabs' manual marks, actions and chips ──────────────────────
   Mock web-10 (md5 4b59ac96) M:237 (chips, tool), M:320-326 and M:400-402 (cells). Shared by both tabs'
   ManualMarkCell / AttendanceRowActions, because the two tabs draw ONE working day from two sides.
   NO pointer-events ANYWHERE here (#2605, the settle-gate rule above and GridSettleGateTests P-4 (2)): while the
   grid's settle gate is closed a row's action is deliberately not clickable, and nothing under .k-grid may switch
   it back on. */
.k-attendance-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
.k-attendance-chips { display: inline-flex; flex-wrap: wrap; gap: 6px; }
.k-attendance-chip {
    border: 1px solid var(--k-border);
    border-radius: 999px;
    background: transparent;
    color: var(--k-text);
    padding: 2px 10px;
    font: inherit;
    /* K3c rez B: web-10-rucna-odjava.html:52 .chips span */
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    cursor: pointer;
}
.k-attendance-chip[aria-pressed="true"] {
    border-color: var(--k-accent);
    background: rgba(var(--k-accent-rgb), 0.1);
}
.k-attendance-chip:focus-visible,
.k-attendance-tool:focus-visible,
.k-attendance__action:focus-visible {
    outline: var(--k-focus-ring);
    outline-offset: var(--k-focus-ring-offset);
}
.k-attendance-tool {
    margin-left: auto;
    border: 1px solid var(--k-accent);
    border-radius: var(--k-radius-sm);
    background: var(--k-accent);
    color: var(--k-btn-text-on-accent);
    padding: 4px 12px;
    font: inherit;
    cursor: pointer;
}
.k-attendance-tool__plus { margin-right: 8px; }
.k-attendance-notice { margin: 0; color: var(--k-warning); }
.k-attendance__moment { color: var(--k-text); }
/* pecat P4 DOPUNA 6.2 N2 (i): the default colour of both check-in tabs' new spans (location: #2674) stands IN FRONT of
   .k-attendance__muted — same specificity, so the later rule wins and a muted duration/tracking stays muted. */
.k-worker-checkins__position,
.k-worker-checkins__tracking,
.k-worker-checkins__duration,
.k-location-checkins__position,
.k-location-checkins__tracking,
.k-location-checkins__duration { color: var(--k-text); }
.k-attendance__muted { color: var(--k-text-muted); }
.k-attendance__audit {
    display: block;
    color: var(--k-text-muted);
    font-size: 12px;
    white-space: normal;
    overflow-wrap: anywhere;
}
.k-attendance__action {
    border: 0;
    background: transparent;
    padding: 0;
    margin-left: 10px;
    color: var(--k-accent-soft);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
.k-attendance-pill {
    display: inline-block;
    margin-left: 4px;
    padding: 2px 7px;
    border: 1px solid;
    border-radius: var(--k-radius-sm);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .5px;
    text-transform: uppercase;
}
.k-attendance-pill--manual { border-color: var(--k-warning); color: var(--k-warning); }
.k-attendance-pill--voided { border-color: var(--k-text-muted); color: var(--k-text-muted); }
.k-attendance-pill--alarm { border-color: var(--k-danger); color: var(--k-danger); background: color-mix(in srgb, var(--k-danger) 12%, transparent); }
.k-attendance-pill--live { margin-left: 0; padding: 0; border: 0; color: var(--k-success); font-size: 12px; font-weight: 600; }
.k-attendance-pill--live i {
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 6px;
    border-radius: 50%;
    background: var(--k-success);
    vertical-align: middle;
    animation: k-attendance-blink 1.4s ease-in-out infinite;
}
/* DIZ-1 web-10 10-A1 (A-10, mock web-10:59-60 `blink 1.4s`, REV-D 224924 U2): the live dot pulses slowly — one fade per
   1.4 s, far under three flashes a second — and stops for anyone who asked for reduced motion; the green word still
   carries the meaning when it stops. */
@keyframes k-attendance-blink { 50% { opacity: .3; } }
@media (prefers-reduced-motion: reduce) {
    .k-attendance-pill--live i { animation: none; }
}
/* RAZRED 8 (plan T5 „Prikaz", R8): a voided row is MUTED on its cells (a colour is not a strike), and ONLY the
   wrapper of its original values is struck. A strike on a td would reach every inline descendant — the pills and
   the audit lines too — and `text-decoration: none` on a descendant cannot undo it; opacity is forbidden on the
   row for the same reason. More specific than one class (DevExpress's own row rules are). */
.k-attendance-voided > td { color: var(--k-text-muted); }
.k-attendance-voided > td .k-voided-values { text-decoration: line-through; }
/* pecat P4 DOPUNA 6.2 N2 (ii): the tabs' new spans carry an explicit default colour (above), which would beat the
   colour a voided row's cells inherit — so a voided row mutes them by name. */
.k-attendance-voided > td .k-worker-checkins__position,
.k-attendance-voided > td .k-worker-checkins__tracking,
.k-attendance-voided > td .k-worker-checkins__duration,
.k-attendance-voided > td .k-location-checkins__position,
.k-attendance-voided > td .k-location-checkins__tracking,
.k-attendance-voided > td .k-location-checkins__duration { color: var(--k-text-muted); }

/* K4 zaglavlja (web-00 §E, DIZ-8) — page headers: the breadcrumb path (KerberCrumbs), the page head and the
   connection strip, and the entity header (K4b). Values copied from the mock through theme tokens; no raw colour, no K2 primitive
   (.k-pill, .k-status, .k-kv, .k-btn) is defined here — they are reused as they are. One definition per
   selector in the whole sheet (K4ZaglavljaCssTests). The section ends at its own closing comment below the
   last K4 rule; K4ZaglavljaCssTests reads the section up to that comment, so rules a later package appends
   after it are not counted as K4.
   Breadcrumbs take the 47-screen form of web-05:40-41 (12px, uppercase, .5px, links in the muted colour),
   not web-00:100's (13px, no capitals, a --primary link) — ruling ARH-C R1. Contrast of --k-text-muted:
   6,43 on --k-bg and 5,96 on --k-surface (REV-D2).
   The mock's letter-spacing .5px is written through the token --k-label-tracking (0.5px in :root), as
   .k-grid__title already does — one spelling for the label tracking across the shell. */
.k-crumbs { font-size: 12px; color: var(--k-text-muted); text-transform: uppercase; letter-spacing: var(--k-label-tracking); margin-bottom: 6px; }
/* Raspored liste (reset), nije iz mocka: the mock's path is a bare line of text, ours is an <ol>. */
.k-crumbs__list { display: flex; flex-wrap: wrap; list-style: none; margin: 0; padding: 0; }
/* Raspored (reset), nije iz mocka: a step's <li> adds no box of its own. Stated so every class the markup
   carries has a rule (WebStyleAuditTests). */
.k-crumbs__item { margin: 0; }
.k-crumbs__link { color: var(--k-text-muted); text-decoration: none; }
/* Nije iz mocka kao pravilo: the mock leaves unlinked text bare inside .crumbs, so it inherits the path's
   colour; ours sits in a span and inherits it explicitly (WebStyleAuditTests wants a rule per class). */
.k-crumbs__text { color: inherit; }
.k-crumbs__current { color: inherit; }
.k-crumbs__sep { margin: 0 6px; }
/* Page head (KerberPageHead) — web-00:98-99 `.pagehead` / `.pagehead h1`, with the subtitle and tools column
   of the screen mocks (`.pagehead .sub`, `.pagehead .tools`). --k-accent stands for the mock's --primary,
   --k-text-muted for its --muted. Only for pages WITHOUT a grid: there KerberGridBar carries the <h1>. */
.k-page-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 14px; }
/* web-04:44 `.pagehead` `align-items: flex-start` — the one named exception (the wizard, DIZ-5). Same
   specificity as .k-page-head, so it must stay AFTER it. */
.k-page-head--start { align-items: flex-start; }
/* Raspored, nije iz mocka: the mock's title column is a bare <div>; ours is a class, and every class the
   markup carries has a rule (WebStyleAuditTests). min-width: 0 lets the flex item shrink below its
   content so a long title wraps instead of pushing the tools out of the row. */
.k-page-head__main { min-width: 0; }
.k-page-head__title { margin: 0; font-size: 20px; font-weight: 600; text-transform: uppercase; letter-spacing: var(--k-label-tracking); color: var(--k-accent); }
.k-page-head__sub { font-size: 13px; color: var(--k-text-muted); margin-top: 2px; }
.k-page-head__tools { display: flex; gap: 10px; align-items: center; }
/* Connection strip (KerberConnectionStrip) — web-00:92-94 `.strip` / `.strip i` / `.strip.warn`; delta plan
   DOPUNA 1 K1. The mock's rgba(var(--danger-rgb), .14 / .35) and the warning's .14 / .4 are color-mix of the
   theme tokens; --k-text stands for its --text. The base IS the red (Lost) state: .k-conn-strip--lost has no
   rule of its own, kerber-shell.js (Task 4) only names the state with it. Contrast of --k-text: 12,41 over
   the red strip, 11,38 over the amber one (REV-D2 §6). Rendered on every signed-in page, `hidden` while
   connected — see the component's header for why. */
.k-conn-strip { display: flex; align-items: center; gap: 10px; padding: 6px 28px; font-size: 13px; color: var(--k-text); background: color-mix(in srgb, var(--k-danger) 14%, transparent); border-bottom: 1px solid color-mix(in srgb, var(--k-danger) 35%, transparent); }
/* The author `display: flex` above would otherwise override the user-agent [hidden] { display: none }, and a
   "hidden" strip would still paint a red band over every connected page (REV-D 083123 K1).
   Under Themes.BlazingDark this rule is redundant: DevExpress.Blazor.Themes 25.2.9 blazing-dark.bs4/bs5.min.css
   carry `[hidden]{display:none!important}` (bootstrap reboot), which is why mutant M11 survived E2E (run
   37299954808). It becomes load-bearing under Fluent without the bootstrap variant
   (DevExpress.Blazor.Themes.Fluent 25.2.9: of 17 stylesheets only bootstrap/fluent-*.bs5.min.css carry
   [hidden]) — keep it when the theme moves (K3). */
.k-conn-strip[hidden] { display: none; }
/* flex: none — nije iz mocka (web-00:93 `.strip i` has no flex): the dot does not shrink when the text
   wraps to a new line (an empty flex item would otherwise be squeezed narrower than 8px). */
.k-conn-strip__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--k-danger); flex: none; }
/* Nije iz mocka kao pravilo: the mock's text is a bare text node inside .strip; ours sits in a span the
   script repaints, and inherits the strip's colour explicitly (WebStyleAuditTests wants a rule per class). */
.k-conn-strip__label { color: inherit; }
/* Same specificity as .k-conn-strip, so it must stay AFTER it. */
.k-conn-strip--warn { background: color-mix(in srgb, var(--k-warning) 14%, transparent); border-bottom-color: color-mix(in srgb, var(--k-warning) 40%, transparent); }
.k-conn-strip--warn .k-conn-strip__dot { background: var(--k-warning); }
/* Entity header (KerberEntityHeader, KerberFact; K4b) — web-05:123-126 / web-06:122 `.lhead`, web-05:150-152 `.live`.
   --k-accent stands for the mock's --primary, --k-text-muted for --muted, --k-text-label for --label, --k-success for
   --success. The facts' status dot is K2a `.k-status` and the link is K2b `.k-btn .k-btn--outline`, carried in the
   markup only — no selector here mentions a K2 class (K4ZaglavljaCssTests, M16). Contrast of --k-success (12px/600,
   „Živo"): 9,33 on --k-bg and 8,65 on --k-surface (kontrast, kontrola #FFF/#000 = 21,00). */
.k-entity-header { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 10px; }
/* Raspored, nije iz mocka: the mock's title column is a bare <div>; min-width: 0 lets a long name wrap instead of
   pushing the tools out of the row (as .k-page-head__main). */
.k-entity-header__main { min-width: 0; }
.k-entity-header__title { margin: 0; font-size: 22px; font-weight: 600; text-transform: uppercase; letter-spacing: var(--k-label-tracking); color: var(--k-accent); }
/* web-06:122 — the h1 with a leading avatar is a flex row (gap 12). Same specificity as __title: keep AFTER it. */
.k-entity-header__title--leading { display: flex; align-items: center; gap: 12px; }
.k-entity-header__facts { display: flex; gap: 18px; color: var(--k-text-muted); font-size: 13px; margin-top: 4px; flex-wrap: wrap; }
.k-entity-header__facts b { color: var(--k-text-label); font-weight: 600; }
/* web-08:108 `.facts b { color: var(--text) }` — the one named exception (#3021); same specificity (0,1,1) as the
   rule above, so it stays AFTER it. 0 consumers until web-08 adopts the header (ARH-C Q-D). */
.k-entity-header__facts--text b { color: var(--k-text); }
/* Nije iz `.lhead` (the mock has no `.lhead .tools` rule — „Živo" and the button sit glued): the screen mocks'
   `.pagehead .tools` web-05:45 = `.dhead .tools` web-08:110 (ARH-C Q-A). */
.k-entity-header__tools { display: flex; gap: 10px; align-items: center; }
/* Nije iz mocka (the mock draws the button as a <span>): ours is an <a class="k-btn k-btn--outline">, and the DX
   bootstrap reboot underlines links — bs5 `a` (0,0,1) at rest; bs4 `a:not(.btn)` (0,1,1) at rest and `a:hover`
   (0,1,1) under the pointer (DevExpress.Blazor.Themes 25.2.9, T0). (0,2,0) / (0,3,0) beat all three; the :hover item
   names the pointer state explicitly (REV-D N1). If a second consumer of <a class="k-btn"> appears, the underline
   moves into the K2 primitive (ARH-C Q-B). */
.k-entity-header .k-entity-header__link,
.k-entity-header .k-entity-header__link:hover { text-decoration: none; }
/* Druga kopija oznake „Živo" (08D `.k-wd__live`); objedinjavanje #3401. */
.k-entity-header__live { display: inline-flex; align-items: center; gap: 6px; color: var(--k-success); font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: var(--k-label-tracking); }
/* web-05:151; the keyframes are named k-live-blink, not the mock's `blink`, so a future global name cannot collide. */
.k-entity-header__live i { width: 8px; height: 8px; border-radius: 50%; background: var(--k-success); animation: k-live-blink 1.4s ease-in-out infinite; }
@keyframes k-live-blink { 50% { opacity: .3; } }
/* Nije mock — pravilo pristupačnosti (delta plan §3, Z4): no blinking under reduced motion; the dot stays green and
   „Živo" carries the meaning. */
@media (prefers-reduced-motion: reduce) { .k-entity-header__live i { animation: none; } }
/* /K4 zaglavlja — kraj odsječka */

/* ── W-04 — THE DANGEROUS BUTTON IS OUTLINED, NEVER FILLED ─────────────────────────────────────────
   Owner 5.9. (docs/design/web-decisions.md, W-04): a delete confirmation is a red title plus a red
   OUTLINED button, never a filled red one. This is the button half and only that — the title belongs to
   the dialog's own shell. One modifier on the button base: `<button class="k-btn k-btn--danger-outline">`
   or `<DxButton CssClass="k-btn k-btn--danger-outline">`. Pinned by DangerOutlineButtonCssTests.

   CONTRACT: a STANDALONE DxButton (default SizeMode) and a plain <button>. Inside DxToolbar,
   DxButtonGroup or a grid cell DevExpress sets the same variables from contextual (0,3,0)+ rules, and
   that use is NOT covered. Nor is SizeMode Small/Large: DevExpress then re-sets the ring's size and
   offset (`.dxbl-sm|lg`, (0,3,0)) and touches no colour, background or shadow (measured in 25.2.9) —
   ring geometry only, never a fill.

   THE SHAPE IS `.k-btn`'s (K2b, above; ARH-C 172045 (A)): the base carries every shape declaration of
   mock `.btn` (web-16/web-21 M:35), the 1px border, the focus ring and the disabled state, and
   KerberGumbCssTests pins them there. This modifier is colour only — background, border colour and
   text — and carries none of the shape, no ring and no disabled rule of its own. A disabled button under
   the mouse is its base (ARH-C 003457 (c)): the base rule also lists `:disabled:hover` and
   `[aria-disabled="true"]:hover`, (0,3,0) over the global `button:hover` (0,1,1), as K2b's colour
   modifiers do.

   The hover/active wash stays a WASH (≤ .15) — never `--k-danger` itself — and is written only for an
   enabled button (REV-D 002518 N1). `button:hover` above is (0,1,1), so the hover rule must be written
   or a plain button would hover to the accent fill. `:active` is written although K2b has none: W-04's
   wash covers the press too (named deviation from K2b). */
.k-btn--danger-outline,
.k-btn--danger-outline:disabled:hover,
.k-btn--danger-outline[aria-disabled="true"]:hover {
    background: transparent;
    border-color: var(--k-danger);
    color: var(--k-danger);
}
/* The wash stays a WASH (≤ .15), never --k-danger itself; enabled only, (0,4,0) over the global button:hover (0,1,1). */
.k-btn--danger-outline:hover:not(:disabled):not([aria-disabled="true"]),
.k-btn--danger-outline:active:not(:disabled):not([aria-disabled="true"]) {
    background: rgba(var(--k-danger-rgb), 0.1);
    border-color: var(--k-danger);
    color: var(--k-danger);
}
/* DxButton: DevExpress paints hover/active/focus and the disabled button under the mouse from rules such as
   `.dxbl-btn:hover`, `.dxbl-btn:not(.dxbl-disabled):not(:disabled):active` and `.dxbl-btn:focus-visible`
   (Fluent 25.2.9 core.min.css, md5 81c5423f), reading --dxbl-btn-* variables it defines ON THE BUTTON: from
   two-class variant rules (`.dxbl-btn.dxbl-btn-primary`, 0,2,0) and, for a disabled button, from THREE-class
   rules `.dxbl-btn.dxbl-disabled.dxbl-btn-<style>` (0,3,0), e.g. `.dxbl-btn.dxbl-disabled.dxbl-btn-primary
   { --dxbl-btn-bg: var(--dxbl-btn-disabled-bg) … }`. So the paint goes through those variables, from our own class
   written THREE times (0,3,0) BECAUSE of `.dxbl-btn.dxbl-disabled.dxbl-btn-<style>` (0,3,0): it ties those
   disabled rules and this sheet is linked after the DevExpress theme — the W4 focus block's recipe, and no
   DevExpress class name (docs.devexpress.com/Blazor/401740). Every variable those rules read is re-pointed
   here; pin 4 DERIVES that set from the served Fluent sheet and measures the tie (K3-F N12b: under
   BlazingDark two classes were enough).
   K3-F N12b (#3291, ARH-C 080330): nine BlazingDark channels are GONE, not renamed — no Fluent 25.2.9 button
   rule reads them (Fluent only declares some of them in contextual rules of its own): --dxbl-btn-box-shadow
   and --dxbl-btn-focus-box-shadow (no Fluent button rule paints a box-shadow), --dxbl-btn-hover-, -active-,
   -focus- and -disabled-background (no Fluent button state paints a background image), --dxbl-btn-focus-bg
   and --dxbl-btn-focus-border-color (Fluent's focus state is ONLY `.dxbl-btn:focus-visible { outline }`, so a
   focused button keeps the rest/hover colours set here), and --dxbl-btn-disabled-opacity (the disabled fade
   is .k-btn:disabled / .k-btn[aria-disabled="true"] { opacity: .4 }, K2b). The --dxbl-* names are
   DevExpress-INTERNAL (docs.devexpress.com/Blazor/405705: "may change between versions"); the hooks, their
   values and the removed names with their reasons are pinned in FluentDxblVarsReadTests.N12b_* / N12_*.
   THE RING is written as parts because DevExpress reads it as parts (`outline: <colour> solid <size>`):
   colour and offset are the tokens; the 2px is the width inside the `--k-focus-ring` shorthand, which has
   no width token of its own — change it here together with `--k-focus-ring`. */
.k-btn--danger-outline.k-btn--danger-outline.k-btn--danger-outline {
    --dxbl-btn-bg: transparent;
    --dxbl-btn-color: var(--k-danger);
    --dxbl-btn-border-color: var(--k-danger);
    --dxbl-btn-hover-bg: rgba(var(--k-danger-rgb), 0.1);
    --dxbl-btn-hover-color: var(--k-danger);
    --dxbl-btn-hover-border-color: var(--k-danger);
    --dxbl-btn-active-bg: rgba(var(--k-danger-rgb), 0.1);
    --dxbl-btn-active-color: var(--k-danger);
    --dxbl-btn-active-border-color: var(--k-danger);
    --dxbl-btn-focus-outline-color: var(--k-accent);
    --dxbl-btn-focus-outline-size: 2px;
    --dxbl-btn-focus-outline-offset: var(--k-focus-ring-offset);
    --dxbl-btn-disabled-bg: transparent;
    --dxbl-btn-disabled-color: var(--k-danger);
    --dxbl-btn-disabled-border-color: var(--k-danger);
}
/* web-22 22b (DIZ-7) — §11.4 devices grid, mock k1 (docs/design/mocks/web-22-uredjaji.html): the muted ID
   (`td.muted`), the phone icon before the name, the 11 px muted sub-line under the name and under the last
   login (`.ver`), and „Obriši" as red TEXT (`.rst.dan`) — no background, no border. */
.k-devices__id { color: var(--k-text-muted); }
.k-devices__phone {
    width: 15px;
    height: 15px;
    margin-right: 6px;
    vertical-align: -3px;
    color: var(--k-text-muted);
}
.k-devices__sub { display: block; font-size: 11px; color: var(--k-text-muted); }
.k-devices__delete {
    padding: 0;
    border: 0;
    background: none;
    color: var(--k-danger);
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .5px;
    text-transform: uppercase;
    white-space: nowrap;
    cursor: pointer;
}
.k-devices__delete:hover { text-decoration: underline; }
.k-devices__delete:focus-visible { outline: 2px solid var(--k-accent-soft); outline-offset: 2px; }
/* web-22 22d (DIZ-7) — C2 (mock k1 `.yn.on i`, M:245–246): the dot before „Aktivan" — green with the mock's
   glow, at the mock's 60 % alpha mixed from the success token so the colour has one source. Decorative
   (aria-hidden): the state is the word. Every listed phone that is not revoked is active, so there is no grey
   variant. */
.k-devices__dot {
    display: inline-block;
    width: 9px;
    height: 9px;
    margin-right: 6px;
    border-radius: 50%;
    background: var(--k-success);
    box-shadow: 0 0 6px color-mix(in srgb, var(--k-success) 60%, transparent);
    vertical-align: middle;
}
/* web-22 22d — C13 (mock k1 `tr.rev td`, M:513): a revoked phone's row is muted — KerberGrid's RowCssClass puts
   the class on the row. A COLOUR, never an opacity: the row has to stay readable (scen 188, E2E Y1). The cells'
   spans carry no colour of their own and inherit it; the pill „Opozvan" keeps its own (the shared primitive's
   `--rev`, as in the mock), so no selector here names the pill. */
.k-grid__dx tr.k-devices__row--revoked > td {
    color: var(--k-text-muted);
}
/* #4130 — the super admin's roles editor of one Kerber client (ClientRolesEditor; mock web-28b frames 2, 3 and 7,
   `.rolecat.ed`): one grid row per catalogue role — the switch or the lock, the name with its tags and its six
   read-only marks, the alias box and the bare use count; a reason line spans the row under it. The disabled switch
   of a role in use is NEUTRAL (muted, never the danger colour): it is a fact about the role, not an error. */
.k-client-roles {
    border: 1px solid var(--k-border-strong);
    border-radius: 8px;
    background: var(--k-bg);
}
.k-client-roles__row {
    display: grid;
    grid-template-columns: 28px minmax(0, 1fr) 280px 110px;
    align-items: center;
    gap: 6px 10px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--k-border);
    font-size: 14px;
}
.k-client-roles__row:last-child { border-bottom: 0; }
.k-client-roles__row--head {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .5px;
    text-transform: uppercase;
    color: var(--k-text-label);
}
.k-client-roles__head-hint {
    display: block;
    font-size: 11px;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    color: var(--k-text-muted);
}
.k-client-roles__row--off { color: var(--k-text-muted); }
.k-client-roles__row--new {
    background: rgba(var(--k-accent-rgb), .07);
    box-shadow: inset 3px 0 0 var(--k-accent-soft);
}
.k-client-roles__select {
    width: 18px;
    height: 18px;
    margin: 0;
    accent-color: var(--k-accent);
    cursor: pointer;
}
.k-client-roles__select:disabled {
    accent-color: var(--k-text-muted);
    cursor: not-allowed;
}
.k-client-roles__select:focus-visible { outline: 2px solid var(--k-accent-soft); outline-offset: 2px; }
.k-client-roles__lock {
    display: inline-flex;
    width: 18px;
    height: 18px;
    align-items: center;
    justify-content: center;
    color: var(--k-text-muted);
}
.k-client-roles__lock svg { width: 15px; height: 15px; }
.k-client-roles__tag {
    margin-left: 6px;
    padding: 1px 6px;
    border: 1px solid var(--k-border-strong);
    border-radius: 4px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .5px;
    text-transform: uppercase;
    color: var(--k-text-muted);
    vertical-align: 1px;
}
.k-client-roles__tag--adds { border-color: var(--k-warning); color: var(--k-warning); }
.k-client-roles__props { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.k-client-roles__prop {
    padding: 1px 5px;
    border: 1px solid var(--k-border-strong);
    border-radius: 3px;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .4px;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--k-text-muted);
}
.k-client-roles__prop--on { border-color: var(--k-accent); color: var(--k-accent-soft); }
.k-client-roles__alias-box { width: 100%; }
.k-client-roles__alias-box--changed { outline: 1px solid var(--k-warning); border-radius: 6px; }
.k-client-roles__none { color: var(--k-text-muted); }
.k-client-roles__uses { text-align: right; font-variant-numeric: tabular-nums; }
.k-client-roles__uses--zero { color: var(--k-text-muted); }
.k-client-roles__why {
    grid-column: 2 / -1;
    margin-top: -2px;
    font-size: 12px;
    color: var(--k-text-label);
}
.k-client-roles__why--adds { color: var(--k-warning); }
/* The three cells of a role row that had no rule of their own: the first cell centres its one mark (the switch or
   the lock), and the name and alias cells may shrink inside their grid tracks instead of pushing the row wider. */
.k-client-roles__mark {
    display: flex;
    align-items: center;
    justify-content: center;
}
.k-client-roles__name { min-width: 0; }
.k-client-roles__alias { min-width: 0; }
/* #4130 — a refused save beside its row (the editor's Errors) and the changed alias the refusal is about. */
.k-client-roles__why--err { color: var(--k-danger); }
.k-client-roles__alias-box--err { outline: 1px solid var(--k-danger); border-radius: 6px; }
/* #4130 — the page around the editor (AdminClientRolesBody; mock web-28b frames 2–7): the client's name and inactive
   tag under the title, the inactive note, the refusal line above the table, the footer (legend, outcome lines,
   buttons) and the not-found state. */
.k-client-roles-page { display: flex; flex-direction: column; gap: 12px; }
.k-client-roles-page__client { color: var(--k-text); font-weight: 600; }
.k-client-roles-page__inactive {
    margin-left: 8px;
    padding: 1px 6px;
    border: 1px solid var(--k-border-strong);
    border-radius: 4px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .5px;
    text-transform: uppercase;
    color: var(--k-text-muted);
}
.k-client-roles-page__note { margin: 0; font-size: 13px; color: var(--k-text-label); }
.k-client-roles-page__banner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
    padding: 10px 12px;
    border: 1px solid var(--k-danger);
    border-radius: 8px;
    background: rgba(var(--k-danger-rgb), .06);
    font-size: 13px;
}
.k-client-roles-page__banner-head { color: var(--k-danger); }
.k-client-roles-page__banner-line { color: var(--k-text); }
/* #4130 (mock web-28b frame 4): someone changed the roles while this page holds unsaved edits — a warning, not a refusal. */
.k-client-roles-page__banner--warn {
    border-color: var(--k-warning);
    background: rgba(var(--k-warning-rgb), .08);
}
.k-client-roles-page__banner--warn .k-client-roles-page__banner-head { color: var(--k-text); }
/* #4130 (mock web-28b `.live`, frames 2, 3, 4, 6): „Živo" in the page head while the page follows other saves. The
   mock's values, --success → --k-success; one more copy of the live mark beside `.k-task-detail__live` and the
   others, named: merging them is #3401. The dot blinks with `k-live-blink`, reused, not copied; under reduced motion
   it stops and the word still says „live". */
.k-client-roles-page__live {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--k-success);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
}
.k-client-roles-page__live i {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--k-success);
    animation: k-live-blink 1.4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .k-client-roles-page__live i { animation: none; }
}
.k-client-roles-page__footer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}
.k-client-roles-page__notes { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
.k-client-roles-page__legend { display: inline-flex; align-items: center; gap: 6px; color: var(--k-text-muted); }
.k-client-roles-page__legend svg { width: 14px; height: 14px; }
.k-client-roles-page__saved { color: var(--k-success); }
.k-client-roles-page__failed { color: var(--k-danger); }
.k-client-roles-page__dirty { color: var(--k-warning); }
.k-client-roles-page__adds { color: var(--k-warning); }
.k-client-roles-page__actions { display: flex; gap: 8px; align-items: center; }
.k-client-roles-page__notfound { margin: 0; color: var(--k-text-muted); }
.k-client-roles-page__link { margin-left: 6px; color: var(--k-accent-soft); }

/* #4065 (spec §4.3) — THE SUPER ADMIN'S „NOVI KERBER KLIJENT“ (NewClientDialog.razor), dialog 5 of mock web-28
   (M:751-783) as the owner approved it after 20.10. (with the sign-in PIN, without the working positions and
   the state switch): two sections — Tvrtka, and Prvi administrator with its note — the mock's pairs in two
   columns (OIB | Jezik, E-mail | Telefon, Ime | Prezime, Korisničko ime | Kod za uparivanje, PIN | Potvrda),
   and the hints under their rows. The dialog's width is the DxPopup's Width/MaxWidth parameters, not a rule
   here. The frame, title, head and foot lines and the footer's button row are the house shell's
   (.k-dialog.k-dialog--form, .k-dialog__actions) — nothing here restyles them. Tokens only, so the light
   theme paints it through its own token block. */
.k-new-client {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

/* M:755 / M:762 .sec — one section, its rows 14px apart (M:398 .dlg.form .fb .fld margin-bottom). */
.k-new-client__section {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

/* M:470 .sec h5 — the section heading, the worker form's heading on the same tokens. */
.k-new-client__heading {
    margin: 0;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--k-border-strong);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--k-label-tracking);
    color: var(--k-accent-soft);
}

/* M:762 — the note beside „Prvi administrator“, the mock's inline small. */
.k-new-client__heading-note {
    color: var(--k-text-muted);
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
}

.k-new-client__field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

/* The shared label's 6px between label and box: 2px here plus the field's 4px gap (the worker form's sum). */
.k-new-client__field > .k-field-label { margin-bottom: 2px; }

/* M:471 .fld .two — a pair shares one row; minmax(0, …) keeps a DX editor from pushing its track wider than
   half. */
.k-new-client__pair {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 10px;
}

/* A pair and the hint under it are one row of the form. */
.k-new-client__block {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* M:258 .fld .hint */
.k-new-client__hint {
    margin: 0;
    font-size: 12px;
    color: var(--k-text-muted);
}

/* M:764 — „generira se“ in the pairing-code box: a box like the editors beside it, read only, the mock's
   spaced bold value. */
.k-new-client__readonly {
    box-sizing: border-box;
    width: 100%;
    padding: 6px 10px;
    border: 1px solid var(--k-border-strong);
    border-radius: 4px;
    background: var(--k-bg);
    color: var(--k-text);
    font-family: inherit;
    font-size: var(--k-font-size);
    font-weight: 700;
    letter-spacing: 3px;
}

/* A refusal sits UNDER the box it belongs to. */
.k-new-client__field-error {
    margin: 0;
    font-size: 13px;
    color: var(--k-danger);
}

/* A refusal or failure of the whole create, above the footer. */
.k-new-client__outcome {
    margin: 0;
    color: var(--k-danger);
}

/* The code step's line above the pairing offer. */
.k-new-client__created {
    margin: 0;
    color: var(--k-text);
}

/* A phone-wide dialog folds every pair into one column. */
@media (max-width: 480px) {
    .k-new-client__pair { grid-template-columns: minmax(0, 1fr); }
}
